diff --git a/.github/update.log b/.github/update.log index 2fa837b5dd..4528d5636a 100644 --- a/.github/update.log +++ b/.github/update.log @@ -854,3 +854,4 @@ Update On Fri Dec 13 19:36:09 CET 2024 Update On Sat Dec 14 19:33:42 CET 2024 Update On Sun Dec 15 19:34:29 CET 2024 Update On Mon Dec 16 19:36:05 CET 2024 +Update On Tue Dec 17 19:39:30 CET 2024 diff --git a/clash-nyanpasu/.eslintignore b/clash-nyanpasu/.eslintignore deleted file mode 100644 index 3d3667c5bd..0000000000 --- a/clash-nyanpasu/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -frontend/nyanpasu/auto-imports.d.ts -frontend/nyanpasu/src/router.ts diff --git a/clash-nyanpasu/.eslintrc.cjs b/clash-nyanpasu/.eslintrc.cjs deleted file mode 100644 index 298d700767..0000000000 --- a/clash-nyanpasu/.eslintrc.cjs +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - root: true, - env: { - browser: true, - node: true, - }, - extends: [ - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended", - "prettier", - "plugin:prettier/recommended", - ], - ignorePatterns: ["index.html", "node_modules/", "dist/", "backend/**/target"], - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint", "react-compiler", "react-hooks"], - rules: { - "no-console": process.env.NODE_ENV === "production" ? "error" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", - "@typescript-eslint/no-unused-vars": "warn", - "@typescript-eslint/no-explicit-any": "warn", - "react/jsx-no-undef": "off", - "react/react-in-jsx-scope": "off", - "@typescript-eslint/no-namespace": "off", - "react-compiler/react-compiler": "warn", // blocked by https://github.com/facebook/react/issues/30782 - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", - "react/no-children-prop": "off", - }, - settings: { - react: { - version: "detect", - }, - "import/resolver": { - alias: { - map: [ - ["@", "./src"], - ["~", "./"], - ], - extensions: [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"], - }, - }, - }, -}; diff --git a/clash-nyanpasu/.github/ISSUE_TEMPLATE/bug_report.yaml b/clash-nyanpasu/.github/ISSUE_TEMPLATE/bug_report.yaml index a1971bd633..579d02fa08 100644 --- a/clash-nyanpasu/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/clash-nyanpasu/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -3,8 +3,8 @@ name: Bug 反馈 / Bug report description: 提交一个问题报告 / Create a bug report labels: - - "T: Bug" - - "S: Untriaged" + - 'T: Bug' + - 'S: Untriaged' body: - type: markdown attributes: diff --git a/clash-nyanpasu/.github/ISSUE_TEMPLATE/feature_request.yaml b/clash-nyanpasu/.github/ISSUE_TEMPLATE/feature_request.yaml index 3087611b54..110b091f3b 100644 --- a/clash-nyanpasu/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/clash-nyanpasu/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -3,8 +3,8 @@ name: 功能请求 / Feature request description: 提出一个功能建议 / Suggest an idea labels: - - "T: Feature" - - "S: Untriaged" + - 'T: Feature' + - 'S: Untriaged' body: - type: markdown attributes: diff --git a/clash-nyanpasu/.github/workflows/ci.yml b/clash-nyanpasu/.github/workflows/ci.yml index e51780b8a3..ddd70072a9 100644 --- a/clash-nyanpasu/.github/workflows/ci.yml +++ b/clash-nyanpasu/.github/workflows/ci.yml @@ -48,14 +48,14 @@ jobs: xvfb - uses: Swatinem/rust-cache@v2 with: - workspaces: "./backend/" - prefix-key: "rust-stable" - shared-key: "ci" + workspaces: './backend/' + prefix-key: 'rust-stable' + shared-key: 'ci' save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - uses: maxim-lobanov/setup-xcode@v1 if: startsWith(matrix.targets.os, 'macos-') with: - xcode-version: "15.0" + xcode-version: '15.0' - name: Install Node.js uses: actions/setup-node@v4 with: @@ -85,7 +85,7 @@ jobs: - name: Prepare fronend run: pnpm -r build # Build frontend env: - NODE_OPTIONS: "--max_old_space_size=4096" + NODE_OPTIONS: '--max_old_space_size=4096' - name: Prepare sidecar and resources run: pnpm check - name: Lint @@ -95,7 +95,7 @@ jobs: if: startsWith(matrix.targets.os, 'ubuntu-') == false run: pnpm run-p lint:clippy lint:rustfmt # Lint env: - NODE_OPTIONS: "--max_old_space_size=4096" + NODE_OPTIONS: '--max_old_space_size=4096' # 以后完善了新的测试套件后再添加 # test_unit: diff --git a/clash-nyanpasu/.github/workflows/daily.yml b/clash-nyanpasu/.github/workflows/daily.yml index 79dd234a8d..df7ceb117b 100644 --- a/clash-nyanpasu/.github/workflows/daily.yml +++ b/clash-nyanpasu/.github/workflows/daily.yml @@ -1,7 +1,7 @@ on: workflow_dispatch: schedule: - - cron: "15 22 * * *" # 每天 06:15 UTC+8 自动构建 + - cron: '15 22 * * *' # 每天 06:15 UTC+8 自动构建 name: Daily @@ -16,7 +16,7 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: "20" + node-version: '20' - uses: pnpm/action-setup@v4 name: Install pnpm @@ -35,9 +35,9 @@ jobs: - uses: oleksiyrudenko/gha-git-credentials@v2-latest if: steps.git-check.outputs.has-changes == 'true' with: - token: "${{ secrets.GITHUB_TOKEN }}" - name: "github-actions[bot]" - email: "41898282+github-actions[bot]@users.noreply.github.com" + token: '${{ secrets.GITHUB_TOKEN }}' + name: 'github-actions[bot]' + email: '41898282+github-actions[bot]@users.noreply.github.com' - name: Commit Manifest if: steps.git-check.outputs.has-changes == 'true' @@ -57,7 +57,7 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: "20" + node-version: '20' - uses: pnpm/action-setup@v4 name: Install pnpm @@ -76,9 +76,9 @@ jobs: - uses: oleksiyrudenko/gha-git-credentials@v2-latest if: steps.git-check.outputs.has-changes == 'true' with: - token: "${{ secrets.GITHUB_TOKEN }}" - name: "github-actions[bot]" - email: "41898282+github-actions[bot]@users.noreply.github.com" + token: '${{ secrets.GITHUB_TOKEN }}' + name: 'github-actions[bot]' + email: '41898282+github-actions[bot]@users.noreply.github.com' - name: Commit Manifest if: steps.git-check.outputs.has-changes == 'true' diff --git a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml index 2af56e05bc..91a526a4e1 100644 --- a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml +++ b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml @@ -1,24 +1,24 @@ -name: "[Single] Build Linux" +name: '[Single] Build Linux' on: workflow_dispatch: inputs: nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string arch: type: choice - description: "build arch target" + description: 'build arch target' required: true - default: "x86_64" + default: 'x86_64' options: - x86_64 - i686 @@ -29,21 +29,21 @@ on: workflow_call: inputs: nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string arch: type: string - description: "build arch target" + description: 'build arch target' required: true - default: "x86_64" + default: 'x86_64' jobs: build: @@ -86,10 +86,10 @@ jobs: sudo apt-get install -y libwebkit2gtk-4.1-dev libxdo-dev libappindicator3-dev librsvg2-dev patchelf openssl - uses: Swatinem/rust-cache@v2 with: - workspaces: "./backend/" - prefix-key: "rust-stable" + workspaces: './backend/' + prefix-key: 'rust-stable' key: ubuntu-latest - shared-key: "release" + shared-key: 'release' - name: Install Node latest uses: actions/setup-node@v4 @@ -142,8 +142,8 @@ jobs: NIGHTLY: ${{ inputs.nightly == true && 'true' || 'false' }} with: tagName: ${{ inputs.tag }} - releaseName: "Clash Nyanpasu Dev" - releaseBody: "More new features are now supported." + releaseName: 'Clash Nyanpasu Dev' + releaseBody: 'More new features are now supported.' releaseDraft: false prerelease: true tauriScript: pnpm tauri diff --git a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml index edf413f8e4..9d7e3e10b2 100644 --- a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml +++ b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml @@ -1,41 +1,41 @@ -name: "[Single] Build macOS" +name: '[Single] Build macOS' on: workflow_dispatch: inputs: aarch64: - description: "Build aarch64 pkg" + description: 'Build aarch64 pkg' required: true type: boolean default: false nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string workflow_call: inputs: aarch64: - description: "Build aarch64 pkg" + description: 'Build aarch64 pkg' required: true type: boolean default: false nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string @@ -54,10 +54,10 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - workspaces: "./backend/" - prefix-key: "rust-stable" + workspaces: './backend/' + prefix-key: 'rust-stable' key: ${{ inputs.aarch64 && 'macos-14' || 'macos-13' }} - shared-key: "release" + shared-key: 'release' - name: Install the missing rust target (aarch64 Only) if: ${{ inputs.aarch64 == 'macos-14' }} @@ -78,7 +78,7 @@ jobs: uses: maxim-lobanov/setup-xcode@v1 if: ${{ inputs.aarch64 == false }} with: - xcode-version: "15.0" + xcode-version: '15.0' - name: Pnpm install run: | @@ -110,11 +110,11 @@ jobs: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} NIGHTLY: ${{ inputs.nightly == true && 'true' || 'false' }} - NODE_OPTIONS: "--max_old_space_size=4096" + NODE_OPTIONS: '--max_old_space_size=4096' with: tagName: ${{ inputs.tag }} - releaseName: "Clash Nyanpasu Dev" - releaseBody: "More new features are now supported." + releaseName: 'Clash Nyanpasu Dev' + releaseBody: 'More new features are now supported.' releaseDraft: false prerelease: true tauriScript: pnpm tauri @@ -128,7 +128,7 @@ jobs: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} NIGHTLY: ${{ inputs.nightly == true && 'true' || 'false' }} - NODE_OPTIONS: "--max_old_space_size=4096" + NODE_OPTIONS: '--max_old_space_size=4096' run: | ${{ inputs.nightly == true && 'pnpm build:nightly --target aarch64-apple-darwin' || 'pnpm build --target aarch64-apple-darwin' }} pnpm upload:osx-aarch64 diff --git a/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml b/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml index bd8cd16c07..07141c6ad8 100644 --- a/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml +++ b/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml @@ -1,36 +1,36 @@ -name: "[Single] Build Windows NSIS" +name: '[Single] Build Windows NSIS' on: workflow_dispatch: inputs: portable: - description: "Build Portable pkg" + description: 'Build Portable pkg' required: true type: boolean default: false fixed-webview: - description: "Fixed WebView" + description: 'Fixed WebView' required: true type: boolean default: false nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string arch: type: choice - description: "build arch target" + description: 'build arch target' required: true - default: "x86_64" + default: 'x86_64' options: - x86_64 - i686 @@ -39,33 +39,33 @@ on: workflow_call: inputs: portable: - description: "Build Portable pkg" + description: 'Build Portable pkg' required: true type: boolean default: false fixed-webview: - description: "Fixed WebView" + description: 'Fixed WebView' required: true type: boolean default: false nightly: - description: "Nightly prepare" + description: 'Nightly prepare' required: true type: boolean default: false tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string arch: type: string - description: "build arch target" + description: 'build arch target' required: true - default: "x86_64" + default: 'x86_64' jobs: build: @@ -87,10 +87,10 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - workspaces: "./backend/" - prefix-key: "rust-stable" + workspaces: './backend/' + prefix-key: 'rust-stable' key: windows-latest - shared-key: "release" + shared-key: 'release' - name: Install Node latest uses: actions/setup-node@v4 diff --git a/clash-nyanpasu/.github/workflows/deps-create-updater.yaml b/clash-nyanpasu/.github/workflows/deps-create-updater.yaml index 758d121703..1a2c2ae58e 100644 --- a/clash-nyanpasu/.github/workflows/deps-create-updater.yaml +++ b/clash-nyanpasu/.github/workflows/deps-create-updater.yaml @@ -1,26 +1,26 @@ -name: "[Single] Create Updater" +name: '[Single] Create Updater' on: workflow_dispatch: inputs: nightly: - description: "Nightly" + description: 'Nightly' required: true type: boolean default: false release_body: - description: "Release Body" + description: 'Release Body' required: false type: string workflow_call: inputs: nightly: - description: "Nightly" + description: 'Nightly' required: true type: boolean default: false release_body: - description: "Release Body" + description: 'Release Body' required: false type: string diff --git a/clash-nyanpasu/.github/workflows/deps-delete-releases.yaml b/clash-nyanpasu/.github/workflows/deps-delete-releases.yaml index 0be76ba41c..8e77b627b2 100644 --- a/clash-nyanpasu/.github/workflows/deps-delete-releases.yaml +++ b/clash-nyanpasu/.github/workflows/deps-delete-releases.yaml @@ -1,17 +1,17 @@ -name: "[Single] Delete Current Releases" +name: '[Single] Delete Current Releases' on: workflow_dispatch: inputs: tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string workflow_call: inputs: tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string diff --git a/clash-nyanpasu/.github/workflows/deps-message-telegram.yaml b/clash-nyanpasu/.github/workflows/deps-message-telegram.yaml index 199f969dd6..36b60803fd 100644 --- a/clash-nyanpasu/.github/workflows/deps-message-telegram.yaml +++ b/clash-nyanpasu/.github/workflows/deps-message-telegram.yaml @@ -1,10 +1,10 @@ -name: "[Single] Send Message to Telegram" +name: '[Single] Send Message to Telegram' on: workflow_dispatch: inputs: nightly: - description: "Nightly" + description: 'Nightly' required: true type: boolean default: false @@ -12,7 +12,7 @@ on: workflow_call: inputs: nightly: - description: "Nightly" + description: 'Nightly' required: true type: boolean default: false @@ -49,6 +49,6 @@ jobs: TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }} TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID }} TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} - TELEGRAM_TO: "@keikolog" - TELEGRAM_TO_NIGHTLY: "@ClashNyanpasu" + TELEGRAM_TO: '@keikolog' + TELEGRAM_TO_NIGHTLY: '@ClashNyanpasu' WORKFLOW_RUN_ID: ${{ github.run_id }} diff --git a/clash-nyanpasu/.github/workflows/deps-update-tag.yaml b/clash-nyanpasu/.github/workflows/deps-update-tag.yaml index 609b3f6c79..c872904fa7 100644 --- a/clash-nyanpasu/.github/workflows/deps-update-tag.yaml +++ b/clash-nyanpasu/.github/workflows/deps-update-tag.yaml @@ -1,17 +1,17 @@ -name: "[Single] Update Tag" +name: '[Single] Update Tag' on: workflow_dispatch: inputs: tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string workflow_call: inputs: tag: - description: "Release Tag" + description: 'Release Tag' required: true type: string diff --git a/clash-nyanpasu/.github/workflows/macos-aarch64.yaml b/clash-nyanpasu/.github/workflows/macos-aarch64.yaml index 66fdca6940..f7fd97e830 100644 --- a/clash-nyanpasu/.github/workflows/macos-aarch64.yaml +++ b/clash-nyanpasu/.github/workflows/macos-aarch64.yaml @@ -20,13 +20,13 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - workspaces: "./backend/" - prefix-key: "rust-stable" - key: "macos-13" - shared-key: "release" + workspaces: './backend/' + prefix-key: 'rust-stable' + key: 'macos-13' + shared-key: 'release' - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: "15.0" + xcode-version: '15.0' - name: install the missing rust target run: | rustup target add aarch64-apple-darwin @@ -34,7 +34,7 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: "20" + node-version: '20' - uses: pnpm/action-setup@v4 name: Install pnpm diff --git a/clash-nyanpasu/.github/workflows/publish.yml b/clash-nyanpasu/.github/workflows/publish.yml index 206efa5e6c..fbf0940f44 100644 --- a/clash-nyanpasu/.github/workflows/publish.yml +++ b/clash-nyanpasu/.github/workflows/publish.yml @@ -5,9 +5,9 @@ on: inputs: versionType: type: choice - description: "" + description: '' required: true - default: "patch" + default: 'patch' options: - major - minor @@ -83,15 +83,15 @@ jobs: - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v5 with: - commit_message: "chore: bump version to v${{ steps.update-version.outputs.version }}" - commit_user_name: "github-actions[bot]" - commit_user_email: "41898282+github-actions[bot]@users.noreply.github.com" - tagging_message: "v${{ steps.update-version.outputs.version }}" + commit_message: 'chore: bump version to v${{ steps.update-version.outputs.version }}' + commit_user_name: 'github-actions[bot]' + commit_user_email: '41898282+github-actions[bot]@users.noreply.github.com' + tagging_message: 'v${{ steps.update-version.outputs.version }}' - name: Release uses: softprops/action-gh-release@v2 with: draft: true body: ${{steps.build-changelog.outputs.content}} name: Clash Nyanpasu v${{steps.update-version.outputs.version}} - tag_name: "v${{ steps.update-version.outputs.version }}" + tag_name: 'v${{ steps.update-version.outputs.version }}' # target_commitish: ${{ steps.tag.outputs.sha }} diff --git a/clash-nyanpasu/.github/workflows/stale.yml b/clash-nyanpasu/.github/workflows/stale.yml index e20c6c44a9..50f21ed833 100644 --- a/clash-nyanpasu/.github/workflows/stale.yml +++ b/clash-nyanpasu/.github/workflows/stale.yml @@ -1,7 +1,7 @@ -name: "Close stale issues and PRs" +name: 'Close stale issues and PRs' on: schedule: - - cron: "30 1 * * *" + - cron: '30 1 * * *' workflow_dispatch: permissions: @@ -15,9 +15,9 @@ jobs: steps: - uses: actions/stale@v9 with: - stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days." - close-issue-message: "This issue is closed because it has been stale for 5 days with no activity." + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + close-issue-message: 'This issue is closed because it has been stale for 5 days with no activity.' days-before-stale: 30 days-before-close: 5 - stale-issue-label: "S: Stale" - only-issue-labels: "S: Untriaged" + stale-issue-label: 'S: Stale' + only-issue-labels: 'S: Untriaged' diff --git a/clash-nyanpasu/.github/workflows/target-dev-build.yaml b/clash-nyanpasu/.github/workflows/target-dev-build.yaml index 332d5eeb18..6246bf9e71 100644 --- a/clash-nyanpasu/.github/workflows/target-dev-build.yaml +++ b/clash-nyanpasu/.github/workflows/target-dev-build.yaml @@ -1,9 +1,9 @@ -name: "[Entire] Build Developer Version" +name: '[Entire] Build Developer Version' on: workflow_dispatch: schedule: - - cron: "15 0 * * *" # 每天 08:15 UTC+8 自动构建 + - cron: '15 0 * * *' # 每天 08:15 UTC+8 自动构建 env: CARGO_INCREMENTAL: 0 @@ -15,7 +15,7 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.repository, 'libnyanpasu') }} uses: ./.github/workflows/deps-delete-releases.yaml with: - tag: "pre-release" + tag: 'pre-release' windows_amd64_build: name: Windows x86_64 Build @@ -25,8 +25,8 @@ jobs: portable: true nightly: true fixed-webview: false - arch: "x86_64" - tag: "pre-release" + arch: 'x86_64' + tag: 'pre-release' secrets: inherit windows_aarch64_build: @@ -37,8 +37,8 @@ jobs: portable: true nightly: true fixed-webview: false - arch: "aarch64" - tag: "pre-release" + arch: 'aarch64' + tag: 'pre-release' secrets: inherit windows_i686_build: @@ -49,8 +49,8 @@ jobs: portable: true nightly: true fixed-webview: false - arch: "i686" - tag: "pre-release" + arch: 'i686' + tag: 'pre-release' secrets: inherit windows_amd64_build_fixed_webview: @@ -60,9 +60,9 @@ jobs: with: portable: true nightly: true - arch: "x86_64" + arch: 'x86_64' fixed-webview: true - tag: "pre-release" + tag: 'pre-release' secrets: inherit windows_aarch64_build_fixed_webview: @@ -72,9 +72,9 @@ jobs: with: portable: true nightly: true - arch: "aarch64" + arch: 'aarch64' fixed-webview: true - tag: "pre-release" + tag: 'pre-release' secrets: inherit windows_i686_build_fixed_webview: @@ -84,9 +84,9 @@ jobs: with: portable: true nightly: true - arch: "i686" + arch: 'i686' fixed-webview: true - tag: "pre-release" + tag: 'pre-release' secrets: inherit linux_amd64_build: @@ -95,8 +95,8 @@ jobs: needs: [delete_current_releases] with: nightly: true - tag: "pre-release" - arch: "x86_64" + tag: 'pre-release' + arch: 'x86_64' secrets: inherit linux_i686_build: @@ -105,8 +105,8 @@ jobs: needs: [delete_current_releases] with: nightly: true - tag: "pre-release" - arch: "i686" + tag: 'pre-release' + arch: 'i686' secrets: inherit linux_aarch64_build: @@ -115,8 +115,8 @@ jobs: needs: [delete_current_releases] with: nightly: true - tag: "pre-release" - arch: "aarch64" + tag: 'pre-release' + arch: 'aarch64' secrets: inherit linux_armhf_build: @@ -125,8 +125,8 @@ jobs: needs: [delete_current_releases] with: nightly: true - tag: "pre-release" - arch: "armhf" + tag: 'pre-release' + arch: 'armhf' secrets: inherit linux_armel_build: @@ -135,8 +135,8 @@ jobs: needs: [delete_current_releases] with: nightly: true - tag: "pre-release" - arch: "armel" + tag: 'pre-release' + arch: 'armel' secrets: inherit macos_amd64_build: @@ -146,7 +146,7 @@ jobs: with: nightly: true aarch64: false - tag: "pre-release" + tag: 'pre-release' secrets: inherit macos_aarch64_build: @@ -156,7 +156,7 @@ jobs: with: nightly: true aarch64: true - tag: "pre-release" + tag: 'pre-release' secrets: inherit update_tag: @@ -179,7 +179,7 @@ jobs: ] uses: ./.github/workflows/deps-update-tag.yaml with: - tag: "pre-release" + tag: 'pre-release' updater: name: Create Updater diff --git a/clash-nyanpasu/.github/workflows/target-release-build.yaml b/clash-nyanpasu/.github/workflows/target-release-build.yaml index fe4784540b..2f92255575 100644 --- a/clash-nyanpasu/.github/workflows/target-release-build.yaml +++ b/clash-nyanpasu/.github/workflows/target-release-build.yaml @@ -1,4 +1,4 @@ -name: "[Entire] Build Release Version" +name: '[Entire] Build Release Version' on: release: diff --git a/clash-nyanpasu/.lintstagedrc.js b/clash-nyanpasu/.lintstagedrc.js index f3255ab7fd..46d1a5cdbf 100644 --- a/clash-nyanpasu/.lintstagedrc.js +++ b/clash-nyanpasu/.lintstagedrc.js @@ -1,33 +1,33 @@ export default { - "*.{js,cjs,.mjs,jsx}": ["prettier --write", "eslint --cache --fix"], - "scripts/**/*.{ts,tsx}": [ - "prettier --write", - "eslint --cache --fix", - () => "tsc -p scripts/tsconfig.json --noEmit", + '*.{js,cjs,.mjs,jsx}': ['prettier --write', 'eslint --cache --fix'], + 'scripts/**/*.{ts,tsx}': [ + 'prettier --write', + 'eslint --cache --fix', + () => 'tsc -p scripts/tsconfig.json --noEmit', ], - "frontend/interface/**/*.{ts,tsx}": [ - "prettier --write", - "eslint --cache --fix", - () => "tsc -p frontend/interface/tsconfig.json --noEmit", + 'frontend/interface/**/*.{ts,tsx}': [ + 'prettier --write', + 'eslint --cache --fix', + () => 'tsc -p frontend/interface/tsconfig.json --noEmit', ], - "frontend/ui/**/*.{ts,tsx}": [ - "prettier --write", - "eslint --cache --fix", - () => "tsc -p frontend/ui/tsconfig.json --noEmit", + 'frontend/ui/**/*.{ts,tsx}': [ + 'prettier --write', + 'eslint --cache --fix', + () => 'tsc -p frontend/ui/tsconfig.json --noEmit', ], - "frontend/nyanpasu/**/*.{ts,tsx}": [ - "prettier --write", - "eslint --cache --fix", - () => "tsc -p frontend/nyanpasu/tsconfig.json --noEmit", + 'frontend/nyanpasu/**/*.{ts,tsx}': [ + 'prettier --write', + 'eslint --cache --fix', + () => 'tsc -p frontend/nyanpasu/tsconfig.json --noEmit', ], - "backend/**/*.{rs,toml}": [ + 'backend/**/*.{rs,toml}': [ () => - "cargo clippy --manifest-path=./backend/Cargo.toml --all-targets --all-features", - () => "cargo fmt --manifest-path ./backend/Cargo.toml --all", + 'cargo clippy --manifest-path=./backend/Cargo.toml --all-targets --all-features', + () => 'cargo fmt --manifest-path ./backend/Cargo.toml --all', // () => 'cargo test --manifest-path=./backend/Cargo.toml', // () => "cargo fmt --manifest-path=./backend/Cargo.toml --all", ], - "*.{html,sass,scss,less}": ["prettier --write", "stylelint --fix"], - "package.json": ["prettier --write"], - "*.{md,json,jsonc,json5,yaml,yml,toml}": ["prettier --write"], -}; + '*.{html,sass,scss,less}': ['prettier --write', 'stylelint --fix'], + 'package.json': ['prettier --write'], + '*.{md,json,jsonc,json5,yaml,yml,toml}': ['prettier --write'], +} diff --git a/clash-nyanpasu/.prettierrc.cjs b/clash-nyanpasu/.prettierrc.cjs index 1ed653fcb8..9ca6f44ff6 100644 --- a/clash-nyanpasu/.prettierrc.cjs +++ b/clash-nyanpasu/.prettierrc.cjs @@ -1,31 +1,31 @@ /** @type {import("prettier").Config} */ module.exports = { - endOfLine: "lf", - semi: true, - singleQuote: false, + endOfLine: 'lf', + semi: false, + singleQuote: true, bracketSpacing: true, tabWidth: 2, - trailingComma: "all", + trailingComma: 'all', overrides: [ { - files: ["tsconfig.json", "jsconfig.json"], + files: ['tsconfig.json', 'jsconfig.json'], options: { - parser: "jsonc", + parser: 'jsonc', }, }, ], importOrder: [ - "^@nyanpasu/ui/(.*)$", - "^@nyanpasu/interface/(.*)$", - "^@/(.*)$", - "^@(.*)$", - "^[./]", + '^@nyanpasu/ui/(.*)$', + '^@nyanpasu/interface/(.*)$', + '^@/(.*)$', + '^@(.*)$', + '^[./]', ], - importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"], - importOrderTypeScriptVersion: "5.0.0", + importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'], + importOrderTypeScriptVersion: '5.0.0', plugins: [ - "@ianvs/prettier-plugin-sort-imports", - "prettier-plugin-tailwindcss", - "prettier-plugin-toml", + '@ianvs/prettier-plugin-sort-imports', + 'prettier-plugin-tailwindcss', + 'prettier-plugin-toml', ], -}; +} diff --git a/clash-nyanpasu/.stylelintrc.js b/clash-nyanpasu/.stylelintrc.js index 54d0a4c142..a27f785d90 100644 --- a/clash-nyanpasu/.stylelintrc.js +++ b/clash-nyanpasu/.stylelintrc.js @@ -1,74 +1,74 @@ -import PostCssScss from "postcss-scss"; +import PostCssScss from 'postcss-scss' export default { root: true, - defaultSeverity: "error", + defaultSeverity: 'error', plugins: [ - "stylelint-scss", - "stylelint-order", - "stylelint-declaration-block-no-ignored-properties", + 'stylelint-scss', + 'stylelint-order', + 'stylelint-declaration-block-no-ignored-properties', ], extends: [ - "stylelint-config-standard", - "stylelint-config-html/html", // the shareable html config for Stylelint. - "stylelint-config-recess-order", + 'stylelint-config-standard', + 'stylelint-config-html/html', // the shareable html config for Stylelint. + 'stylelint-config-recess-order', // 'stylelint-config-prettier' ], rules: { - "selector-pseudo-class-no-unknown": [ + 'selector-pseudo-class-no-unknown': [ true, - { ignorePseudoClasses: ["global"] }, + { ignorePseudoClasses: ['global'] }, ], - "font-family-name-quotes": null, - "font-family-no-missing-generic-family-keyword": null, - "max-nesting-depth": [ + 'font-family-name-quotes': null, + 'font-family-no-missing-generic-family-keyword': null, + 'max-nesting-depth': [ 10, { - ignore: ["blockless-at-rules", "pseudo-classes"], + ignore: ['blockless-at-rules', 'pseudo-classes'], }, ], - "declaration-block-no-duplicate-properties": true, - "no-duplicate-selectors": true, - "no-descending-specificity": null, - "selector-class-pattern": null, - "value-no-vendor-prefix": [true, { ignoreValues: ["box"] }], - "at-rule-no-unknown": [ + 'declaration-block-no-duplicate-properties': true, + 'no-duplicate-selectors': true, + 'no-descending-specificity': null, + 'selector-class-pattern': null, + 'value-no-vendor-prefix': [true, { ignoreValues: ['box'] }], + 'at-rule-no-unknown': [ true, { ignoreAtRules: [ - "tailwind", - "unocss", - "layer", - "apply", - "variants", - "responsive", - "screen", + 'tailwind', + 'unocss', + 'layer', + 'apply', + 'variants', + 'responsive', + 'screen', ], }, ], }, overrides: [ { - files: ["**/*.scss", "*.scss"], + files: ['**/*.scss', '*.scss'], customSyntax: PostCssScss, rules: { - "at-rule-no-unknown": null, - "import-notation": null, - "scss/at-rule-no-unknown": [ + 'at-rule-no-unknown': null, + 'import-notation': null, + 'scss/at-rule-no-unknown': [ true, { ignoreAtRules: [ - "tailwind", - "unocss", - "layer", - "apply", - "variants", - "responsive", - "screen", + 'tailwind', + 'unocss', + 'layer', + 'apply', + 'variants', + 'responsive', + 'screen', ], }, ], }, }, ], -}; +} diff --git a/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/audit.yml b/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/audit.yml index 59952e51f1..6ac151b9a9 100644 --- a/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/audit.yml +++ b/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/audit.yml @@ -2,19 +2,19 @@ name: Audit on: schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' push: branches: - main paths: - - "**/Cargo.lock" - - "**/Cargo.toml" + - '**/Cargo.lock' + - '**/Cargo.toml' pull_request: branches: - main paths: - - "**/Cargo.lock" - - "**/Cargo.toml" + - '**/Cargo.lock' + - '**/Cargo.toml' jobs: audit: diff --git a/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/release.yml b/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/release.yml index 33b788f319..ba3a45a50f 100644 --- a/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/release.yml +++ b/clash-nyanpasu/backend/tauri-plugin-deep-link/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Publish on: push: tags: - - "v*.*.*" + - 'v*.*.*' jobs: release: diff --git a/clash-nyanpasu/backend/tauri/src/enhance/builtin/config_fixer.js b/clash-nyanpasu/backend/tauri/src/enhance/builtin/config_fixer.js index b62760c167..def42be9df 100644 --- a/clash-nyanpasu/backend/tauri/src/enhance/builtin/config_fixer.js +++ b/clash-nyanpasu/backend/tauri/src/enhance/builtin/config_fixer.js @@ -1,6 +1,6 @@ export default function main(params) { - if (typeof params["log-level"] === "boolean") { - params["log-level"] = "debug"; + if (typeof params['log-level'] === 'boolean') { + params['log-level'] = 'debug' } - return params; + return params } diff --git a/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_guard.js b/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_guard.js index 8e65ad1d82..6b2f6fee32 100644 --- a/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_guard.js +++ b/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_guard.js @@ -1,6 +1,6 @@ export default function main(params) { - if (params.mode === "script") { - params.mode = "rule"; + if (params.mode === 'script') { + params.mode = 'rule' } - return params; + return params } diff --git a/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_hy_alpn.js b/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_hy_alpn.js index 976ae56ae0..7174ee1f98 100644 --- a/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_hy_alpn.js +++ b/clash-nyanpasu/backend/tauri/src/enhance/builtin/meta_hy_alpn.js @@ -1,10 +1,10 @@ export default function main(params) { if (Array.isArray(params.proxies)) { params.proxies.forEach((p, i) => { - if (p.type === "hysteria" && typeof p.alpn === "string") { - params.proxies[i].alpn = [p.alpn]; + if (p.type === 'hysteria' && typeof p.alpn === 'string') { + params.proxies[i].alpn = [p.alpn] } - }); + }) } - return params; + return params } diff --git a/clash-nyanpasu/commitlint.config.js b/clash-nyanpasu/commitlint.config.js index fa584fb6d9..7c4ff4d984 100644 --- a/clash-nyanpasu/commitlint.config.js +++ b/clash-nyanpasu/commitlint.config.js @@ -1 +1 @@ -export default { extends: ["@commitlint/config-conventional"] }; +export default { extends: ['@commitlint/config-conventional'] } diff --git a/clash-nyanpasu/eslint.config.js b/clash-nyanpasu/eslint.config.js new file mode 100644 index 0000000000..784c33456a --- /dev/null +++ b/clash-nyanpasu/eslint.config.js @@ -0,0 +1,110 @@ +// @ts-check +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import eslintConfigPrettier from 'eslint-config-prettier' +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import react from 'eslint-plugin-react' +import pluginReactCompiler from 'eslint-plugin-react-compiler' +import pluginReactHooks from 'eslint-plugin-react-hooks' +import globals from 'globals' +import neostandard from 'neostandard' +import tseslint from 'typescript-eslint' +import { includeIgnoreFile } from '@eslint/compat' +import { FlatCompat } from '@eslint/eslintrc' + +// import ImportX from "eslint-plugin-import-x"; + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const compat = new FlatCompat({ + // import.meta.dirname is available after Node.js v20.11.0 + baseDirectory: __dirname, +}) +const gitignorePath = path.resolve(__dirname, '.gitignore') + +const ignores = [ + path.resolve(__dirname, 'index.html'), + '**/node_modules/', + 'node_modules/', + '**/dist/', + 'dist/', + 'backend/', + 'backend/**/target', +] + +export default tseslint.config( + includeIgnoreFile(gitignorePath), + { + ignores, + }, + { + files: ['**/*.{jsx,mjsx,tsx,mtsx}'], + extends: [ + // @ts-expect-error fucking plugin why export flat config with nullable types? + react.configs.flat.recommended, + ], + plugins: { + // @ts-expect-error react hooks not compatible with eslint types + 'react-hooks': pluginReactHooks, + 'react-compiler': pluginReactCompiler, + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: { + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'react-compiler/react-compiler': 'warn', + }, + }, + { + files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'], + extends: [ + ...neostandard({ ts: true, semi: true, noStyle: true }), + eslintConfigPrettier, + eslintPluginPrettierRecommended, + ], + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + 'react/react-in-jsx-scope': 'off', + 'prettier/prettier': [ + 'error', + { + singleQuote: true, + }, + ], + }, + }, + { + files: ['**/*.{ts,tsx,mtsx}'], + extends: [...tseslint.configs.recommended], + ignores, + rules: { + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + }, + languageOptions: { + parserOptions: { + project: true, + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + files: ['**/*.{jsx,mjsx,tsx,mtsx}'], + languageOptions: { + ...react.configs.flat?.recommended.languageOptions, + globals: { + ...globals.serviceworker, + ...globals.browser, + }, + }, + }, +) diff --git a/clash-nyanpasu/frontend/interface/src/index.ts b/clash-nyanpasu/frontend/interface/src/index.ts index 90833041b4..f412e701ae 100644 --- a/clash-nyanpasu/frontend/interface/src/index.ts +++ b/clash-nyanpasu/frontend/interface/src/index.ts @@ -1,3 +1,3 @@ -export * from "./ipc"; -export * from "./service"; -export * from "./openapi"; +export * from './ipc' +export * from './service' +export * from './openapi' diff --git a/clash-nyanpasu/frontend/interface/src/ipc/index.ts b/clash-nyanpasu/frontend/interface/src/ipc/index.ts index fdd1b0b6b8..60f379e20a 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/index.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/index.ts @@ -1,4 +1,4 @@ -export * from "./useNyanpasu"; -export * from "./useClash"; -export * from "./useClashCore"; -export * from "./useClashWS"; +export * from './useNyanpasu' +export * from './useClash' +export * from './useClashCore' +export * from './useClashWS' diff --git a/clash-nyanpasu/frontend/interface/src/ipc/useClash.ts b/clash-nyanpasu/frontend/interface/src/ipc/useClash.ts index 959f36d067..d99606643d 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/useClash.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/useClash.ts @@ -1,101 +1,101 @@ -import useSWR from "swr"; -import { ClashConfig, Profile } from "@/index"; -import * as tauri from "@/service/tauri"; -import { clash } from "../service/clash"; +import useSWR from 'swr' +import { ClashConfig, Profile } from '@/index' +import * as tauri from '@/service/tauri' +import { clash } from '../service/clash' /** * useClash with swr. * Data from tauri backend. */ export const useClash = () => { - const { deleteConnections, ...api } = clash(); + const { deleteConnections, ...api } = clash() - const getClashInfo = useSWR("getClashInfo", tauri.getClashInfo); - const getConfigs = useSWR("getClashConfig", api.getConfigs); + const getClashInfo = useSWR('getClashInfo', tauri.getClashInfo) + const getConfigs = useSWR('getClashConfig', api.getConfigs) const setConfigs = async (payload: Partial) => { try { - await tauri.patchClashConfig(payload); + await tauri.patchClashConfig(payload) - await Promise.all([getClashInfo.mutate(), getConfigs.mutate()]); + await Promise.all([getClashInfo.mutate(), getConfigs.mutate()]) } catch (e) { - console.error(e); - } finally { - return getClashInfo.data; + console.error(e) } - }; - const getVersion = useSWR("getClashVersion", api.getVersion); + return getClashInfo.data + } - const getRules = useSWR("getClashRules", api.getRules); + const getVersion = useSWR('getClashVersion', api.getVersion) - const getRuntimeExists = useSWR("getRuntimeExists", tauri.getRuntimeExists); + const getRules = useSWR('getClashRules', api.getRules) - const getProfiles = useSWR("getProfiles", tauri.getProfiles); + const getRuntimeExists = useSWR('getRuntimeExists', tauri.getRuntimeExists) + + const getProfiles = useSWR('getProfiles', tauri.getProfiles) const setProfiles = async (uid: string, profile: Partial) => { - await tauri.setProfiles({ uid, profile }); + await tauri.setProfiles({ uid, profile }) - await getProfiles.mutate(); + await getProfiles.mutate() - await getRuntimeLogs.mutate(); - }; + await getRuntimeLogs.mutate() + } const setProfilesConfig = async (profiles: Partial) => { - await tauri.setProfilesConfig(profiles); + await tauri.setProfilesConfig(profiles) - await getProfiles.mutate(); + await getProfiles.mutate() - await getRuntimeLogs.mutate(); - }; + await getRuntimeLogs.mutate() + } const createProfile = async (item: Partial, data?: string) => { - await tauri.createProfile(item, data); + await tauri.createProfile(item, data) - await getProfiles.mutate(); - }; + await getProfiles.mutate() + } const updateProfile = async (uid: string, option?: Profile.Option) => { - await tauri.updateProfile(uid, option); + await tauri.updateProfile(uid, option) - await getProfiles.mutate(); - }; + await getProfiles.mutate() + } const deleteProfile = async (uid: string) => { - await tauri.deleteProfile(uid); + await tauri.deleteProfile(uid) - await getProfiles.mutate(); - }; + await getProfiles.mutate() + } const getProfileFile = async (id?: string) => { if (id) { - const result = await tauri.readProfileFile(id); + const result = await tauri.readProfileFile(id) if (result) { - return result; + return result } else { - return ""; + return '' } } else { - return ""; + return '' } - }; + } const importProfile = async (url: string, option?: Profile.Option) => { - await tauri.importProfile(url, option); + await tauri.importProfile(url, option) - await getProfiles.mutate(); - }; + await getProfiles.mutate() + } - const getRuntimeLogs = useSWR("getRuntimeLogs", tauri.getRuntimeLogs, { + const getRuntimeLogs = useSWR('getRuntimeLogs', tauri.getRuntimeLogs, { refreshInterval: 1000, - }); + }) const reorderProfilesByList = async (list: string[]) => { - await tauri.reorderProfilesByList(list); + await tauri.reorderProfilesByList(list) - await getProfiles.mutate(); - }; + await getProfiles.mutate() + } return { getClashInfo, @@ -117,5 +117,5 @@ export const useClash = () => { getRuntimeLogs, setProfileFile: tauri.saveProfileFile, reorderProfilesByList, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/interface/src/ipc/useClashCore.ts b/clash-nyanpasu/frontend/interface/src/ipc/useClashCore.ts index 014f210159..41956a7ff9 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/useClashCore.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/useClashCore.ts @@ -1,95 +1,95 @@ -import useSWR from "swr"; +import useSWR from 'swr' import { Clash, clash as clashApi, ProviderItem, ProviderRules, -} from "@/service"; -import * as tauri from "@/service/tauri"; +} from '@/service' +import * as tauri from '@/service/tauri' export const useClashCore = () => { - const { getGroupDelay, getProxiesDelay, ...clash } = clashApi(); + const { getGroupDelay, getProxiesDelay, ...clash } = clashApi() - const { data, isLoading, mutate } = useSWR("getProxies", tauri.getProxies); + const { data, isLoading, mutate } = useSWR('getProxies', tauri.getProxies) const updateGroupDelay = async ( index: number, options?: Clash.DelayOptions, ) => { - const group = data?.groups[index]; + const group = data?.groups[index] if (!group) { - return; + return } - await getGroupDelay(group?.name, options); + await getGroupDelay(group?.name, options) - await mutate(() => tauri.mutateProxies()); - }; + await mutate(() => tauri.mutateProxies()) + } const updateProxiesDelay = async ( name: string, options?: Clash.DelayOptions, ) => { - const result = await getProxiesDelay(name, options); + const result = await getProxiesDelay(name, options) - await mutate(); + await mutate() - return result; - }; + return result + } const setGroupProxy = async (index: number, name: string) => { - const group = data?.groups[index]; + const group = data?.groups[index] if (!group) { - return; + return } - await tauri.selectProxy(group?.name, name); + await tauri.selectProxy(group?.name, name) - await mutate(); - }; + await mutate() + } const setGlobalProxy = async (name: string) => { - const group = data?.global; + const group = data?.global if (!group) { - return; + return } - await tauri.selectProxy(group?.name, name); + await tauri.selectProxy(group?.name, name) - await mutate(); - }; + await mutate() + } - const getRules = useSWR("getRules", clash.getRules); + const getRules = useSWR('getRules', clash.getRules) const getRulesProviders = useSWR<{ [name: string]: ProviderRules }>( - "getRulesProviders", + 'getRulesProviders', clash.getRulesProviders, - ); + ) const updateRulesProviders = async (name: string) => { - await clash.updateRulesProviders(name); + await clash.updateRulesProviders(name) - await getRulesProviders.mutate(); - }; + await getRulesProviders.mutate() + } const getProxiesProviders = useSWR<{ [name: string]: ProviderItem }>( - "getProxiesProviders", + 'getProxiesProviders', clash.getProxiesProviders, - ); + ) const getAllProxiesProviders = useSWR<{ [name: string]: ProviderItem }>( - "getAllProxiesProviders", + 'getAllProxiesProviders', clash.getAllProxiesProviders, - ); + ) const updateProxiesProviders = async (name: string) => { - await clash.updateProxiesProviders(name); + await clash.updateProxiesProviders(name) - await getProxiesProviders.mutate(); - }; + await getProxiesProviders.mutate() + } return { data, @@ -104,5 +104,5 @@ export const useClashCore = () => { getProxiesProviders, getAllProxiesProviders, updateProxiesProviders, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts b/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts index 4b8a2bc34e..7f85a8efdc 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts @@ -1,48 +1,48 @@ -import { useWebSocket } from "ahooks"; -import { useCallback, useMemo } from "react"; -import { useClash } from "./useClash"; +import { useWebSocket } from 'ahooks' +import { useCallback, useMemo } from 'react' +import { useClash } from './useClash' export const useClashWS = () => { - const { getClashInfo } = useClash(); + const { getClashInfo } = useClash() const getBaseUrl = useCallback(() => { - return `ws://${getClashInfo.data?.server}`; - }, [getClashInfo.data?.server]); + return `ws://${getClashInfo.data?.server}` + }, [getClashInfo.data?.server]) const getTokenUrl = useCallback(() => { - return `token=${encodeURIComponent(getClashInfo.data?.secret || "")}`; - }, [getClashInfo.data?.secret]); + return `token=${encodeURIComponent(getClashInfo.data?.secret || '')}` + }, [getClashInfo.data?.secret]) const resolveUrl = useCallback( (path: string) => { - return `${getBaseUrl()}/${path}?${getTokenUrl()}`; + return `${getBaseUrl()}/${path}?${getTokenUrl()}` }, [getBaseUrl, getTokenUrl], - ); + ) const url = useMemo(() => { if (getClashInfo.data) { return { - connections: resolveUrl("connections"), - logs: resolveUrl("logs"), - traffic: resolveUrl("traffic"), - memory: resolveUrl("memory"), - }; + connections: resolveUrl('connections'), + logs: resolveUrl('logs'), + traffic: resolveUrl('traffic'), + memory: resolveUrl('memory'), + } } - }, [getClashInfo.data, resolveUrl]); + }, [getClashInfo.data, resolveUrl]) - const connections = useWebSocket(url?.connections ?? ""); + const connections = useWebSocket(url?.connections ?? '') - const logs = useWebSocket(url?.logs ?? ""); + const logs = useWebSocket(url?.logs ?? '') - const traffic = useWebSocket(url?.traffic ?? ""); + const traffic = useWebSocket(url?.traffic ?? '') - const memory = useWebSocket(url?.memory ?? ""); + const memory = useWebSocket(url?.memory ?? '') return { connections, logs, traffic, memory, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/interface/src/ipc/useNyanpasu.ts b/clash-nyanpasu/frontend/interface/src/ipc/useNyanpasu.ts index 6606781395..1ba2f86783 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/useNyanpasu.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/useNyanpasu.ts @@ -1,135 +1,135 @@ -import { useMemo } from "react"; -import useSWR from "swr"; -import * as service from "@/service"; -import { VergeConfig } from "@/service"; -import { fetchCoreVersion, fetchLatestCore } from "@/service/core"; -import * as tauri from "@/service/tauri"; -import { useClash } from "./useClash"; +import { useMemo } from 'react' +import useSWR from 'swr' +import * as service from '@/service' +import { VergeConfig } from '@/service' +import { fetchCoreVersion, fetchLatestCore } from '@/service/core' +import * as tauri from '@/service/tauri' +import { useClash } from './useClash' /** * useNyanpasu with swr. * Data from tauri backend. */ export const useNyanpasu = (options?: { - onSuccess?: (data?: VergeConfig) => void; - onUpdate?: (data?: VergeConfig) => void; - onError?: (error: any) => void; - onLatestCoreError?: (error: any) => void; + onSuccess?: (data?: VergeConfig) => void + onUpdate?: (data?: VergeConfig) => void + onError?: (error: any) => void + onLatestCoreError?: (error: any) => void }) => { - const { getConfigs, setConfigs, deleteConnections } = useClash(); + const { getConfigs, setConfigs, deleteConnections } = useClash() const { data, error, mutate } = useSWR( - "nyanpasuConfig", + 'nyanpasuConfig', service.getNyanpasuConfig, { onSuccess: options?.onSuccess, }, - ); + ) const setNyanpasuConfig = async (payload: Partial) => { try { - await service.patchNyanpasuConfig(payload); + await service.patchNyanpasuConfig(payload) - const result = await mutate(); + const result = await mutate() if (options?.onUpdate) { - options?.onUpdate(result); + options?.onUpdate(result) } } catch (error) { if (options?.onError) { - options?.onError(error); + options?.onError(error) } else { - throw error; + throw error } } - }; + } - const getClashCore = useSWR("getClashCore", fetchCoreVersion); + const getClashCore = useSWR('getClashCore', fetchCoreVersion) const setClashCore = async ( - clashCore: Required["clash_core"], + clashCore: Required['clash_core'], ) => { - await service.setClashCore(clashCore); + await service.setClashCore(clashCore) // timeout for restart clash core. setTimeout(() => { - getClashCore.mutate(); - }, 100); - }; + getClashCore.mutate() + }, 100) + } - const getLatestCore = useSWR("getLatestCore", fetchLatestCore, { + const getLatestCore = useSWR('getLatestCore', fetchLatestCore, { revalidateOnMount: false, revalidateOnFocus: false, refreshInterval: 0, onError: options?.onLatestCoreError, - }); + }) - const updateCore = async (core: Required["clash_core"]) => { - return await service.updateCore(core); + const updateCore = async (core: Required['clash_core']) => { + return await service.updateCore(core) // getClashCore.mutate(); - }; + } - const getSystemProxy = useSWR("getSystemProxy", service.getSystemProxy); + const getSystemProxy = useSWR('getSystemProxy', service.getSystemProxy) - const getServiceStatus = useSWR("getServiceStatus", service.statusService); + const getServiceStatus = useSWR('getServiceStatus', service.statusService) const setServiceStatus = async ( - type: "install" | "uninstall" | "start" | "stop", + type: 'install' | 'uninstall' | 'start' | 'stop', ) => { switch (type) { - case "install": - await service.installService(); - break; + case 'install': + await service.installService() + break - case "uninstall": - await service.uninstallService(); - break; + case 'uninstall': + await service.uninstallService() + break - case "start": - await service.startService(); - break; + case 'start': + await service.startService() + break - case "stop": - await service.stopService(); - break; + case 'stop': + await service.stopService() + break default: - break; + break } - return getServiceStatus.mutate(); - }; + return getServiceStatus.mutate() + } const setCurrentMode = async (mode: string) => { - await deleteConnections(); + await deleteConnections() - await setConfigs({ mode }); + await setConfigs({ mode }) - await mutate(); - }; + await mutate() + } const getCurrentMode = useMemo(() => { const modes: { [key: string]: boolean } = { rule: false, global: false, direct: false, - }; - - if (data?.clash_core == "clash") { - modes.script = false; } - const mode = getConfigs.data?.mode?.toLowerCase(); + if (data?.clash_core === 'clash') { + modes.script = false + } - if (mode && modes.hasOwnProperty(mode)) { - modes[mode] = true; + const mode = getConfigs.data?.mode?.toLowerCase() + + if (mode && Object.prototype.hasOwnProperty.call(modes, mode)) { + modes[mode] = true } else { - modes.rule = true; + modes.rule = true } - return modes; - }, [data?.clash_core, getConfigs.data?.mode]); + return modes + }, [data?.clash_core, getConfigs.data?.mode]) return { nyanpasuConfig: data, @@ -147,5 +147,5 @@ export const useNyanpasu = (options?: { setServiceStatus, getCurrentMode, setCurrentMode, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/interface/src/openapi/geoip/index.ts b/clash-nyanpasu/frontend/interface/src/openapi/geoip/index.ts index f28923ab86..aa26b14ad4 100644 --- a/clash-nyanpasu/frontend/interface/src/openapi/geoip/index.ts +++ b/clash-nyanpasu/frontend/interface/src/openapi/geoip/index.ts @@ -1 +1 @@ -export * from "./ipsb"; +export * from './ipsb' diff --git a/clash-nyanpasu/frontend/interface/src/openapi/geoip/ipsb.ts b/clash-nyanpasu/frontend/interface/src/openapi/geoip/ipsb.ts index 3e4ab45e52..2ab945732d 100644 --- a/clash-nyanpasu/frontend/interface/src/openapi/geoip/ipsb.ts +++ b/clash-nyanpasu/frontend/interface/src/openapi/geoip/ipsb.ts @@ -1,21 +1,21 @@ -import useSWR, { SWRConfiguration } from "swr"; -import { getIpsbASN } from "@/service"; +import useSWR, { SWRConfiguration } from 'swr' +import { getIpsbASN } from '@/service' export interface IPSBResponse { - organization: string; - longitude: number; - timezone: string; - isp: string; - offset: number; - asn: number; - asn_organization: string; - country: string; - ip: string; - latitude: number; - continent_code: string; - country_code: string; + organization: string + longitude: number + timezone: string + isp: string + offset: number + asn: number + asn_organization: string + country: string + ip: string + latitude: number + continent_code: string + country_code: string } export const useIPSB = (config?: SWRConfiguration) => { - return useSWR("https://api.ip.sb/geoip", () => getIpsbASN(), config); -}; + return useSWR('https://api.ip.sb/geoip', () => getIpsbASN(), config) +} diff --git a/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/index.ts b/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/index.ts index f1be59e966..7ae08f011a 100644 --- a/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/index.ts +++ b/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/index.ts @@ -1,8 +1,8 @@ -import { createTiming } from "./utils"; +import { createTiming } from './utils' export const timing = { - Google: createTiming("https://www.gstatic.com/generate_204"), - GitHub: createTiming("https://github.com/", 200), - BingCN: createTiming("https://cn.bing.com/", 200), - Baidu: createTiming("https://www.baidu.com/", 200), -}; + Google: createTiming('https://www.gstatic.com/generate_204'), + GitHub: createTiming('https://github.com/', 200), + BingCN: createTiming('https://cn.bing.com/', 200), + Baidu: createTiming('https://www.baidu.com/', 200), +} diff --git a/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/utils.ts b/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/utils.ts index 9aaa62075f..66c653cc92 100644 --- a/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/utils.ts +++ b/clash-nyanpasu/frontend/interface/src/openapi/healthcheck/utils.ts @@ -1,9 +1,9 @@ -import { urlDelayTest } from "@/service"; +import { urlDelayTest } from '@/service' export const timing = async (url: string, code: number) => { - return (await urlDelayTest(url, code)) ?? 0; -}; + return (await urlDelayTest(url, code)) ?? 0 +} export const createTiming = (url: string, code: number = 204) => { - return () => timing(url, code); -}; + return () => timing(url, code) +} diff --git a/clash-nyanpasu/frontend/interface/src/openapi/index.ts b/clash-nyanpasu/frontend/interface/src/openapi/index.ts index 7d9c9212b7..36be7c5f4d 100644 --- a/clash-nyanpasu/frontend/interface/src/openapi/index.ts +++ b/clash-nyanpasu/frontend/interface/src/openapi/index.ts @@ -1,2 +1,2 @@ -export * from "./geoip"; -export * from "./healthcheck"; +export * from './geoip' +export * from './healthcheck' diff --git a/clash-nyanpasu/frontend/interface/src/service/clash.ts b/clash-nyanpasu/frontend/interface/src/service/clash.ts index 02c0ff80be..accc64028f 100644 --- a/clash-nyanpasu/frontend/interface/src/service/clash.ts +++ b/clash-nyanpasu/frontend/interface/src/service/clash.ts @@ -1,101 +1,102 @@ -import { ofetch } from "ofetch"; -import { getClashInfo } from "./tauri"; -import { ProviderItem } from "./types"; +import { ofetch } from 'ofetch' +import { getClashInfo } from './tauri' +import { ProviderItem } from './types' +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Clash { export interface Config { - port: number; - mode: string; - ipv6: boolean; - "socket-port": number; - "allow-lan": boolean; - "log-level": string; - "mixed-port": number; - "redir-port": number; - "socks-port": number; - "tproxy-port": number; - "external-controller": string; - secret: string; + port: number + mode: string + ipv6: boolean + 'socket-port': number + 'allow-lan': boolean + 'log-level': string + 'mixed-port': number + 'redir-port': number + 'socks-port': number + 'tproxy-port': number + 'external-controller': string + secret: string } export interface Version { - premium: boolean; - meta?: boolean; - version: string; + premium: boolean + meta?: boolean + version: string } export interface Rule { - type: string; - payload: string; - proxy: string; + type: string + payload: string + proxy: string } export interface Proxy { - name: string; - type: string; - udp: boolean; - xudp?: boolean; + name: string + type: string + udp: boolean + xudp?: boolean history: { - time: string; - delay: number; - }[]; - all?: T[]; - now?: string; - provider?: string; - alive?: boolean; - tfo?: boolean; - icon?: string; - hidden?: boolean; + time: string + delay: number + }[] + all?: T[] + now?: string + provider?: string + alive?: boolean + tfo?: boolean + icon?: string + hidden?: boolean } export interface DelayOptions { - url?: string; - timeout?: number; + url?: string + timeout?: number } } const prepareServer = (server: string) => { - if (server.startsWith(":")) { - return `127.0.0.1${server}`; + if (server.startsWith(':')) { + return `127.0.0.1${server}` } else if (/^\d+$/.test(server)) { - return `127.0.0.1:${server}`; + return `127.0.0.1:${server}` } else { - return server; + return server } -}; +} export const clash = () => { const buildRequest = async () => { - const info = await getClashInfo(); + const info = await getClashInfo() return ofetch.create({ baseURL: `http://${prepareServer(info?.server as string)}`, headers: info?.secret ? { Authorization: `Bearer ${info?.secret}` } : undefined, - }); - }; + }) + } const getConfigs = async () => { - return (await buildRequest())("/configs"); - }; + return (await buildRequest())('/configs') + } const setConfigs = async (config: Partial) => { - return (await buildRequest())("/configs", { - method: "PATCH", + return (await buildRequest())('/configs', { + method: 'PATCH', body: config, - }); - }; + }) + } const getVersion = async () => { - return (await buildRequest())("/version"); - }; + return (await buildRequest())('/version') + } const getRules = async () => { return (await buildRequest())<{ - rules: Clash.Rule[]; - }>("/rules"); - }; + rules: Clash.Rule[] + }>('/rules') + } const getProxiesDelay = async ( name: string, @@ -106,11 +107,11 @@ export const clash = () => { { params: { timeout: options?.timeout || 10000, - url: options?.url || "http://www.gstatic.com/generate_204", + url: options?.url || 'http://www.gstatic.com/generate_204', }, }, - ); - }; + ) + } const getGroupDelay = async (group: string, options?: Clash.DelayOptions) => { return (await buildRequest())<{ [key: string]: number }>( @@ -118,81 +119,81 @@ export const clash = () => { { params: { timeout: options?.timeout || 10000, - url: options?.url || "http://www.gstatic.com/generate_204", + url: options?.url || 'http://www.gstatic.com/generate_204', }, }, - ); - }; + ) + } const getProxies = async () => { return (await buildRequest())<{ - proxies: Clash.Proxy[]; - }>("/proxies"); - }; + proxies: Clash.Proxy[] + }>('/proxies') + } const setProxies = async ({ group, proxy, }: { - group: string; - proxy: string; + group: string + proxy: string }) => { return (await buildRequest())(`/proxies/${encodeURIComponent(group)}`, { - method: "PUT", + method: 'PUT', body: { name: proxy }, - }); - }; + }) + } const deleteConnections = async (id?: string) => { - return (await buildRequest())(id ? `/connections/${id}` : "/connections", { - method: "DELETE", - }); - }; + return (await buildRequest())(id ? `/connections/${id}` : '/connections', { + method: 'DELETE', + }) + } const getRulesProviders = async () => { return ( await ( await buildRequest() - )("/providers/rules", { - method: "GET", + )('/providers/rules', { + method: 'GET', }) - )?.providers; - }; + )?.providers + } const updateRulesProviders = async (name: string) => { return (await buildRequest())(`/providers/rules/${name}`, { - method: "PUT", - }); - }; + method: 'PUT', + }) + } const getProxiesProviders = async () => { const result: { [key: string]: ProviderItem } = ( await ( await buildRequest() - )("/providers/proxies") - )?.providers; + )('/providers/proxies') + )?.providers - const types = ["http", "file"]; + const types = ['http', 'file'] return Object.fromEntries( Object.entries(result).filter(([, value]) => types.includes(value.vehicleType.toLowerCase()), ), - ); - }; + ) + } const getAllProxiesProviders = async () => { - return (await (await buildRequest())("/providers/proxies"))?.providers; - }; + return (await (await buildRequest())('/providers/proxies'))?.providers + } const updateProxiesProviders = async (name: string) => { return (await buildRequest())( `/providers/proxies/${encodeURIComponent(name)}`, { - method: "PUT", + method: 'PUT', }, - ); - }; + ) + } return { getConfigs, @@ -209,5 +210,5 @@ export const clash = () => { getProxiesProviders, getAllProxiesProviders, updateProxiesProviders, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/interface/src/service/core.ts b/clash-nyanpasu/frontend/interface/src/service/core.ts index 1878934b8c..44e9d8f011 100644 --- a/clash-nyanpasu/frontend/interface/src/service/core.ts +++ b/clash-nyanpasu/frontend/interface/src/service/core.ts @@ -1,92 +1,92 @@ -import { fetchLatestCoreVersions, getCoreVersion } from "./tauri"; -import { VergeConfig } from "./types"; +import { fetchLatestCoreVersions, getCoreVersion } from './tauri' +import { VergeConfig } from './types' -export type ClashCore = Required["clash_core"]; +export type ClashCore = Required['clash_core'] export interface Core { - name: string; - core: ClashCore; - version?: string; - latest?: string; + name: string + core: ClashCore + version?: string + latest?: string } export const VALID_CORE: Core[] = [ - { name: "Clash Premium", core: "clash" }, - { name: "Mihomo", core: "mihomo" }, - { name: "Mihomo Alpha", core: "mihomo-alpha" }, - { name: "Clash Rust", core: "clash-rs" }, - { name: "Clash Rust Alpha", core: "clash-rs-alpha" }, -]; + { name: 'Clash Premium', core: 'clash' }, + { name: 'Mihomo', core: 'mihomo' }, + { name: 'Mihomo Alpha', core: 'mihomo-alpha' }, + { name: 'Clash Rust', core: 'clash-rs' }, + { name: 'Clash Rust Alpha', core: 'clash-rs-alpha' }, +] export const fetchCoreVersion = async () => { return await Promise.all( VALID_CORE.map(async (item) => { try { - const version = await getCoreVersion(item.core); - return { ...item, version }; + const version = await getCoreVersion(item.core) + return { ...item, version } } catch (e) { - console.error("failed to fetch core version", e); - return { ...item, version: "N/A" }; + console.error('failed to fetch core version', e) + return { ...item, version: 'N/A' } } }), - ); -}; + ) +} export const fetchLatestCore = async () => { - const results = await fetchLatestCoreVersions(); + const results = await fetchLatestCoreVersions() const cores = VALID_CORE.map((item) => { - const key = item.core.replace(/-/g, "_") as keyof typeof results; + const key = item.core.replace(/-/g, '_') as keyof typeof results - let latest: string; + let latest: string switch (item.core) { - case "clash": - latest = `n${results["clash_premium"]}`; - break; + case 'clash': + latest = `n${results['clash_premium']}` + break - case "clash-rs": - latest = results[key].replace(/v/, ""); - break; + case 'clash-rs': + latest = results[key].replace(/v/, '') + break default: - latest = results[key]; - break; + latest = results[key] + break } return { ...item, latest: latest, - }; - }); + } + }) - return cores; -}; + return cores +} export enum SupportedArch { // blocked by clash-rs // WindowsX86 = "windows-x86", - WindowsX86_64 = "windows-x86_64", + WindowsX86_64 = 'windows-x86_64', // blocked by clash-rs#212 // WindowsArm64 = "windows-arm64", - LinuxAarch64 = "linux-aarch64", - LinuxAmd64 = "linux-amd64", - DarwinArm64 = "darwin-arm64", - DarwinX64 = "darwin-x64", + LinuxAarch64 = 'linux-aarch64', + LinuxAmd64 = 'linux-amd64', + DarwinArm64 = 'darwin-arm64', + DarwinX64 = 'darwin-x64', } export enum SupportedCore { - Mihomo = "mihomo", - MihomoAlpha = "mihomo_alpha", - ClashRs = "clash_rs", - ClashPremium = "clash_premium", + Mihomo = 'mihomo', + MihomoAlpha = 'mihomo_alpha', + ClashRs = 'clash_rs', + ClashPremium = 'clash_premium', } -export type ArchMapping = { [key in SupportedArch]: string }; +export type ArchMapping = { [key in SupportedArch]: string } export interface ManifestVersion { - manifest_version: number; - latest: { [K in SupportedCore]: string }; - arch_template: { [K in SupportedCore]: ArchMapping }; - updated_at: string; // ISO 8601 + manifest_version: number + latest: { [K in SupportedCore]: string } + arch_template: { [K in SupportedCore]: ArchMapping } + updated_at: string // ISO 8601 } diff --git a/clash-nyanpasu/frontend/interface/src/service/index.ts b/clash-nyanpasu/frontend/interface/src/service/index.ts index e16da452ab..271d15c3e4 100644 --- a/clash-nyanpasu/frontend/interface/src/service/index.ts +++ b/clash-nyanpasu/frontend/interface/src/service/index.ts @@ -1,4 +1,4 @@ -export * from "./types"; -export * from "./tauri"; -export * from "./clash"; -export * from "./core"; +export * from './types' +export * from './tauri' +export * from './clash' +export * from './core' diff --git a/clash-nyanpasu/frontend/interface/src/service/tauri.ts b/clash-nyanpasu/frontend/interface/src/service/tauri.ts index 241b99e5b7..4c055605c0 100644 --- a/clash-nyanpasu/frontend/interface/src/service/tauri.ts +++ b/clash-nyanpasu/frontend/interface/src/service/tauri.ts @@ -1,6 +1,6 @@ -import { IPSBResponse } from "@/openapi"; -import { invoke } from "@tauri-apps/api/core"; -import { ManifestVersion } from "./core"; +import { IPSBResponse } from '@/openapi' +import { invoke } from '@tauri-apps/api/core' +import { ManifestVersion } from './core' import { ClashConfig, ClashInfo, @@ -10,280 +10,280 @@ import { Proxies, SystemProxy, VergeConfig, -} from "./types"; +} from './types' export const getNyanpasuConfig = async () => { - return await invoke("get_verge_config"); -}; + return await invoke('get_verge_config') +} export const patchNyanpasuConfig = async (payload: VergeConfig) => { - return await invoke("patch_verge_config", { payload }); -}; + return await invoke('patch_verge_config', { payload }) +} export const getClashInfo = async () => { - return await invoke("get_clash_info"); -}; + return await invoke('get_clash_info') +} export const patchClashConfig = async (payload: Partial) => { - return await invoke("patch_clash_config", { payload }); -}; + return await invoke('patch_clash_config', { payload }) +} export const getRuntimeExists = async () => { - return await invoke("get_runtime_exists"); -}; + return await invoke('get_runtime_exists') +} export const getRuntimeLogs = async () => { - return await invoke>("get_runtime_logs"); -}; + return await invoke>('get_runtime_logs') +} export const createProfile = async ( item: Partial, fileData?: string | null, ) => { - return await invoke("create_profile", { item, fileData }); -}; + return await invoke('create_profile', { item, fileData }) +} export const updateProfile = async (uid: string, option?: Profile.Option) => { - return await invoke("update_profile", { uid, option }); -}; + return await invoke('update_profile', { uid, option }) +} export const deleteProfile = async (uid: string) => { - return await invoke("delete_profile", { uid }); -}; + return await invoke('delete_profile', { uid }) +} export const viewProfile = async (uid: string) => { - return await invoke("view_profile", { uid }); -}; + return await invoke('view_profile', { uid }) +} export const getProfiles = async () => { - return await invoke("get_profiles"); -}; + return await invoke('get_profiles') +} export const setProfiles = async (payload: { - uid: string; - profile: Partial; + uid: string + profile: Partial }) => { - return await invoke("patch_profile", payload); -}; + return await invoke('patch_profile', payload) +} export const setProfilesConfig = async (profiles: Partial) => { - return await invoke("patch_profiles_config", { profiles }); -}; + return await invoke('patch_profiles_config', { profiles }) +} export const readProfileFile = async (uid: string) => { - return await invoke("read_profile_file", { uid }); -}; + return await invoke('read_profile_file', { uid }) +} export const saveProfileFile = async (uid: string, fileData: string) => { - return await invoke("save_profile_file", { uid, fileData }); -}; + return await invoke('save_profile_file', { uid, fileData }) +} export const importProfile = async ( url: string, option: Profile.Option = { with_proxy: true }, ) => { - return await invoke("import_profile", { + return await invoke('import_profile', { url, option, - }); -}; + }) +} export const getCoreVersion = async ( - coreType: Required["clash_core"], + coreType: Required['clash_core'], ) => { - return await invoke("get_core_version", { coreType }); -}; + return await invoke('get_core_version', { coreType }) +} export const setClashCore = async ( - clashCore: Required["clash_core"], + clashCore: Required['clash_core'], ) => { - return await invoke("change_clash_core", { clashCore }); -}; + return await invoke('change_clash_core', { clashCore }) +} export const restartSidecar = async () => { - return await invoke("restart_sidecar"); -}; + return await invoke('restart_sidecar') +} export const fetchLatestCoreVersions = async () => { - return await invoke("fetch_latest_core_versions"); -}; + return await invoke('fetch_latest_core_versions') +} export const updateCore = async ( - coreType: Required["clash_core"], + coreType: Required['clash_core'], ) => { - return await invoke("update_core", { coreType }); -}; + return await invoke('update_core', { coreType }) +} export const inspectUpdater = async (updaterId: number) => { - return await invoke("inspect_updater", { updaterId }); -}; + return await invoke('inspect_updater', { updaterId }) +} export const pullupUWPTool = async () => { - return await invoke("invoke_uwp_tool"); -}; + return await invoke('invoke_uwp_tool') +} export const getSystemProxy = async () => { - return await invoke("get_sys_proxy"); -}; + return await invoke('get_sys_proxy') +} export const statusService = async () => { try { const result = await invoke<{ - status: "running" | "stopped" | "not_installed"; - }>("status_service"); - return result.status; + status: 'running' | 'stopped' | 'not_installed' + }>('status_service') + return result.status } catch (e) { - console.error(e); - return "not_installed"; + console.error(e) + return 'not_installed' } -}; +} export const installService = async () => { - return await invoke("install_service"); -}; + return await invoke('install_service') +} export const uninstallService = async () => { - return await invoke("uninstall_service"); -}; + return await invoke('uninstall_service') +} export const startService = async () => { - return await invoke("start_service"); -}; + return await invoke('start_service') +} export const stopService = async () => { - return await invoke("stop_service"); -}; + return await invoke('stop_service') +} export const restartService = async () => { - return await invoke("restart_service"); -}; + return await invoke('restart_service') +} export const openAppConfigDir = async () => { - return await invoke("open_app_config_dir"); -}; + return await invoke('open_app_config_dir') +} export const openAppDataDir = async () => { - return await invoke("open_app_data_dir"); -}; + return await invoke('open_app_data_dir') +} export const openCoreDir = async () => { - return await invoke("open_core_dir"); -}; + return await invoke('open_core_dir') +} export const getCoreDir = async () => { - return await invoke("get_core_dir"); -}; + return await invoke('get_core_dir') +} export const openLogsDir = async () => { - return await invoke("open_logs_dir"); -}; + return await invoke('open_logs_dir') +} export const collectLogs = async () => { - return await invoke("collect_logs"); -}; + return await invoke('collect_logs') +} export const setCustomAppDir = async (path: string) => { - return await invoke("set_custom_app_dir", { path }); -}; + return await invoke('set_custom_app_dir', { path }) +} export const restartApplication = async () => { - return await invoke("restart_application"); -}; + return await invoke('restart_application') +} export const isPortable = async () => { - return await invoke("is_portable"); -}; + return await invoke('is_portable') +} export const getProxies = async () => { - return await invoke("get_proxies"); -}; + return await invoke('get_proxies') +} export const mutateProxies = async () => { - return await invoke("mutate_proxies"); -}; + return await invoke('mutate_proxies') +} export const selectProxy = async (group: string, name: string) => { - return await invoke("select_proxy", { group, name }); -}; + return await invoke('select_proxy', { group, name }) +} export const updateProxyProvider = async (name: string) => { - return await invoke("update_proxy_provider", { name }); -}; + return await invoke('update_proxy_provider', { name }) +} -export const save_window_size_state = async () => { - return await invoke("save_window_size_state"); -}; +export const saveWindowSizeState = async () => { + return await invoke('save_window_size_state') +} -export const collect_envs = async () => { - return await invoke("collect_envs"); -}; +export const collectEnvs = async () => { + return await invoke('collect_envs') +} export const getRuntimeYaml = async () => { - return await invoke("get_runtime_yaml"); -}; + return await invoke('get_runtime_yaml') +} export const getServerPort = async () => { - return await invoke("get_server_port"); -}; + return await invoke('get_server_port') +} export const setTrayIcon = async ( - mode: "tun" | "system_proxy" | "normal", + mode: 'tun' | 'system_proxy' | 'normal', path?: string, ) => { - return await invoke("set_tray_icon", { mode, path }); -}; + return await invoke('set_tray_icon', { mode, path }) +} export const isTrayIconSet = async ( - mode: "tun" | "system_proxy" | "normal", + mode: 'tun' | 'system_proxy' | 'normal', ) => { - return await invoke("is_tray_icon_set", { + return await invoke('is_tray_icon_set', { mode, - }); -}; + }) +} export const getCoreStatus = async () => { return await invoke< - ["Running" | { Stopped: string | null }, number, "normal" | "service"] - >("get_core_status"); -}; + ['Running' | { Stopped: string | null }, number, 'normal' | 'service'] + >('get_core_status') +} export const urlDelayTest = async (url: string, expectedStatus: number) => { - return await invoke("url_delay_test", { + return await invoke('url_delay_test', { url, expectedStatus, - }); -}; + }) +} -export const getIpsbASN = async () => invoke("get_ipsb_asn"); +export const getIpsbASN = async () => invoke('get_ipsb_asn') export const openThat = async (path: string) => { - return await invoke("open_that", { path }); -}; + return await invoke('open_that', { path }) +} export const isAppImage = async () => { - return await invoke("is_appimage"); -}; + return await invoke('is_appimage') +} export const getServiceInstallPrompt = async () => { - return await invoke("get_service_install_prompt"); -}; + return await invoke('get_service_install_prompt') +} export const cleanupProcesses = async () => { - return await invoke("cleanup_processes"); -}; + return await invoke('cleanup_processes') +} export const getStorageItem = async (key: string) => { - return await invoke("get_storage_item", { key }); -}; + return await invoke('get_storage_item', { key }) +} export const setStorageItem = async (key: string, value: string) => { - return await invoke("set_storage_item", { key, value }); -}; + return await invoke('set_storage_item', { key, value }) +} export const removeStorageItem = async (key: string) => { - return await invoke("remove_storage_item", { key }); -}; + return await invoke('remove_storage_item', { key }) +} export const reorderProfilesByList = async (list: string[]) => { - return await invoke("reorder_profiles_by_list", { list }); -}; + return await invoke('reorder_profiles_by_list', { list }) +} diff --git a/clash-nyanpasu/frontend/interface/src/service/types.ts b/clash-nyanpasu/frontend/interface/src/service/types.ts index 9170fa3569..037396f6a1 100644 --- a/clash-nyanpasu/frontend/interface/src/service/types.ts +++ b/clash-nyanpasu/frontend/interface/src/service/types.ts @@ -1,85 +1,86 @@ -import { Clash } from "./clash"; +import { Clash } from './clash' export interface VergeConfig { - app_log_level?: "trace" | "debug" | "info" | "warn" | "error" | string; - language?: string; + app_log_level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | string + language?: string clash_core?: - | "mihomo" - | "mihomo-alpha" - | "clash-rs" - | "clash-rs-alpha" - | "clash"; - theme_mode?: "light" | "dark" | "system"; - theme_blur?: boolean; - traffic_graph?: boolean; - enable_memory_usage?: boolean; - lighten_animation_effects?: boolean; - enable_auto_check_update?: boolean; - enable_tun_mode?: boolean; - enable_auto_launch?: boolean; - enable_service_mode?: boolean; - enable_silent_start?: boolean; - enable_system_proxy?: boolean; - enable_random_port?: boolean; - verge_mixed_port?: number; - enable_proxy_guard?: boolean; - proxy_guard_interval?: number; - system_proxy_bypass?: string; - web_ui_list?: string[]; - hotkeys?: string[]; + | 'mihomo' + | 'mihomo-alpha' + | 'clash-rs' + | 'clash-rs-alpha' + | 'clash' + theme_mode?: 'light' | 'dark' | 'system' + theme_blur?: boolean + traffic_graph?: boolean + enable_memory_usage?: boolean + lighten_animation_effects?: boolean + enable_auto_check_update?: boolean + enable_tun_mode?: boolean + enable_auto_launch?: boolean + enable_service_mode?: boolean + enable_silent_start?: boolean + enable_system_proxy?: boolean + enable_random_port?: boolean + verge_mixed_port?: number + enable_proxy_guard?: boolean + proxy_guard_interval?: number + system_proxy_bypass?: string + web_ui_list?: string[] + hotkeys?: string[] theme_setting?: { - primary_color?: string; - secondary_color?: string; - primary_text?: string; - secondary_text?: string; - info_color?: string; - error_color?: string; - warning_color?: string; - success_color?: string; - font_family?: string; - css_injection?: string; - page_transition_duration?: number; - }; - max_log_files?: number; - auto_close_connection?: boolean; - default_latency_test?: string; - enable_clash_fields?: boolean; - enable_builtin_enhanced?: boolean; - proxy_layout_column?: number; - clash_tray_selector?: "normal" | "hidden" | "submenu"; + primary_color?: string + secondary_color?: string + primary_text?: string + secondary_text?: string + info_color?: string + error_color?: string + warning_color?: string + success_color?: string + font_family?: string + css_injection?: string + page_transition_duration?: number + } + max_log_files?: number + auto_close_connection?: boolean + default_latency_test?: string + enable_clash_fields?: boolean + enable_builtin_enhanced?: boolean + proxy_layout_column?: number + clash_tray_selector?: 'normal' | 'hidden' | 'submenu' clash_strategy?: { - external_controller_port_strategy: "fixed" | "random" | "allow_fallback"; - }; - tun_stack?: "system" | "gvisor" | "mixed"; - always_on_top?: boolean; + external_controller_port_strategy: 'fixed' | 'random' | 'allow_fallback' + } + tun_stack?: 'system' | 'gvisor' | 'mixed' + always_on_top?: boolean } export interface ClashInfo { - port?: number; - server?: string; - secret?: string; + port?: number + server?: string + secret?: string } export interface ClashConfig { - port: number; - mode: string; - ipv6: boolean; - "socket-port": number; - "allow-lan": boolean; - "log-level": string; - "mixed-port": number; - "redir-port": number; - "socks-port": number; - "tproxy-port": number; - "external-controller": string; - secret: string; + port: number + mode: string + ipv6: boolean + 'socket-port': number + 'allow-lan': boolean + 'log-level': string + 'mixed-port': number + 'redir-port': number + 'socks-port': number + 'tproxy-port': number + 'external-controller': string + secret: string } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Profile { export interface Config { - current: string[]; - chain: string[]; - valid: string[]; - items: Item[]; + current: string[] + chain: string[] + valid: string[] + items: Item[] } export const Template = { @@ -112,189 +113,190 @@ proxy-groups: rules: `, - }; + } export const Type = { - Local: "local", - Remote: "remote", - Merge: "merge", + Local: 'local', + Remote: 'remote', + Merge: 'merge', JavaScript: { - script: "javascript", + script: 'javascript', }, LuaScript: { - script: "lua", + script: 'lua', }, - } as const; + } as const export interface Item { - uid: string; - type?: (typeof Type)[keyof typeof Type]; - name?: string; - desc?: string; - file?: string; - url?: string; - updated?: number; + uid: string + type?: (typeof Type)[keyof typeof Type] + name?: string + desc?: string + file?: string + url?: string + updated?: number selected?: { - name?: string; - now?: string; - }[]; + name?: string + now?: string + }[] extra?: { - upload: number; - download: number; - total: number; - expire: number; - }; - option?: Option; - chain?: string[]; + upload: number + download: number + total: number + expire: number + } + option?: Option + chain?: string[] } export interface Option { - user_agent?: string; - with_proxy?: boolean; - self_proxy?: boolean; - update_interval?: number; + user_agent?: string + with_proxy?: boolean + self_proxy?: boolean + update_interval?: number } } export interface SystemProxy { - enable: boolean; - server: string; - bypass: string; + enable: boolean + server: string + bypass: string } export interface Proxies { - direct: Clash.Proxy; - global: Clash.Proxy; - groups: Clash.Proxy[]; - proxies: Clash.Proxy[]; + direct: Clash.Proxy + global: Clash.Proxy + groups: Clash.Proxy[] + proxies: Clash.Proxy[] records: { - [key: string]: Clash.Proxy; - }; + [key: string]: Clash.Proxy + } } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Connection { export interface Item { - id: string; - metadata: Metadata; - upload: number; - download: number; - start: string; - chains: string[]; - rule: string; - rulePayload: string; + id: string + metadata: Metadata + upload: number + download: number + start: string + chains: string[] + rule: string + rulePayload: string } export interface Metadata { - network: string; - type: string; - host: string; - sourceIP: string; - sourcePort: string; - destinationPort: string; - destinationIP?: string; - destinationIPASN?: string; - process?: string; - processPath?: string; - dnsMode?: string; - dscp?: number; - inboundIP?: string; - inboundName?: string; - inboundPort?: string; - inboundUser?: string; - remoteDestination?: string; - sniffHost?: string; - specialProxy?: string; - specialRules?: string; + network: string + type: string + host: string + sourceIP: string + sourcePort: string + destinationPort: string + destinationIP?: string + destinationIPASN?: string + process?: string + processPath?: string + dnsMode?: string + dscp?: number + inboundIP?: string + inboundName?: string + inboundPort?: string + inboundUser?: string + remoteDestination?: string + sniffHost?: string + specialProxy?: string + specialRules?: string } export interface Response { - downloadTotal: number; - uploadTotal: number; - memory?: number; - connections?: Item[]; + downloadTotal: number + uploadTotal: number + memory?: number + connections?: Item[] } } export interface LogMessage { - type: string; - time?: string; - payload: string; + type: string + time?: string + payload: string } export interface ProviderRules { - behavior: string; - format: string; - name: string; - ruleCount: number; - type: string; - updatedAt: string; - vehicleType: string; + behavior: string + format: string + name: string + ruleCount: number + type: string + updatedAt: string + vehicleType: string } export interface ProviderItem { - name: string; - type: string; - proxies: Clash.Proxy[]; - updatedAt?: string; - vehicleType: string; + name: string + type: string + proxies: Clash.Proxy[] + updatedAt?: string + vehicleType: string subscriptionInfo?: { - Upload?: number; - Download?: number; - Total?: number; - Expire?: number; - }; - testUrl?: string; + Upload?: number + Download?: number + Total?: number + Expire?: number + } + testUrl?: string } export interface Traffic { - up: number; - down: number; + up: number + down: number } export interface Memory { - inuse: number; - oslimit: number; + inuse: number + oslimit: number } export interface EnvInfos { - os: string; - arch: string; - core: { [key: string]: string }; + os: string + arch: string + core: { [key: string]: string } device: { - cpu: Array; - memory: string; - }; - build_info: { [key: string]: string }; + cpu: Array + memory: string + } + build_info: { [key: string]: string } } export interface InspectUpdater { - id: number; + id: number state: - | "idle" - | "downloading" - | "decompressing" - | "replacing" - | "restarting" - | "done" - | { failed: string }; + | 'idle' + | 'downloading' + | 'decompressing' + | 'replacing' + | 'restarting' + | 'done' + | { failed: string } downloader: { state: - | "idle" - | "downloading" - | "waiting_for_merge" - | "merging" + | 'idle' + | 'downloading' + | 'waiting_for_merge' + | 'merging' | { failed: string } - | "finished"; - downloaded: number; - total: number; - speed: number; + | 'finished' + downloaded: number + total: number + speed: number chunks: Array<{ - state: "idle" | "downloading" | "finished"; - start: number; - end: number; - downloaded: number; - speed: number; - }>; - now: number; - }; + state: 'idle' | 'downloading' | 'finished' + start: number + end: number + downloaded: number + speed: number + }> + now: number + } } diff --git a/clash-nyanpasu/frontend/nyanpasu/index.html b/clash-nyanpasu/frontend/nyanpasu/index.html index 8177b519ed..2b2366a205 100644 --- a/clash-nyanpasu/frontend/nyanpasu/index.html +++ b/clash-nyanpasu/frontend/nyanpasu/index.html @@ -10,25 +10,25 @@ Clash Nyanpasu diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 7444db96f8..b035bbd389 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -52,7 +52,7 @@ "@csstools/normalize.css": "12.1.1", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", - "@iconify/json": "2.2.283", + "@iconify/json": "2.2.285", "@monaco-editor/react": "4.6.0", "@tanstack/react-router": "1.89.2", "@tanstack/router-devtools": "1.89.2", @@ -78,7 +78,7 @@ "meta-json-schema": "1.18.10", "monaco-yaml": "5.2.3", "nanoid": "5.0.9", - "sass": "1.83.0", + "sass-embedded": "1.83.0", "shiki": "1.24.2", "tailwindcss-textshadow": "2.1.3", "unplugin-auto-import": "0.19.0", diff --git a/clash-nyanpasu/frontend/nyanpasu/postcss.config.js b/clash-nyanpasu/frontend/nyanpasu/postcss.config.js index 22b100266a..ff9d4b3982 100644 --- a/clash-nyanpasu/frontend/nyanpasu/postcss.config.js +++ b/clash-nyanpasu/frontend/nyanpasu/postcss.config.js @@ -1,9 +1,9 @@ export default { plugins: { // to edit target browsers: use "browserslist" field in package.json - "postcss-import": {}, - "postcss-html": {}, + 'postcss-import': {}, + 'postcss-html': {}, autoprefixer: {}, tailwindcss: {}, }, -}; +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/fonts.scss b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/fonts.scss index 1f41b6d580..8a40d8bdbf 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/fonts.scss +++ b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/fonts.scss @@ -1,16 +1,16 @@ // 这个字体是为了解决在 Windows 系统下,微软因为政策问题,不支持显示国旗 emoji 的问题 @font-face { - font-family: "Color Emoji Flags"; - src: local("Apple Color Emoji"), local("Noto Color Emoji"), - url("../fonts/Twemoji.Mozilla.ttf"); + font-family: 'Color Emoji Flags'; + src: local('Apple Color Emoji'), local('Noto Color Emoji'), + url('../fonts/Twemoji.Mozilla.ttf'); unicode-range: U+1F1E6-1F1FF; } @font-face { - font-family: "Color Emoji"; - src: local("Apple Color Emoji"), local("Segoe UI Emoji"), - local("Segoe UI Symbol"), local("Noto Color Emoji"), - url("../fonts/Twemoji.Mozilla.ttf"); + font-family: 'Color Emoji'; + src: local('Apple Color Emoji'), local('Segoe UI Emoji'), + local('Segoe UI Symbol'), local('Noto Color Emoji'), + url('../fonts/Twemoji.Mozilla.ttf'); // use local emoji font for better backward compatibility } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/index.scss b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/index.scss index 5b993e95d3..15ded366ad 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/index.scss +++ b/clash-nyanpasu/frontend/nyanpasu/src/assets/styles/index.scss @@ -1,4 +1,4 @@ -@import "./fonts.scss"; +@import './fonts.scss'; body { margin: 0; @@ -9,12 +9,12 @@ body { BlinkMacSystemFont, Segoe UI, Roboto, - "Helvetica Neue", + 'Helvetica Neue', Arial, - "Noto Sans", + 'Noto Sans', sans-serif, - "Color Emoji Flags", - "Color Emoji"; + 'Color Emoji Flags', + 'Color Emoji'; user-select: none; -webkit-font-smoothing: antialiased; } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.module.scss.d.ts index 1f1eda8994..e3287f6963 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.module.scss.d.ts @@ -1,5 +1,5 @@ declare const classNames: { - readonly layout: "layout"; - readonly container: "container"; -}; -export default classNames; + readonly layout: 'layout' + readonly container: 'container' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx index 044478fc5e..0f57e8aefb 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx @@ -1,31 +1,31 @@ -import getSystem from "@/utils/get-system"; -import { alpha, useTheme } from "@mui/material"; -import Paper from "@mui/material/Paper"; -import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; -import "allotment/dist/style.css"; -import { useAtomValue } from "jotai"; -import { ReactNode } from "react"; -import { atomIsDrawerOnlyIcon } from "@/store"; -import { cn } from "@nyanpasu/ui"; -import { LayoutControl } from "../layout/layout-control"; -import styles from "./app-container.module.scss"; -import AppDrawer from "./app-drawer"; -import DrawerContent from "./drawer-content"; +import getSystem from '@/utils/get-system' +import { alpha, useTheme } from '@mui/material' +import Paper from '@mui/material/Paper' +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' +import 'allotment/dist/style.css' +import { useAtomValue } from 'jotai' +import { ReactNode } from 'react' +import { atomIsDrawerOnlyIcon } from '@/store' +import { cn } from '@nyanpasu/ui' +import { LayoutControl } from '../layout/layout-control' +import styles from './app-container.module.scss' +import AppDrawer from './app-drawer' +import DrawerContent from './drawer-content' -const appWindow = getCurrentWebviewWindow(); +const appWindow = getCurrentWebviewWindow() -const OS = getSystem(); +const OS = getSystem() export const AppContainer = ({ children, isDrawer, }: { - children?: ReactNode; - isDrawer?: boolean; + children?: ReactNode + isDrawer?: boolean }) => { - const { palette } = useTheme(); + const { palette } = useTheme() - const onlyIcon = useAtomValue(atomIsDrawerOnlyIcon); + const onlyIcon = useAtomValue(atomIsDrawerOnlyIcon) return ( { if (e.target?.dataset?.windrag) { - appWindow.startDragging(); + appWindow.startDragging() } }} onContextMenu={(e) => { - e.preventDefault(); + e.preventDefault() }} > {isDrawer && } {!isDrawer && ( -
+
)}
- {OS === "windows" && ( + {OS === 'windows' && ( )} - {OS === "macos" && ( + {OS === 'macos' && (
{children}
- ); -}; + ) +} -export default AppContainer; +export default AppContainer diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-drawer.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-drawer.tsx index 762fbfb59e..0adced48ea 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-drawer.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-drawer.tsx @@ -1,23 +1,23 @@ -import { AnimatePresence, motion } from "framer-motion"; -import { useState } from "react"; -import getSystem from "@/utils/get-system"; -import { MenuOpen } from "@mui/icons-material"; -import { alpha, Backdrop, IconButton } from "@mui/material"; -import { cn } from "@nyanpasu/ui"; -import AnimatedLogo from "../layout/animated-logo"; -import DrawerContent from "./drawer-content"; +import { AnimatePresence, motion } from 'framer-motion' +import { useState } from 'react' +import getSystem from '@/utils/get-system' +import { MenuOpen } from '@mui/icons-material' +import { alpha, Backdrop, IconButton } from '@mui/material' +import { cn } from '@nyanpasu/ui' +import AnimatedLogo from '../layout/animated-logo' +import DrawerContent from './drawer-content' -const OS = getSystem(); +const OS = getSystem() export const AppDrawer = () => { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) const DrawerTitle = () => { return (
@@ -26,7 +26,7 @@ export const AppDrawer = () => { sx={[ (theme) => ({ backgroundColor: alpha(theme.palette.primary.main, 0.1), - svg: { transform: "scale(0.9)" }, + svg: { transform: 'scale(0.9)' }, }), ]} onClick={() => setOpen(true)} @@ -42,23 +42,23 @@ export const AppDrawer = () => { Clash Nyanpasu
- ); - }; + ) + } return ( <> - OS === "linux" + OS === 'linux' ? { backgroundColor: null, } : { backgroundColor: alpha(theme.palette.primary.light, 0.1), - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { backgroundColor: alpha(theme.palette.primary.dark, 0.1), }), }, @@ -70,7 +70,7 @@ export const AppDrawer = () => {
{ }, }} transition={{ - type: "tween", + type: 'tween', }} > @@ -89,7 +89,7 @@ export const AppDrawer = () => { - ); -}; + ) +} -export default AppDrawer; +export default AppDrawer diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx index 4a473f22a7..4a51b4de37 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx @@ -1,34 +1,34 @@ -import getSystem from "@/utils/get-system"; -import { getRoutesWithIcon } from "@/utils/routes-utils"; -import { Box } from "@mui/material"; -import { cn } from "@nyanpasu/ui"; -import AnimatedLogo from "../layout/animated-logo"; -import RouteListItem from "./modules/route-list-item"; +import getSystem from '@/utils/get-system' +import { getRoutesWithIcon } from '@/utils/routes-utils' +import { Box } from '@mui/material' +import { cn } from '@nyanpasu/ui' +import AnimatedLogo from '../layout/animated-logo' +import RouteListItem from './modules/route-list-item' export const DrawerContent = ({ className, onlyIcon, }: { - className?: string; - onlyIcon?: boolean; + className?: string + onlyIcon?: boolean }) => { - const routes = getRoutesWithIcon(); + const routes = getRoutesWithIcon() return ( - {"Clash\nNyanpasu"} + {'Clash\nNyanpasu'}
)}
@@ -58,11 +58,11 @@ export const DrawerContent = ({ icon={icon} onlyIcon={onlyIcon} /> - ); + ) })} - ); -}; + ) +} -export default DrawerContent; +export default DrawerContent diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/locales-provider.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/locales-provider.tsx index 2ed6d52dd7..d4f7faacb8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/locales-provider.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/locales-provider.tsx @@ -1,22 +1,22 @@ -import { locale } from "dayjs"; -import { changeLanguage } from "i18next"; -import { useEffect } from "react"; -import { useNyanpasu } from "@nyanpasu/interface"; +import { locale } from 'dayjs' +import { changeLanguage } from 'i18next' +import { useEffect } from 'react' +import { useNyanpasu } from '@nyanpasu/interface' export const LocalesProvider = () => { - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() useEffect(() => { if (nyanpasuConfig?.language) { locale( - nyanpasuConfig?.language === "zh" ? "zh-cn" : nyanpasuConfig?.language, - ); + nyanpasuConfig?.language === 'zh' ? 'zh-cn' : nyanpasuConfig?.language, + ) - changeLanguage(nyanpasuConfig?.language); + changeLanguage(nyanpasuConfig?.language) } - }, [nyanpasuConfig?.language]); + }, [nyanpasuConfig?.language]) - return null; -}; + return null +} -export default LocalesProvider; +export default LocalesProvider diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx index e5ecbb7af4..d7fe05533b 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/modules/route-list-item.tsx @@ -1,11 +1,11 @@ -import { createElement } from "react"; -import { useTranslation } from "react-i18next"; -import { languageQuirks } from "@/utils/language"; -import { SvgIconComponent } from "@mui/icons-material"; -import { alpha, ListItemButton, ListItemIcon, useTheme } from "@mui/material"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { cn } from "@nyanpasu/ui"; -import { useMatch, useNavigate } from "@tanstack/react-router"; +import { createElement } from 'react' +import { useTranslation } from 'react-i18next' +import { languageQuirks } from '@/utils/language' +import { SvgIconComponent } from '@mui/icons-material' +import { alpha, ListItemButton, ListItemIcon, useTheme } from '@mui/material' +import { useNyanpasu } from '@nyanpasu/interface' +import { cn } from '@nyanpasu/ui' +import { useMatch, useNavigate } from '@tanstack/react-router' export const RouteListItem = ({ name, @@ -13,45 +13,45 @@ export const RouteListItem = ({ icon, onlyIcon, }: { - name: string; - path: string; - icon: SvgIconComponent; - onlyIcon?: boolean; + name: string + path: string + icon: SvgIconComponent + onlyIcon?: boolean }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() const match = useMatch({ strict: false, shouldThrow: false, from: path as never, - }); + }) - const navigate = useNavigate(); + const navigate = useNavigate() - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() return ( {!onlyIcon && (
)} - ); -}; + ) +} -export default RouteListItem; +export default RouteListItem diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-empty.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-empty.tsx index b75a01a1a2..3c3958769f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-empty.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-empty.tsx @@ -1,29 +1,29 @@ -import { InboxRounded } from "@mui/icons-material"; -import { alpha, Box, Typography } from "@mui/material"; +import { InboxRounded } from '@mui/icons-material' +import { alpha, Box, Typography } from '@mui/material' interface Props { - text?: React.ReactNode; - extra?: React.ReactNode; + text?: React.ReactNode + extra?: React.ReactNode } export const BaseEmpty = (props: Props) => { - const { text = "Empty", extra } = props; + const { text = 'Empty', extra } = props return ( ({ - width: "100%", - height: "100%", - display: "flex", - flexDirection: "column", - alignItems: "center", - justifyContent: "center", + width: '100%', + height: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', color: alpha(palette.text.secondary, 0.75), })} > - - {text} + + {text} {extra} - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-error-boundary.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-error-boundary.tsx index 2475a2ffdf..8e9053ea78 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-error-boundary.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-error-boundary.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from "react"; -import { ErrorBoundary, FallbackProps } from "react-error-boundary"; +import { ReactNode } from 'react' +import { ErrorBoundary, FallbackProps } from 'react-error-boundary' function ErrorFallback({ error }: FallbackProps) { return ( @@ -13,11 +13,11 @@ function ErrorFallback({ error }: FallbackProps) {
{error.stack}
- ); + ) } interface Props { - children?: ReactNode; + children?: ReactNode } export const BaseErrorBoundary = (props: Props) => { @@ -25,5 +25,5 @@ export const BaseErrorBoundary = (props: Props) => { {props.children} - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-notice.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-notice.tsx index d97fe0fb40..3b5f52ef8b 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-notice.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/base/base-notice.tsx @@ -1,48 +1,48 @@ -import { ReactNode, useState } from "react"; -import { createRoot } from "react-dom/client"; -import { CheckCircleRounded, Close, ErrorRounded } from "@mui/icons-material"; -import { Box, IconButton, Slide, Snackbar, Typography } from "@mui/material"; +import { ReactNode, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { CheckCircleRounded, Close, ErrorRounded } from '@mui/icons-material' +import { Box, IconButton, Slide, Snackbar, Typography } from '@mui/material' interface InnerProps { - type: string; - duration?: number; - message: ReactNode; - onClose: () => void; + type: string + duration?: number + message: ReactNode + onClose: () => void } const NoticeInner = (props: InnerProps) => { - const { type, message, duration = 1500, onClose } = props; - const [visible, setVisible] = useState(true); + const { type, message, duration = 1500, onClose } = props + const [visible, setVisible] = useState(true) const onBtnClose = () => { - setVisible(false); - onClose(); - }; + setVisible(false) + onClose() + } const onAutoClose = (_e: any, reason: string) => { - if (reason !== "clickaway") onBtnClose(); - }; + if (reason !== 'clickaway') onBtnClose() + } const msgElement = - type === "info" ? ( + type === 'info' ? ( message ) : ( - - {type === "error" && } - {type === "success" && } + + {type === 'error' && } + {type === 'success' && } {message} - ); + ) return ( { } /> - ); -}; - -interface NoticeInstance { - (props: Omit): void; - - info(message: ReactNode, duration?: number): void; - error(message: ReactNode, duration?: number): void; - success(message: ReactNode, duration?: number): void; + ) } -let parent: HTMLDivElement = null!; +interface NoticeInstance { + (props: Omit): void + + info(message: ReactNode, duration?: number): void + error(message: ReactNode, duration?: number): void + success(message: ReactNode, duration?: number): void +} + +let parent: HTMLDivElement = null! // @ts-expect-error 90 行动态添加了 info、error、success 属性 export const Notice: NoticeInstance = (props) => { if (!parent) { - parent = document.createElement("div"); - document.body.appendChild(parent); + parent = document.createElement('div') + document.body.appendChild(parent) } - const container = document.createElement("div"); - parent.appendChild(container); - const root = createRoot(container); + const container = document.createElement('div') + parent.appendChild(container) + const root = createRoot(container) const onUnmount = () => { - root.unmount(); - if (parent) setTimeout(() => parent.removeChild(container), 500); - }; + root.unmount() + if (parent) setTimeout(() => parent.removeChild(container), 500) + } - root.render(); -}; - -(["info", "error", "success"] as const).forEach((type) => { + root.render() +} +;(['info', 'error', 'success'] as const).forEach((type) => { Notice[type] = (message, duration) => { - setTimeout(() => Notice({ type, message, duration }), 0); - }; -}); + setTimeout(() => Notice({ type, message, duration }), 0) + } +}) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/base/content-display.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/base/content-display.tsx index 858383fd80..049a77cca3 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/base/content-display.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/base/content-display.tsx @@ -1,11 +1,11 @@ -import { ReactNode } from "react"; -import { Public } from "@mui/icons-material"; -import { cn } from "@nyanpasu/ui"; +import { ReactNode } from 'react' +import { Public } from '@mui/icons-material' +import { cn } from '@nyanpasu/ui' export interface ContentDisplayProps { - className?: string; - message?: string; - children?: ReactNode; + className?: string + message?: string + children?: ReactNode } export const ContentDisplay = ({ @@ -14,12 +14,10 @@ export const ContentDisplay = ({ className, }: ContentDisplayProps) => (
- {children ? ( - children - ) : ( + {children || ( <> @@ -28,6 +26,6 @@ export const ContentDisplay = ({ )}
-); +) -export default ContentDisplay; +export default ContentDisplay diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/base/index.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/base/index.ts index 4ab003dee8..c51736bb13 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/base/index.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/base/index.ts @@ -1,3 +1,3 @@ -export { BaseEmpty } from "./base-empty"; -export { BaseErrorBoundary } from "./base-error-boundary"; -export { Notice } from "./base-notice"; +export { BaseEmpty } from './base-empty' +export { BaseErrorBoundary } from './base-error-boundary' +export { Notice } from './base-notice' diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/close-connections-button.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/close-connections-button.tsx index 907c1f4592..c1436d6553 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/close-connections-button.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/close-connections-button.tsx @@ -1,26 +1,26 @@ -import { useLockFn } from "ahooks"; -import { useTranslation } from "react-i18next"; -import { Close } from "@mui/icons-material"; -import { Tooltip } from "@mui/material"; -import { useClash } from "@nyanpasu/interface"; -import { FloatingButton } from "@nyanpasu/ui"; +import { useLockFn } from 'ahooks' +import { useTranslation } from 'react-i18next' +import { Close } from '@mui/icons-material' +import { Tooltip } from '@mui/material' +import { useClash } from '@nyanpasu/interface' +import { FloatingButton } from '@nyanpasu/ui' export const CloseConnectionsButton = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { deleteConnections } = useClash(); + const { deleteConnections } = useClash() const onCloseAll = useLockFn(async () => { - await deleteConnections(); - }); + await deleteConnections() + }) return ( - + - ); -}; + ) +} -export default CloseConnectionsButton; +export default CloseConnectionsButton diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-detail-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-detail-dialog.tsx index 7387d6a3c6..9538c9f1b3 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-detail-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-detail-dialog.tsx @@ -1,89 +1,89 @@ -import { sentenceCase } from "change-case"; -import dayjs from "dayjs"; -import { filesize } from "filesize"; -import * as React from "react"; -import { useTranslation } from "react-i18next"; -import { Tooltip } from "@mui/material"; -import { Connection } from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps, cn } from "@nyanpasu/ui"; +import { sentenceCase } from 'change-case' +import dayjs from 'dayjs' +import { filesize } from 'filesize' +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { Tooltip } from '@mui/material' +import { Connection } from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps, cn } from '@nyanpasu/ui' export type ConnectionDetailDialogProps = { item?: Connection.Item } & Omit< BaseDialogProps, - "title" ->; + 'title' +> // eslint-disable-next-line @typescript-eslint/no-explicit-any const formatValue = (key: string, value: any): React.ReactElement => { if (Array.isArray(value)) { - return {value.join(" / ")}; + return {value.join(' / ')} } - key = key.toLowerCase(); - if (key.includes("speed")) { - return {filesize(value)}/s; + key = key.toLowerCase() + if (key.includes('speed')) { + return {filesize(value)}/s } - if (key.includes("download") || key.includes("upload")) { - return {filesize(value)}; + if (key.includes('download') || key.includes('upload')) { + return {filesize(value)} } - if (key.includes("port") || key.includes("id") || key.includes("ip")) { - return {value}; + if (key.includes('port') || key.includes('id') || key.includes('ip')) { + return {value} } - const date = dayjs(value); + const date = dayjs(value) if (date.isValid()) { return ( - + {date.fromNow()} - ); + ) } - return value; -}; + return value +} // eslint-disable-next-line @typescript-eslint/no-explicit-any const Row = ({ label, value }: { label: string; value: any }) => { - const key = label.toLowerCase(); + const key = label.toLowerCase() return ( <>
{sentenceCase(label)}
{formatValue(key, value)}
- ); -}; + ) +} export default function ConnectionDetailDialog({ item, ...others }: ConnectionDetailDialogProps) { - const { t } = useTranslation(); - if (!item) return null; + const { t } = useTranslation() + if (!item) return null return ( - +
{Object.entries(item) - .filter(([key, value]) => key !== "metadata" && !!value) + .filter(([key, value]) => key !== 'metadata' && !!value) .map(([key, value]) => ( ))}

- {t("Metadata")} + {t('Metadata')}

{Object.entries(item.metadata) @@ -93,5 +93,5 @@ export default function ConnectionDetailDialog({ ))}
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-page.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-page.tsx index 6155fcdf5d..721e70d538 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-page.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-page.tsx @@ -1,14 +1,14 @@ -import { use } from "react"; -import CloseConnectionsButton from "./close-connections-button"; -import { SearchTermCtx } from "./connection-search-term"; -import ConnectionsTable from "./connections-table"; +import { use } from 'react' +import CloseConnectionsButton from './close-connections-button' +import { SearchTermCtx } from './connection-search-term' +import ConnectionsTable from './connections-table' export default function ConnectionPage() { - const searchTerm = use(SearchTermCtx); + const searchTerm = use(SearchTermCtx) return ( <> - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-search-term.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-search-term.tsx index 41e300862c..b8fa9910c1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-search-term.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connection-search-term.tsx @@ -1,3 +1,3 @@ -import { createContext } from "react"; +import { createContext } from 'react' -export const SearchTermCtx = createContext(undefined); +export const SearchTermCtx = createContext(undefined) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-column-filter.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-column-filter.tsx index dfbe76cb47..d8c9376416 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-column-filter.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-column-filter.tsx @@ -1,35 +1,36 @@ -import { useLockFn } from "ahooks"; -import { snakeCase } from "change-case"; -import dayjs from "dayjs"; -import { AnimatePresence, Reorder, useDragControls } from "framer-motion"; -import { useAtom } from "jotai"; -import { type MRT_ColumnDef } from "material-react-table"; -import { MouseEventHandler, useCallback, useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { connectionTableColumnsAtom } from "@/store"; -import parseTraffic from "@/utils/parse-traffic"; -import { Cancel, Menu } from "@mui/icons-material"; -import { Checkbox, CircularProgress, IconButton } from "@mui/material"; -import { useClash } from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps } from "@nyanpasu/ui"; -import { TableConnection } from "./connections-table"; +/* eslint-disable camelcase */ +import { useLockFn } from 'ahooks' +import { snakeCase } from 'change-case' +import dayjs from 'dayjs' +import { AnimatePresence, Reorder, useDragControls } from 'framer-motion' +import { useAtom } from 'jotai' +import { type MRT_ColumnDef } from 'material-react-table' +import { MouseEventHandler, useCallback, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { connectionTableColumnsAtom } from '@/store' +import parseTraffic from '@/utils/parse-traffic' +import { Cancel, Menu } from '@mui/icons-material' +import { Checkbox, CircularProgress, IconButton } from '@mui/material' +import { useClash } from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps } from '@nyanpasu/ui' +import { TableConnection } from './connections-table' function CloseConnectionButton({ id }: { id: string }) { - const { deleteConnections } = useClash(); + const { deleteConnections } = useClash() const closeConnect = useLockFn(async (id?: string) => { - await deleteConnections(id); - }); - const [loading, setLoading] = useState(false); + await deleteConnections(id) + }) + const [loading, setLoading] = useState(false) const onClick: MouseEventHandler = useCallback( (e) => { - e.preventDefault(); - e.stopPropagation(); - setLoading(true); - closeConnect(id).finally(() => setLoading(false)); + e.preventDefault() + e.stopPropagation() + setLoading(true) + closeConnect(id).finally(() => setLoading(false)) }, [closeConnect, id], - ); + ) return (
@@ -42,18 +43,18 @@ function CloseConnectionButton({ id }: { id: string }) { {loading ? : }
- ); + ) } export const useColumns = (): Array> => { - const { t } = useTranslation(); + const { t } = useTranslation() return useMemo( () => ( [ { - header: "Actions", + header: 'Actions', size: 60, enableSorting: false, enableGlobalFilter: false, @@ -61,86 +62,86 @@ export const useColumns = (): Array> => { accessorFn: ({ id }) => , }, { - header: "Host", + header: 'Host', size: 240, accessorFn: ({ metadata }) => metadata.host || metadata.destinationIP, }, { - header: "Process", + header: 'Process', size: 140, accessorFn: ({ metadata }) => metadata.process, }, { - header: "Downloaded", + header: 'Downloaded', size: 88, - accessorFn: ({ download }) => parseTraffic(download).join(" "), + accessorFn: ({ download }) => parseTraffic(download).join(' '), sortingFn: (rowA, rowB) => rowA.original.download - rowB.original.download, }, { - header: "Uploaded", + header: 'Uploaded', size: 88, - accessorFn: ({ upload }) => parseTraffic(upload).join(" "), + accessorFn: ({ upload }) => parseTraffic(upload).join(' '), sortingFn: (rowA, rowB) => rowA.original.upload - rowB.original.upload, }, { - header: "DL Speed", + header: 'DL Speed', size: 88, accessorFn: ({ downloadSpeed }) => - parseTraffic(downloadSpeed).join(" ") + "/s", + parseTraffic(downloadSpeed).join(' ') + '/s', sortingFn: (rowA, rowB) => (rowA.original.downloadSpeed || 0) - (rowB.original.downloadSpeed || 0), }, { - header: "UL Speed", + header: 'UL Speed', size: 88, accessorFn: ({ uploadSpeed }) => - parseTraffic(uploadSpeed).join(" ") + "/s", + parseTraffic(uploadSpeed).join(' ') + '/s', sortingFn: (rowA, rowB) => (rowA.original.uploadSpeed || 0) - (rowB.original.uploadSpeed || 0), }, { - header: "Chains", + header: 'Chains', size: 360, - accessorFn: ({ chains }) => [...chains].reverse().join(" / "), + accessorFn: ({ chains }) => [...chains].reverse().join(' / '), }, { - header: "Rule", + header: 'Rule', size: 200, accessorFn: ({ rule, rulePayload }) => rulePayload ? `${rule} (${rulePayload})` : rule, }, { - header: "Time", + header: 'Time', size: 120, accessorFn: ({ start }) => dayjs(start).fromNow(), sortingFn: (rowA, rowB) => dayjs(rowA.original.start).diff(rowB.original.start), }, { - header: "Source", + header: 'Source', size: 200, accessorFn: ({ metadata: { sourceIP, sourcePort } }) => `${sourceIP}:${sourcePort}`, }, { - header: "Destination IP", + header: 'Destination IP', size: 200, accessorFn: ({ metadata: { destinationIP, destinationPort } }) => `${destinationIP}:${destinationPort}`, }, { - header: "Destination ASN", + header: 'Destination ASN', size: 200, accessorFn: ({ metadata: { destinationIPASN } }) => `${destinationIPASN}`, }, { - header: "Type", + header: 'Type', size: 160, accessorFn: ({ metadata }) => `${metadata.type} (${metadata.network})`, @@ -155,13 +156,13 @@ export const useColumns = (): Array> => { }) satisfies MRT_ColumnDef, ), [t], - ); -}; + ) +} export type ConnectionColumnFilterDialogProps = {} & Omit< BaseDialogProps, - "title" ->; + 'title' +> function ColItem({ column, @@ -169,12 +170,12 @@ function ColItem({ onChange, value, }: { - column: MRT_ColumnDef; - checked: boolean; - onChange: (e: React.ChangeEvent) => void; - value: [string, boolean]; + column: MRT_ColumnDef + checked: boolean + onChange: (e: React.ChangeEvent) => void + value: [string, boolean] }) { - const controls = useDragControls(); + const controls = useDragControls() return ( - ); + ) } export default function ConnectionColumnFilterDialog( props: ConnectionColumnFilterDialogProps, ) { - const { t } = useTranslation(); - const columns = useColumns(); - const [filteredCols, setFilteredCols] = useAtom(connectionTableColumnsAtom); + const { t } = useTranslation() + const columns = useColumns() + const [filteredCols, setFilteredCols] = useAtom(connectionTableColumnsAtom) const sortedCols = useMemo( () => columns - .filter((o) => o.id !== "actions") + .filter((o) => o.id !== 'actions') .sort((a, b) => { - const aIndex = filteredCols.findIndex((o) => o[0] === a.id); - const bIndex = filteredCols.findIndex((o) => o[0] === b.id); + const aIndex = filteredCols.findIndex((o) => o[0] === a.id) + const bIndex = filteredCols.findIndex((o) => o[0] === b.id) if (aIndex === -1 && bIndex === -1) { - return 0; + return 0 } if (aIndex === -1) { - return 1; + return 1 } if (bIndex === -1) { - return -1; + return -1 } - return aIndex - bIndex; + return aIndex - bIndex }), [columns, filteredCols], - ); + ) const latestFilteredCols = sortedCols.map((column) => [ column.id, filteredCols.find((o) => o[0] === column.id)?.[1] ?? true, - ]) as Array<[string, boolean]>; + ]) as Array<[string, boolean]> return ( - +
o[0] === column.id)?.[1] ?? true } onChange={(e) => { - console.log(e.target.checked); - const newCols = [...filteredCols]; - newCols[index] = [newCols[index][0], e.target.checked]; - console.log(newCols); - setFilteredCols(newCols); + console.log(e.target.checked) + const newCols = [...filteredCols] + newCols[index] = [newCols[index][0], e.target.checked] + console.log(newCols) + setFilteredCols(newCols) }} value={latestFilteredCols[index]} /> @@ -256,5 +257,5 @@ export default function ConnectionColumnFilterDialog(
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-table.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-table.tsx index 04240dd4f4..4236cc72df 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-table.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-table.tsx @@ -1,93 +1,91 @@ -import { useAtomValue } from "jotai"; -import { cloneDeep } from "lodash-es"; -import { - MaterialReactTable, - useMaterialReactTable, -} from "material-react-table"; -import { MRT_Localization_EN } from "material-react-table/locales/en"; -import { MRT_Localization_RU } from "material-react-table/locales/ru"; -import { MRT_Localization_ZH_HANS } from "material-react-table/locales/zh-Hans"; -import { lazy, useDeferredValue, useMemo, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { connectionTableColumnsAtom } from "@/store"; -import { containsSearchTerm } from "@/utils"; -import { Connection, useClashWS } from "@nyanpasu/interface"; -import ContentDisplay from "../base/content-display"; -import { useColumns } from "./connections-column-filter"; +/* eslint-disable camelcase */ +import { useAtomValue } from 'jotai' +import { cloneDeep } from 'lodash-es' +import { MaterialReactTable, useMaterialReactTable } from 'material-react-table' +import { MRT_Localization_EN } from 'material-react-table/locales/en' +import { MRT_Localization_RU } from 'material-react-table/locales/ru' +import { MRT_Localization_ZH_HANS } from 'material-react-table/locales/zh-Hans' +import { lazy, useDeferredValue, useMemo, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { connectionTableColumnsAtom } from '@/store' +import { containsSearchTerm } from '@/utils' +import { Connection, useClashWS } from '@nyanpasu/interface' +import ContentDisplay from '../base/content-display' +import { useColumns } from './connections-column-filter' -const ConnectionDetailDialog = lazy(() => import("./connection-detail-dialog")); +const ConnectionDetailDialog = lazy(() => import('./connection-detail-dialog')) export type TableConnection = Connection.Item & { - downloadSpeed?: number; - uploadSpeed?: number; -}; + downloadSpeed?: number + uploadSpeed?: number +} -export interface TableMessage extends Omit { - connections: TableConnection[]; +export interface TableMessage extends Omit { + connections: TableConnection[] } export const ConnectionsTable = ({ searchTerm }: { searchTerm?: string }) => { - const { t, i18n } = useTranslation(); + const { t, i18n } = useTranslation() const { connections: { latestMessage }, - } = useClashWS(); + } = useClashWS() - const historyMessage = useRef(null); + const historyMessage = useRef(null) const connectionsMessage = useMemo(() => { - if (!latestMessage?.data) return; - const result = JSON.parse(latestMessage.data) as Connection.Response; - const updatedConnections: TableConnection[] = []; + if (!latestMessage?.data) return + const result = JSON.parse(latestMessage.data) as Connection.Response + const updatedConnections: TableConnection[] = [] const filteredConnections = searchTerm ? result.connections?.filter((connection) => containsSearchTerm(connection, searchTerm), ) - : result.connections; + : result.connections filteredConnections?.forEach((connection) => { const previousConnection = historyMessage.current?.connections.find( (history) => history.id === connection.id, - ); + ) const downloadSpeed = previousConnection ? connection.download - previousConnection.download - : 0; + : 0 const uploadSpeed = previousConnection ? connection.upload - previousConnection.upload - : 0; + : 0 updatedConnections.push({ ...connection, downloadSpeed, uploadSpeed, - }); - }); + }) + }) - const data = { ...result, connections: updatedConnections }; + const data = { ...result, connections: updatedConnections } - historyMessage.current = data; + historyMessage.current = data - return data; - }, [latestMessage?.data, searchTerm]); - const deferredTableData = useDeferredValue(connectionsMessage?.connections); + return data + }, [latestMessage?.data, searchTerm]) + const deferredTableData = useDeferredValue(connectionsMessage?.connections) const locale = useMemo(() => { switch (i18n.language) { - case "zh": - return MRT_Localization_ZH_HANS; - case "ru": - return MRT_Localization_RU; - case "en": + case 'zh': + return MRT_Localization_ZH_HANS + case 'ru': + return MRT_Localization_RU + case 'en': default: - return MRT_Localization_EN; + return MRT_Localization_EN } - }, [i18n.language]); + }, [i18n.language]) - const columns = useColumns(); - const tableColsOrder = useAtomValue(connectionTableColumnsAtom); + const columns = useColumns() + const tableColsOrder = useAtomValue(connectionTableColumnsAtom) const filteredColumns = useMemo( () => columns @@ -96,50 +94,50 @@ export const ConnectionsTable = ({ searchTerm }: { searchTerm?: string }) => { tableColsOrder.find((o) => o[0] === column.id)?.[1] ?? true, ) .sort((a, b) => { - const aIndex = tableColsOrder.findIndex((o) => o[0] === a.id); - const bIndex = tableColsOrder.findIndex((o) => o[0] === b.id); + const aIndex = tableColsOrder.findIndex((o) => o[0] === a.id) + const bIndex = tableColsOrder.findIndex((o) => o[0] === b.id) if (aIndex === -1 && bIndex === -1) { - return 0; + return 0 } if (aIndex === -1) { - return 1; + return 1 } if (bIndex === -1) { - return -1; + return -1 } - return aIndex - bIndex; + return aIndex - bIndex }), [columns, tableColsOrder], - ); + ) const columnOrder = useMemo( () => filteredColumns.map((column) => column.id) as string[], [filteredColumns], - ); + ) const columnVisibility = useMemo(() => { return filteredColumns.reduce( (acc, column) => { acc[column.id as string] = - tableColsOrder.find((o) => o[0] === column.id)?.[1] ?? true; - return acc; + tableColsOrder.find((o) => o[0] === column.id)?.[1] ?? true + return acc }, {} as Record, - ); - }, [filteredColumns, tableColsOrder]); + ) + }, [filteredColumns, tableColsOrder]) const [connectionDetailDialogOpen, setConnectionDetailDialogOpen] = - useState(false); + useState(false) const [connectioNDetailDialogItem, setConnectionDetailDialogItem] = useState< Connection.Item | undefined - >(undefined); + >(undefined) const table = useMaterialReactTable({ columns: filteredColumns, data: deferredTableData ?? [], initialState: { - density: "compact", + density: 'compact', columnPinning: { - left: ["actions"], + left: ['actions'], }, }, state: { @@ -157,27 +155,27 @@ export const ConnectionsTable = ({ searchTerm }: { searchTerm?: string }) => { enableGlobalFilterModes: true, enableColumnPinning: true, muiTableContainerProps: { - sx: { minHeight: "100%" }, - className: "!absolute !h-full !w-full", + sx: { minHeight: '100%' }, + className: '!absolute !h-full !w-full', }, muiTableBodyRowProps({ row }) { return { onClick() { - const id = row.original.id; - const item = connectionsMessage?.connections.find((o) => o.id === id); + const id = row.original.id + const item = connectionsMessage?.connections.find((o) => o.id === id) if (item) { - setConnectionDetailDialogItem(cloneDeep(item)); - setConnectionDetailDialogOpen(true); + setConnectionDetailDialogItem(cloneDeep(item)) + setConnectionDetailDialogOpen(true) } }, - }; + } }, localization: locale, enableRowVirtualization: true, enableColumnVirtualization: true, rowVirtualizerOptions: { overscan: 5 }, columnVirtualizerOptions: { overscan: 2 }, - }); + }) return connectionsMessage?.connections.length ? ( <> @@ -191,9 +189,9 @@ export const ConnectionsTable = ({ searchTerm }: { searchTerm?: string }) => { ) : ( - ); -}; + ) +} -export default ConnectionsTable; +export default ConnectionsTable diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-total.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-total.tsx index 30b417cd5f..b74b03f00c 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-total.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/connections-total.tsx @@ -1,50 +1,50 @@ -import { filesize } from "filesize"; -import { useEffect, useMemo, useRef, useState } from "react"; -import { Download, Upload } from "@mui/icons-material"; -import { darken, lighten, Paper } from "@mui/material"; -import { Connection, useClashWS } from "@nyanpasu/interface"; +import { filesize } from 'filesize' +import { useEffect, useMemo, useRef, useState } from 'react' +import { Download, Upload } from '@mui/icons-material' +import { darken, lighten, Paper } from '@mui/material' +import { Connection, useClashWS } from '@nyanpasu/interface' export default function ConnectionTotal() { const { connections: { latestMessage }, - } = useClashWS(); - const [downloadHighlight, setDownloadHighlight] = useState(false); - const [uploadHighlight, setUploadHighlight] = useState(false); + } = useClashWS() + const [downloadHighlight, setDownloadHighlight] = useState(false) + const [uploadHighlight, setUploadHighlight] = useState(false) - const downloadHighlightTimerRef = useRef(null); - const uploadHighlightTimerRef = useRef(null); + const downloadHighlightTimerRef = useRef(null) + const uploadHighlightTimerRef = useRef(null) const result = useMemo(() => { - if (!latestMessage?.data) return null; - return JSON.parse(latestMessage.data) as Connection.Response; - }, [latestMessage]); + if (!latestMessage?.data) return null + return JSON.parse(latestMessage.data) as Connection.Response + }, [latestMessage]) useEffect(() => { if (result?.downloadTotal && result?.downloadTotal > 0) { - setDownloadHighlight(true); + setDownloadHighlight(true) if (downloadHighlightTimerRef.current) { - clearTimeout(downloadHighlightTimerRef.current); + clearTimeout(downloadHighlightTimerRef.current) } downloadHighlightTimerRef.current = window.setTimeout(() => { - setDownloadHighlight(false); - }, 300); + setDownloadHighlight(false) + }, 300) } - }, [result?.downloadTotal]); + }, [result?.downloadTotal]) useEffect(() => { if (result?.uploadTotal && result?.uploadTotal > 0) { - setUploadHighlight(true); + setUploadHighlight(true) if (uploadHighlightTimerRef.current) { - clearTimeout(uploadHighlightTimerRef.current); + clearTimeout(uploadHighlightTimerRef.current) } uploadHighlightTimerRef.current = window.setTimeout(() => { - setUploadHighlight(false); - }, 300); + setUploadHighlight(false) + }, 300) } - }, [result?.uploadTotal]); + }, [result?.uploadTotal]) if (!result) { - return null; + return null } return ( @@ -61,7 +61,7 @@ export default function ConnectionTotal() { theme.palette.primary.main, downloadHighlight ? 0.9 : 0.3, ), - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { color: lighten( theme.palette.primary.main, downloadHighlight ? 0.2 : 0.9, @@ -69,7 +69,7 @@ export default function ConnectionTotal() { }), }), ]} - />{" "} + />{' '} {filesize(result.downloadTotal, { pad: true })} @@ -86,7 +86,7 @@ export default function ConnectionTotal() { theme.palette.primary.main, uploadHighlight ? 0.9 : 0.3, ), - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { color: lighten( theme.palette.primary.main, downloadHighlight ? 0.2 : 0.9, @@ -94,11 +94,11 @@ export default function ConnectionTotal() { }), }), ]} - />{" "} + />{' '} {filesize(result.uploadTotal, { pad: true })}
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/header-search.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/header-search.tsx index 59fd35c887..e5009e2b83 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/connections/header-search.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/connections/header-search.tsx @@ -1,45 +1,45 @@ -import { useTranslation } from "react-i18next"; +import { useTranslation } from 'react-i18next' import { alpha, FilledInputProps, TextField, TextFieldProps, useTheme, -} from "@mui/material"; +} from '@mui/material' export const HeaderSearch = (props: TextFieldProps) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() const inputProps: Partial = { sx: { borderRadius: 7, backgroundColor: alpha(palette.primary.main, 0.1), - "&::before": { - display: "none", + '&::before': { + display: 'none', }, - "&::after": { - display: "none", + '&::after': { + display: 'none', }, }, - }; + } return ( - ); -}; + ) +} -export default HeaderSearch; +export default HeaderSearch diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx index 43b8e5ba1d..ba1447fe3f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/data-panel.tsx @@ -1,40 +1,40 @@ -import { useInterval } from "ahooks"; -import { useAtomValue } from "jotai"; -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import Dataline, { DatalineProps } from "@/components/dashboard/dataline"; -import { atomIsDrawer } from "@/store"; +import { useInterval } from 'ahooks' +import { useAtomValue } from 'jotai' +import { useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Dataline, { DatalineProps } from '@/components/dashboard/dataline' +import { atomIsDrawer } from '@/store' import { ArrowDownward, ArrowUpward, MemoryOutlined, SettingsEthernet, -} from "@mui/icons-material"; -import Grid from "@mui/material/Grid2"; +} from '@mui/icons-material' +import Grid from '@mui/material/Grid2' import { Connection, Memory, Traffic, useClashWS, useNyanpasu, -} from "@nyanpasu/interface"; +} from '@nyanpasu/interface' export const DataPanel = () => { - const { t } = useTranslation(); + const { t } = useTranslation() const [traffic, setTraffice] = useState( new Array(20).fill({ up: 0, down: 0 }), - ); + ) const [memory, setMemory] = useState( new Array(20).fill({ inuse: 0 }), - ); + ) const [connection, setConnection] = useState< { - downloadTotal: number; - uploadTotal: number; - connections: number; + downloadTotal: number + uploadTotal: number + connections: number }[] >( new Array(20).fill({ @@ -42,33 +42,33 @@ export const DataPanel = () => { uploadTotal: 0, connections: 0, }), - ); + ) const { traffic: { latestMessage: latestTraffic }, memory: { latestMessage: latestMemory }, connections: { latestMessage: latestConnections }, - } = useClashWS(); + } = useClashWS() useInterval(() => { const trafficData = latestTraffic?.data ? (JSON.parse(latestTraffic.data) as Traffic) - : { up: 0, down: 0 }; + : { up: 0, down: 0 } - setTraffice((prevData) => [...prevData.slice(1), trafficData]); + setTraffice((prevData) => [...prevData.slice(1), trafficData]) const meomryData = latestMemory?.data ? (JSON.parse(latestMemory.data) as Memory) - : { inuse: 0, oslimit: 0 }; + : { inuse: 0, oslimit: 0 } - setMemory((prevData) => [...prevData.slice(1), meomryData]); + setMemory((prevData) => [...prevData.slice(1), meomryData]) const connectionsData = latestConnections?.data ? (JSON.parse(latestConnections.data) as Connection.Response) : { downloadTotal: 0, uploadTotal: 0, - }; + } setConnection((prevData) => [ ...prevData.slice(1), @@ -77,47 +77,47 @@ export const DataPanel = () => { uploadTotal: connectionsData.uploadTotal, connections: connectionsData.connections?.length ?? 0, }, - ]); - }, 1000); + ]) + }, 1000) - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() const supportMemory = nyanpasuConfig?.clash_core && - ["mihomo", "mihomo-alpha"].includes(nyanpasuConfig?.clash_core); + ['mihomo', 'mihomo-alpha'].includes(nyanpasuConfig?.clash_core) const Datalines: DatalineProps[] = [ { data: traffic.map((item) => item.up), icon: ArrowUpward, - title: t("Upload Traffic"), + title: t('Upload Traffic'), total: connection.at(-1)?.uploadTotal, - type: "speed", + type: 'speed', }, { data: traffic.map((item) => item.down), icon: ArrowDownward, - title: t("Download Traffic"), + title: t('Download Traffic'), total: connection.at(-1)?.downloadTotal, - type: "speed", + type: 'speed', }, { data: connection.map((item) => item.connections), icon: SettingsEthernet, - title: t("Active Connections"), - type: "raw", + title: t('Active Connections'), + type: 'raw', }, - ]; + ] if (supportMemory) { Datalines.splice(2, 0, { data: memory.map((item) => item.inuse), icon: MemoryOutlined, - title: t("Memory"), - }); + title: t('Memory'), + }) } - const isDrawer = useAtomValue(atomIsDrawer); + const isDrawer = useAtomValue(atomIsDrawer) const gridLayout = useMemo( () => ({ @@ -127,15 +127,15 @@ export const DataPanel = () => { xl: supportMemory ? 3 : 4, }), [isDrawer, supportMemory], - ); + ) return Datalines.map((props, index) => { return ( - ); - }); -}; + ) + }) +} -export default DataPanel; +export default DataPanel diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx index ac68ec1a94..ea16f3f827 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/dataline.tsx @@ -1,17 +1,17 @@ -import { cloneElement, FC } from "react"; -import { useTranslation } from "react-i18next"; -import parseTraffic from "@/utils/parse-traffic"; -import { type SvgIconComponent } from "@mui/icons-material"; -import { Paper } from "@mui/material"; -import { cn, Sparkline } from "@nyanpasu/ui"; +import { cloneElement, FC } from 'react' +import { useTranslation } from 'react-i18next' +import parseTraffic from '@/utils/parse-traffic' +import { type SvgIconComponent } from '@mui/icons-material' +import { Paper } from '@mui/material' +import { cn, Sparkline } from '@nyanpasu/ui' export interface DatalineProps { - className?: string; - data: number[]; - icon: SvgIconComponent; - title: string; - total?: number; - type?: "speed" | "raw"; + className?: string + data: number[] + icon: SvgIconComponent + title: string + total?: number + type?: 'speed' | 'raw' } export const Dataline: FC = ({ @@ -22,10 +22,10 @@ export const Dataline: FC = ({ type, className, }) => { - const { t } = useTranslation(); + const { t } = useTranslation() return ( - +
@@ -37,20 +37,20 @@ export const Dataline: FC = ({
- {type === "raw" ? data.at(-1) : parseTraffic(data.at(-1)).join(" ")} - {type === "speed" && "/s"} + {type === 'raw' ? data.at(-1) : parseTraffic(data.at(-1)).join(' ')} + {type === 'speed' && '/s'}
{total !== undefined && ( - {t("Total")}: {parseTraffic(total).join(" ")} + {t('Total')}: {parseTraffic(total).join(' ')} )}
- ); -}; + ) +} -export default Dataline; +export default Dataline diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/health-panel.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/health-panel.tsx index 5145190a37..21170c91e5 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/health-panel.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/health-panel.tsx @@ -1,10 +1,10 @@ -import { useInterval } from "ahooks"; -import { useRef, useState } from "react"; -import { timing } from "@nyanpasu/interface"; -import IPASNPanel from "./modules/ipasn-panel"; -import TimingPanel from "./modules/timing-panel"; +import { useInterval } from 'ahooks' +import { useRef, useState } from 'react' +import { timing } from '@nyanpasu/interface' +import IPASNPanel from './modules/ipasn-panel' +import TimingPanel from './modules/timing-panel' -const REFRESH_SECONDS = 5; +const REFRESH_SECONDS = 5 export const HealthPanel = () => { const [health, setHealth] = useState({ @@ -12,29 +12,29 @@ export const HealthPanel = () => { GitHub: 0, BingCN: 0, Baidu: 0, - }); + }) const healthCache = useRef({ Google: 0, GitHub: 0, BingCN: 0, Baidu: 0, - }); + }) - const [refreshCount, setRefreshCount] = useState(0); + const [refreshCount, setRefreshCount] = useState(0) useInterval(async () => { - setHealth(healthCache.current); + setHealth(healthCache.current) - setRefreshCount(refreshCount + REFRESH_SECONDS); + setRefreshCount(refreshCount + REFRESH_SECONDS) healthCache.current = { Google: await timing.Google(), GitHub: await timing.GitHub(), BingCN: await timing.BingCN(), Baidu: await timing.Baidu(), - }; - }, 1000 * REFRESH_SECONDS); + } + }, 1000 * REFRESH_SECONDS) return ( <> @@ -42,7 +42,7 @@ export const HealthPanel = () => { - ); -}; + ) +} -export default HealthPanel; +export default HealthPanel diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/ipasn-panel.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/ipasn-panel.tsx index eac589aacb..73a01d6e43 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/ipasn-panel.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/ipasn-panel.tsx @@ -1,20 +1,20 @@ -import countryCodeEmoji from "country-code-emoji"; -import { useAtomValue } from "jotai"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { mutate } from "swr"; -import { atomIsDrawer } from "@/store"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; -import { LoadingButton } from "@mui/lab"; -import { CircularProgress, IconButton, Paper, Tooltip } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useIPSB } from "@nyanpasu/interface"; -import { cn } from "@nyanpasu/ui"; +import countryCodeEmoji from 'country-code-emoji' +import { useAtomValue } from 'jotai' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { mutate } from 'swr' +import { atomIsDrawer } from '@/store' +import { Visibility, VisibilityOff } from '@mui/icons-material' +import { LoadingButton } from '@mui/lab' +import { CircularProgress, IconButton, Paper, Tooltip } from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useIPSB } from '@nyanpasu/interface' +import { cn } from '@nyanpasu/ui' -const IP_REFRESH_SECONDS = 180; +const IP_REFRESH_SECONDS = 180 const EmojiCounty = ({ countryCode }: { countryCode: string }) => { - const emoji = countryCodeEmoji(countryCode); + const emoji = countryCodeEmoji(countryCode) return (
@@ -22,23 +22,23 @@ const EmojiCounty = ({ countryCode }: { countryCode: string }) => { {emoji}
- ); -}; + ) +} -const MAX_WIDTH = "calc(100% - 48px - 16px)"; +const MAX_WIDTH = 'calc(100% - 48px - 16px)' export const IPASNPanel = ({ refreshCount }: { refreshCount: number }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { data, mutate, isValidating, isLoading } = useIPSB(); + const { data, mutate, isValidating, isLoading } = useIPSB() const handleRefreshIP = () => { - mutate(); - }; + mutate() + } - const [showIPAddress, setShowIPAddress] = useState(false); + const [showIPAddress, setShowIPAddress] = useState(false) - const isDrawer = useAtomValue(atomIsDrawer); + const isDrawer = useAtomValue(atomIsDrawer) return ( {
{data.country}
- + { > {data.ip} @@ -102,8 +102,8 @@ export const IPASNPanel = ({ refreshCount }: { refreshCount: number }) => {
@@ -135,7 +135,7 @@ export const IPASNPanel = ({ refreshCount }: { refreshCount: number }) => { )}
- ); -}; + ) +} -export default IPASNPanel; +export default IPASNPanel diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/timing-panel.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/timing-panel.tsx index da0d4cacee..286cee9927 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/timing-panel.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/modules/timing-panel.tsx @@ -1,28 +1,28 @@ -import { useAtomValue } from "jotai"; -import { useTranslation } from "react-i18next"; -import { useColorForDelay } from "@/hooks/theme"; -import { atomIsDrawer } from "@/store"; -import { Paper } from "@mui/material"; -import Grid from "@mui/material/Grid2"; +import { useAtomValue } from 'jotai' +import { useTranslation } from 'react-i18next' +import { useColorForDelay } from '@/hooks/theme' +import { atomIsDrawer } from '@/store' +import { Paper } from '@mui/material' +import Grid from '@mui/material/Grid2' function LatencyTag({ name, value }: { name: string; value: number }) { - const { t } = useTranslation(); + const { t } = useTranslation() - const color = useColorForDelay(value); + const color = useColorForDelay(value) return (
{name}:
- {value ? `${value.toFixed(0)} ms` : t("Timeout")} + {value ? `${value.toFixed(0)} ms` : t('Timeout')}
- ); + ) } export const TimingPanel = ({ data }: { data: { [key: string]: number } }) => { - const isDrawer = useAtomValue(atomIsDrawer); + const isDrawer = useAtomValue(atomIsDrawer) return ( { - ); -}; + ) +} -export default TimingPanel; +export default TimingPanel diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/proxy-shortcuts.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/proxy-shortcuts.tsx index b8a962b6c7..a3ac1638d5 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/proxy-shortcuts.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/proxy-shortcuts.tsx @@ -1,92 +1,91 @@ -import { useLockFn } from "ahooks"; -import { useAtomValue } from "jotai"; -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { atomIsDrawer } from "@/store"; -import { message } from "@/utils/notification"; -import { NetworkPing, SettingsEthernet } from "@mui/icons-material"; -import { Chip, Paper, type ChipProps } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useClash, useNyanpasu } from "@nyanpasu/interface"; -import { PaperSwitchButton } from "../setting/modules/system-proxy"; +import { useLockFn } from 'ahooks' +import { useAtomValue } from 'jotai' +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import { atomIsDrawer } from '@/store' +import { message } from '@/utils/notification' +import { NetworkPing, SettingsEthernet } from '@mui/icons-material' +import { Chip, Paper, type ChipProps } from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useClash, useNyanpasu } from '@nyanpasu/interface' +import { PaperSwitchButton } from '../setting/modules/system-proxy' const TitleComp = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { getSystemProxy } = useNyanpasu(); + const { getSystemProxy } = useNyanpasu() const { getConfigs: { data: clashConfigs }, - } = useClash(); + } = useClash() const status = useMemo<{ - label: string; - color: ChipProps["color"]; + label: string + color: ChipProps['color'] }>(() => { - const data = getSystemProxy.data; + const data = getSystemProxy.data if (data?.enable) { - const port = Number(data.server.split(":")[1]); + const port = Number(data.server.split(':')[1]) - if (port == clashConfigs?.["mixed-port"]) { + if (port === clashConfigs?.['mixed-port']) { return { - label: t("Successful"), - color: "success", - }; + label: t('Successful'), + color: 'success', + } } else { return { - label: t("Occupied"), - color: "warning", - }; + label: t('Occupied'), + color: 'warning', + } } } else { return { - label: t("Disabled"), - color: "error", - }; + label: t('Disabled'), + color: 'error', + } } - }, [clashConfigs, getSystemProxy.data]); + }, [clashConfigs, getSystemProxy.data]) return (
-
{t("Proxy Takeover Status")}
+
{t('Proxy Takeover Status')}
- ); -}; + ) +} export const ProxyShortcuts = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const isDrawer = useAtomValue(atomIsDrawer); + const isDrawer = useAtomValue(atomIsDrawer) - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() const handleClick = useLockFn( - async (key: "enable_system_proxy" | "enable_tun_mode") => { + async (key: 'enable_system_proxy' | 'enable_tun_mode') => { try { await setNyanpasuConfig({ [key]: !nyanpasuConfig?.[key], - }); + }) } catch (e) { message(`Activation failed!`, { - title: t("Error"), - kind: "error", - }); - } finally { + title: t('Error'), + kind: 'error', + }) } }, - ); + ) return ( {
handleClick("enable_system_proxy")} + onClick={() => handleClick('enable_system_proxy')} >
-
{t("System Proxy")}
+
{t('System Proxy')}
@@ -117,19 +116,19 @@ export const ProxyShortcuts = () => {
handleClick("enable_tun_mode")} + onClick={() => handleClick('enable_tun_mode')} >
-
{t("TUN Mode")}
+
{t('TUN Mode')}
- ); -}; + ) +} -export default ProxyShortcuts; +export default ProxyShortcuts diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/service-shortcuts.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/service-shortcuts.tsx index 2ec70828af..87529f0aa0 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/service-shortcuts.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/dashboard/service-shortcuts.tsx @@ -1,84 +1,95 @@ -import dayjs from "dayjs"; -import { useAtomValue } from "jotai"; -import { isObject } from "lodash-es"; -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import useSWR from "swr"; -import { atomIsDrawer } from "@/store"; +import dayjs from 'dayjs' +import { useAtomValue } from 'jotai' +import { isObject } from 'lodash-es' +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import useSWR from 'swr' +import { atomIsDrawer } from '@/store' import { alpha, CircularProgress, Paper, Tooltip, useTheme, -} from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { getCoreStatus, useNyanpasu } from "@nyanpasu/interface"; +} from '@mui/material' +import Grid from '@mui/material/Grid2' +import { getCoreStatus, useNyanpasu } from '@nyanpasu/interface' export const ServiceShortcuts = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() - const isDrawer = useAtomValue(atomIsDrawer); + const isDrawer = useAtomValue(atomIsDrawer) const { getServiceStatus: { data: serviceStatus }, - } = useNyanpasu(); + } = useNyanpasu() - const coreStatusSWR = useSWR("/coreStatus", getCoreStatus, { + const coreStatusSWR = useSWR('/coreStatus', getCoreStatus, { refreshInterval: 2000, revalidateOnFocus: false, - }); + }) const status = useMemo(() => { switch (serviceStatus) { - case "running": { + case 'running': { return { - label: t("running"), + label: t('running'), color: alpha(palette.success[palette.mode], 0.3), - }; + } } - case "stopped": { + case 'stopped': { return { - label: t("stopped"), + label: t('stopped'), color: alpha(palette.error[palette.mode], 0.3), - }; + } } - default: - case "not_installed": { + case 'not_installed': + default: { return { - label: t("not_installed"), + label: t('not_installed'), color: - palette.mode == "light" + palette.mode === 'light' ? palette.grey[100] : palette.background.paper, - }; + } } } - }, [serviceStatus, palette]); + }, [ + serviceStatus, + t, + palette.success, + palette.mode, + palette.error, + palette.grey, + palette.background.paper, + ]) const coreStatus = useMemo(() => { - const status = coreStatusSWR.data || [{ Stopped: null }, 0, "normal"]; - if (isObject(status[0]) && status[0].hasOwnProperty("Stopped")) { - const { Stopped } = status[0]; + const status = coreStatusSWR.data || [{ Stopped: null }, 0, 'normal'] + if ( + isObject(status[0]) && + Object.prototype.hasOwnProperty.call(status[0], 'Stopped') + ) { + const { Stopped } = status[0] return { label: !!Stopped && Stopped.trim() - ? t("stopped_reason", { reason: Stopped }) - : t("stopped"), + ? t('stopped_reason', { reason: Stopped }) + : t('stopped'), color: alpha(palette.success[palette.mode], 0.3), - }; + } } return { - label: t("service_shortcuts.core_started_by", { - by: t(status[2] === "normal" ? "UI" : "service"), + label: t('service_shortcuts.core_started_by', { + by: t(status[2] === 'normal' ? 'UI' : 'service'), }), color: alpha(palette.success[palette.mode], 0.3), - }; - }, [coreStatusSWR.data, palette.mode, palette.success, t]); + } + }, [coreStatusSWR.data, palette.mode, palette.success, t]) return ( { {serviceStatus ? ( <>
- {t("service_shortcuts.title")} + {t('service_shortcuts.title')}
@@ -101,7 +112,7 @@ export const ServiceShortcuts = () => { className="flex w-full justify-center gap-[2px] rounded-2xl py-2" style={{ backgroundColor: status.color }} > -
{t("service_shortcuts.service_status")}
+
{t('service_shortcuts.service_status')}
{t(status.label)}
@@ -109,11 +120,11 @@ export const ServiceShortcuts = () => { className="flex w-full justify-center gap-[2px] rounded-2xl py-2" style={{ backgroundColor: coreStatus.color }} > -
{t("service_shortcuts.core_status")}
+
{t('service_shortcuts.core_status')}
{ )}
- ); -}; + ) +} -export default ServiceShortcuts; +export default ServiceShortcuts diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.module.scss.d.ts index 9f8f80e4ac..4f7934e5c1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.module.scss.d.ts @@ -1,4 +1,4 @@ declare const classNames: { - readonly LogoSchema: "LogoSchema"; -}; -export default classNames; + readonly LogoSchema: 'LogoSchema' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.tsx index 0591033a7c..ad77b03fee 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/animated-logo.tsx @@ -1,18 +1,18 @@ -import { AnimatePresence, motion, Variants } from "framer-motion"; -import { CSSProperties } from "react"; -import LogoSvg from "@/assets/image/logo.svg?react"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { cn } from "@nyanpasu/ui"; -import styles from "./animated-logo.module.scss"; +import { AnimatePresence, motion, Variants } from 'framer-motion' +import { CSSProperties } from 'react' +import LogoSvg from '@/assets/image/logo.svg?react' +import { useNyanpasu } from '@nyanpasu/interface' +import { cn } from '@nyanpasu/ui' +import styles from './animated-logo.module.scss' // @ts-expect-error framer-motion types is wrong -const Logo = motion.create(LogoSvg); +const Logo = motion.create(LogoSvg) const transition = { - type: "spring", + type: 'spring', stiffness: 260, damping: 20, -}; +} const motionVariants: { [name: string]: Variants } = { default: { @@ -41,33 +41,33 @@ const motionVariants: { [name: string]: Variants } = { animate: {}, exit: {}, }, -}; +} export default function AnimatedLogo({ className, style, disableMotion, }: { - className?: string; - style?: CSSProperties; - disableMotion?: boolean; + className?: string + style?: CSSProperties + disableMotion?: boolean }) { - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() - const disable = disableMotion ?? nyanpasuConfig?.lighten_animation_effects; + const disable = disableMotion ?? nyanpasuConfig?.lighten_animation_effects return ( - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/layout-control.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/layout-control.tsx index 36dda424bb..0a6c9136c5 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/layout-control.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/layout-control.tsx @@ -1,7 +1,7 @@ -import { useMemoizedFn } from "ahooks"; -import { debounce } from "lodash-es"; -import { useEffect, useRef, useState } from "react"; -import { notification, NotificationType } from "@/utils/notification"; +import { useMemoizedFn } from 'ahooks' +import { debounce } from 'lodash-es' +import { useEffect, useRef, useState } from 'react' +import { notification, NotificationType } from '@/utils/notification' import { CloseRounded, CropSquareRounded, @@ -9,78 +9,78 @@ import { HorizontalRuleRounded, PushPin, PushPinOutlined, -} from "@mui/icons-material"; -import { alpha, Button, ButtonProps, useTheme } from "@mui/material"; -import { save_window_size_state, useNyanpasu } from "@nyanpasu/interface"; -import { cn } from "@nyanpasu/ui"; -import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; -import { platform as getPlatform } from "@tauri-apps/plugin-os"; +} from '@mui/icons-material' +import { alpha, Button, ButtonProps, useTheme } from '@mui/material' +import { saveWindowSizeState, useNyanpasu } from '@nyanpasu/interface' +import { cn } from '@nyanpasu/ui' +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' +import { platform as getPlatform } from '@tauri-apps/plugin-os' -const appWindow = getCurrentWebviewWindow(); +const appWindow = getCurrentWebviewWindow() const CtrlButton = (props: ButtonProps) => { - const { palette } = useTheme(); + const { palette } = useTheme() return ( {isRemote && ( - + { - cleanDeepClickEvent(e); - menuMapping.Update(); + cleanDeepClickEvent(e) + menuMapping.Update() }} loading={globalUpdatePending || loading.update} > @@ -330,14 +330,14 @@ export const ProfileItem = memo(function ProfileItem({ )} - + - ); -}); + ) +}) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/delay-chip.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/delay-chip.tsx index e8424c42d7..dbea4d23dd 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/delay-chip.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/delay-chip.tsx @@ -1,44 +1,44 @@ -import { memo, useState } from "react"; -import { useColorForDelay } from "@/hooks/theme"; -import { Bolt } from "@mui/icons-material"; -import { CircularProgress } from "@mui/material"; -import { cn } from "@nyanpasu/ui"; -import FeatureChip from "./feature-chip"; +import { memo, useState } from 'react' +import { useColorForDelay } from '@/hooks/theme' +import { Bolt } from '@mui/icons-material' +import { CircularProgress } from '@mui/material' +import { cn } from '@nyanpasu/ui' +import FeatureChip from './feature-chip' export const DelayChip = memo(function DelayChip({ className, delay, onClick, }: { - className?: string; - delay: number; - onClick: () => Promise; + className?: string + delay: number + onClick: () => Promise }) { - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) const handleClick = async () => { try { - setLoading(true); + setLoading(true) - await onClick(); + await onClick() } finally { - setLoading(false); + setLoading(false) } - }; + } return ( {delay === -1 ? ( @@ -46,34 +46,34 @@ export const DelayChip = memo(function DelayChip({ ) : !!delay && delay < 10000 ? ( `${delay} ms` ) : ( - "timeout" + 'timeout' )} } variant="filled" onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - handleClick(); + e.preventDefault() + e.stopPropagation() + handleClick() }} /> - ); -}); + ) +}) -export default DelayChip; +export default DelayChip diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/feature-chip.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/feature-chip.tsx index 34922e6fcd..58f6c94e35 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/feature-chip.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/feature-chip.tsx @@ -1,5 +1,5 @@ -import { memo } from "react"; -import { Chip, ChipProps } from "@mui/material"; +import { memo } from 'react' +import { Chip, ChipProps } from '@mui/material' export const FeatureChip = memo(function FeatureChip(props: ChipProps) { return ( @@ -12,13 +12,13 @@ export const FeatureChip = memo(function FeatureChip(props: ChipProps) { height: 16, padding: 0, - "& .MuiChip-label": { - padding: "0 4px", + '& .MuiChip-label': { + padding: '0 4px', }, ...props.sx, }} /> - ); -}); + ) +}) -export default FeatureChip; +export default FeatureChip diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/group-list.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/group-list.tsx index bd038a006b..d62b61b04e 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/group-list.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/group-list.tsx @@ -1,9 +1,9 @@ -import { useAtom, useAtomValue } from "jotai"; -import { memo, RefObject, useDeferredValue, useMemo } from "react"; -import useSWR from "swr"; -import { Virtualizer } from "virtua"; -import { proxyGroupAtom } from "@/store"; -import { proxiesFilterAtom } from "@/store/proxies"; +import { useAtom, useAtomValue } from 'jotai' +import { memo, RefObject, useDeferredValue, useMemo } from 'react' +import useSWR from 'swr' +import { Virtualizer } from 'virtua' +import { proxyGroupAtom } from '@/store' +import { proxiesFilterAtom } from '@/store/proxies' import { alpha, ListItem, @@ -12,27 +12,27 @@ import { ListItemIcon, ListItemText, useTheme, -} from "@mui/material"; -import { getServerPort, useClashCore } from "@nyanpasu/interface"; -import { LazyImage } from "@nyanpasu/ui"; +} from '@mui/material' +import { getServerPort, useClashCore } from '@nyanpasu/interface' +import { LazyImage } from '@nyanpasu/ui' const IconRender = memo(function IconRender({ icon }: { icon: string }) { const { data: serverPort, isLoading, error, - } = useSWR("/getServerPort", getServerPort); - const src = icon.trim().startsWith(" { - if (!src.startsWith("http")) { - return src; + if (!src.startsWith('http')) { + return src } - return `http://localhost:${serverPort}/cache/icon?url=${btoa(src)}`; - }, [src, serverPort]); + return `http://localhost:${serverPort}/cache/icon?url=${btoa(src)}` + }, [src, serverPort]) if (isLoading || error) { - return null; + return null } return ( @@ -42,32 +42,32 @@ const IconRender = memo(function IconRender({ icon }: { icon: string }) { src={cachedUrl} /> - ); -}); + ) +}) export interface GroupListProps extends ListItemButtonProps { - scrollRef: RefObject; + scrollRef: RefObject } export const GroupList = ({ scrollRef, ...listItemButtonProps }: GroupListProps) => { - const { data } = useClashCore(); + const { data } = useClashCore() - const { palette } = useTheme(); + const { palette } = useTheme() - const [proxyGroup, setProxyGroup] = useAtom(proxyGroupAtom); - const proxiesFilter = useAtomValue(proxiesFilterAtom); - const deferredProxiesFilter = useDeferredValue(proxiesFilter); + const [proxyGroup, setProxyGroup] = useAtom(proxyGroupAtom) + const proxiesFilter = useAtomValue(proxiesFilterAtom) + const deferredProxiesFilter = useDeferredValue(proxiesFilter) const handleSelect = (index: number) => { - setProxyGroup({ selector: index }); - }; + setProxyGroup({ selector: index }) + } const groups = useMemo(() => { if (!data?.groups) { - return []; + return [] } return data.groups.filter((group) => { @@ -79,17 +79,17 @@ export const GroupList = ({ group.all?.some((proxy) => { return proxy.name .toLowerCase() - .includes(deferredProxiesFilter.toLowerCase()); + .includes(deferredProxiesFilter.toLowerCase()) }) || - false; - return !(group.hidden ?? false) && filterMatches; - }); - }, [data?.groups, deferredProxiesFilter]); + false + return !(group.hidden ?? false) && filterMatches + }) + }, [data?.groups, deferredProxiesFilter]) return ( {groups.map((group, index) => { - const selected = index === proxyGroup.selector; + const selected = index === proxyGroup.selector return ( @@ -116,8 +116,8 @@ export const GroupList = ({ /> - ); + ) })} - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/index.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/index.ts index 715d035169..3f47b2802b 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/index.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/index.ts @@ -1,3 +1,3 @@ -export * from "./group-list"; -export * from "./node-list"; -export * from "./delay-button"; +export * from './group-list' +export * from './node-list' +export * from './delay-button' diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.module.scss.d.ts index ae6483c4fa..7eb5f1d161 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.module.scss.d.ts @@ -1,6 +1,6 @@ declare const classNames: { - readonly Card: "Card"; - readonly NoDelay: "NoDelay"; - readonly DelayChip: "DelayChip"; -}; -export default classNames; + readonly Card: 'Card' + readonly NoDelay: 'NoDelay' + readonly DelayChip: 'DelayChip' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.tsx index 0ddeb99ab2..d60edf602f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-card.tsx @@ -1,13 +1,13 @@ -import { CSSProperties, memo, useMemo } from "react"; -import { alpha, useTheme } from "@mui/material"; -import Box from "@mui/material/Box"; -import { Clash } from "@nyanpasu/interface"; -import { cn } from "@nyanpasu/ui"; -import { PaperSwitchButton } from "../setting/modules/system-proxy"; -import DelayChip from "./delay-chip"; -import FeatureChip from "./feature-chip"; -import styles from "./node-card.module.scss"; -import { filterDelay } from "./utils"; +import { CSSProperties, memo, useMemo } from 'react' +import { alpha, useTheme } from '@mui/material' +import Box from '@mui/material/Box' +import { Clash } from '@nyanpasu/interface' +import { cn } from '@nyanpasu/ui' +import { PaperSwitchButton } from '../setting/modules/system-proxy' +import DelayChip from './delay-chip' +import FeatureChip from './feature-chip' +import styles from './node-card.module.scss' +import { filterDelay } from './utils' export const NodeCard = memo(function NodeCard({ node, @@ -17,18 +17,18 @@ export const NodeCard = memo(function NodeCard({ onClickDelay, style, }: { - node: Clash.Proxy; - now?: string; - disabled?: boolean; - onClick: () => void; - onClickDelay: () => Promise; - style?: CSSProperties; + node: Clash.Proxy + now?: string + disabled?: boolean + onClick: () => void + onClickDelay: () => Promise + style?: CSSProperties }) { - const { palette } = useTheme(); + const { palette } = useTheme() - const delay = useMemo(() => filterDelay(node.history), [node.history]); + const delay = useMemo(() => filterDelay(node.history), [node.history]) - const checked = node.name === now; + const checked = node.name === now return ( - ); -}); + ) +}) -export default NodeCard; +export default NodeCard diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx index 992fa5421d..6a4530cf19 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx @@ -1,5 +1,5 @@ -import { AnimatePresence, motion } from "framer-motion"; -import { useAtomValue } from "jotai"; +import { AnimatePresence, motion } from 'framer-motion' +import { useAtomValue } from 'jotai' import { forwardRef, RefObject, @@ -9,19 +9,19 @@ import { useImperativeHandle, useRef, useState, -} from "react"; -import { Virtualizer, VListHandle } from "virtua"; -import { proxyGroupAtom, proxyGroupSortAtom } from "@/store"; -import { proxiesFilterAtom } from "@/store/proxies"; -import { Clash, useClashCore, useNyanpasu } from "@nyanpasu/interface"; -import { cn, useBreakpointValue } from "@nyanpasu/ui"; -import NodeCard from "./node-card"; -import { nodeSortingFn } from "./utils"; +} from 'react' +import { Virtualizer, VListHandle } from 'virtua' +import { proxyGroupAtom, proxyGroupSortAtom } from '@/store' +import { proxiesFilterAtom } from '@/store/proxies' +import { Clash, useClashCore, useNyanpasu } from '@nyanpasu/interface' +import { cn, useBreakpointValue } from '@nyanpasu/ui' +import NodeCard from './node-card' +import { nodeSortingFn } from './utils' -type RenderClashProxy = Clash.Proxy & { renderLayoutKey: string }; +type RenderClashProxy = Clash.Proxy & { renderLayoutKey: string } export interface NodeListRef { - scrollToCurrent: () => void; + scrollToCurrent: () => void } export const NodeList = forwardRef(function NodeList( @@ -34,32 +34,32 @@ export const NodeList = forwardRef(function NodeList( setGlobalProxy, updateProxiesDelay, getAllProxiesProviders, - } = useClashCore(); + } = useClashCore() - const { getCurrentMode } = useNyanpasu(); + const { getCurrentMode } = useNyanpasu() - const proxyGroup = useAtomValue(proxyGroupAtom); - const proxiesFilter = useAtomValue(proxiesFilterAtom); - const deferredProxiesFilter = useDeferredValue(proxiesFilter); + const proxyGroup = useAtomValue(proxyGroupAtom) + const proxiesFilter = useAtomValue(proxiesFilterAtom) + const deferredProxiesFilter = useDeferredValue(proxiesFilter) - const proxyGroupSort = useAtomValue(proxyGroupSortAtom); + const proxyGroupSort = useAtomValue(proxyGroupSortAtom) - const [group, setGroup] = useState>>(); + const [group, setGroup] = useState>>() const sortGroup = useCallback(() => { if (!getCurrentMode.global) { if (proxyGroup.selector !== null) { - const selectedGroup = data?.groups[proxyGroup.selector]; + const selectedGroup = data?.groups[proxyGroup.selector] if (selectedGroup) { - setGroup(nodeSortingFn(selectedGroup, proxyGroupSort)); + setGroup(nodeSortingFn(selectedGroup, proxyGroupSort)) } } } else { if (data?.global) { - setGroup(nodeSortingFn(data?.global, proxyGroupSort)); + setGroup(nodeSortingFn(data?.global, proxyGroupSort)) } else { - setGroup(data?.global); + setGroup(data?.global) } } }, [ @@ -69,11 +69,11 @@ export const NodeList = forwardRef(function NodeList( getCurrentMode, proxyGroupSort, setGroup, - ]); + ]) useEffect(() => { - sortGroup(); - }, [sortGroup]); + sortGroup() + }, [sortGroup]) const column = useBreakpointValue({ xs: 1, @@ -81,88 +81,88 @@ export const NodeList = forwardRef(function NodeList( md: 2, lg: 3, xl: 4, - }); + }) - const [renderList, setRenderList] = useState([]); + const [renderList, setRenderList] = useState([]) useEffect(() => { - if (!group?.all) return; + if (!group?.all) return - const nodeNames: string[] = []; + const nodeNames: string[] = [] - let nodes = group?.all || []; + let nodes = group?.all || [] if (!!deferredProxiesFilter && deferredProxiesFilter !== group?.name) { nodes = nodes.filter((node) => node.name.toLowerCase().includes(deferredProxiesFilter.toLowerCase()), - ); + ) } const list = nodes.reduce((result, value, index) => { const getKey = () => { - const filter = nodeNames.filter((i) => i === value.name); + const filter = nodeNames.filter((i) => i === value.name) if (filter.length === 0) { - return value.name; + return value.name } else { - return `${value.name}-${filter.length}`; + return `${value.name}-${filter.length}` } - }; + } if (index % column === 0) { - result.push([]); + result.push([]) } result[Math.floor(index / column)].push({ ...value, renderLayoutKey: getKey(), - }); + }) - nodeNames.push(value.name); + nodeNames.push(value.name) - return result; - }, []); + return result + }, []) - setRenderList(list); - }, [group?.all, group?.name, column, deferredProxiesFilter]); + setRenderList(list) + }, [group?.all, group?.name, column, deferredProxiesFilter]) const handleClick = (node: string) => { if (!getCurrentMode.global) { - setGroupProxy(proxyGroup.selector as number, node); + setGroupProxy(proxyGroup.selector as number, node) } else { - setGlobalProxy(node); + setGlobalProxy(node) } - }; + } - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() - const disableMotion = nyanpasuConfig?.lighten_animation_effects; + const disableMotion = nyanpasuConfig?.lighten_animation_effects - const vListRef = useRef(null); + const vListRef = useRef(null) useImperativeHandle(ref, () => ({ scrollToCurrent: () => { const index = renderList.findIndex((node) => node.some((item) => item.name === group?.now), - ); + ) vListRef.current?.scrollToIndex(index, { - align: "center", + align: 'center', smooth: true, - }); + }) }, - })); + })) const handleClickDelay = async (name: string) => { const getGroupTestUrl = () => { if (group?.name) { - return getAllProxiesProviders.data?.[group?.name].testUrl; + return getAllProxiesProviders.data?.[group?.name].testUrl } - }; + } await updateProxiesDelay(name, { url: getGroupTestUrl(), - }); - }; + }) + } return ( @@ -171,7 +171,7 @@ export const NodeList = forwardRef(function NodeList( return (
{node.map((render) => { @@ -179,13 +179,13 @@ export const NodeList = forwardRef(function NodeList( handleClick(render.name)} onClickDelay={async () => await handleClickDelay(render.name) } /> - ); + ) return disableMotion ? (
@@ -201,12 +201,12 @@ export const NodeList = forwardRef(function NodeList( > - ); + ) })}
- ); + ) })} - ); -}); + ) +}) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/proxy-group-name.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/proxy-group-name.tsx index dcd68b2fcf..b7a554161f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/proxy-group-name.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/proxy-group-name.tsx @@ -1,15 +1,15 @@ -import { AnimatePresence, motion } from "framer-motion"; -import { memo } from "react"; -import { useNyanpasu } from "@nyanpasu/interface"; +import { AnimatePresence, motion } from 'framer-motion' +import { memo } from 'react' +import { useNyanpasu } from '@nyanpasu/interface' export const ProxyGroupName = memo(function ProxyGroupName({ name, }: { - name: string; + name: string }) { - const { nyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig } = useNyanpasu() - const disbaleMotion = nyanpasuConfig?.lighten_animation_effects; + const disbaleMotion = nyanpasuConfig?.lighten_animation_effects return disbaleMotion ? ( <>{name} @@ -22,7 +22,7 @@ export const ProxyGroupName = memo(function ProxyGroupName({ animate={{ x: 0, opacity: 1 }} exit={{ x: -100, opacity: 0 }} transition={{ - type: "spring", + type: 'spring', bounce: 0, duration: 0.5, }} @@ -30,7 +30,7 @@ export const ProxyGroupName = memo(function ProxyGroupName({ {name} - ); -}); + ) +}) -export default ProxyGroupName; +export default ProxyGroupName diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/scroll-current-node.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/scroll-current-node.tsx index 5a76e17b43..127555d73f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/scroll-current-node.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/scroll-current-node.tsx @@ -1,14 +1,14 @@ -import { useTranslation } from "react-i18next"; -import { Radar } from "@mui/icons-material"; -import { alpha, Button, Tooltip, useTheme } from "@mui/material"; +import { useTranslation } from 'react-i18next' +import { Radar } from '@mui/icons-material' +import { alpha, Button, Tooltip, useTheme } from '@mui/material' export const ScrollCurrentNode = ({ onClick }: { onClick?: () => void }) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() return ( - + - ); -}; + ) +} -export default ScrollCurrentNode; +export default ScrollCurrentNode diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/sort-selector.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/sort-selector.tsx index c373029122..284604b9b0 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/sort-selector.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/sort-selector.tsx @@ -1,30 +1,30 @@ -import { useAtom } from "jotai"; -import { memo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { proxyGroupSortAtom } from "@/store"; -import { alpha, Button, Menu, MenuItem, useTheme } from "@mui/material"; +import { useAtom } from 'jotai' +import { memo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { proxyGroupSortAtom } from '@/store' +import { alpha, Button, Menu, MenuItem, useTheme } from '@mui/material' export const SortSelector = memo(function SortSelector() { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() - const [proxyGroupSort, setProxyGroupSort] = useAtom(proxyGroupSortAtom); + const [proxyGroupSort, setProxyGroupSort] = useAtom(proxyGroupSortAtom) - type SortType = typeof proxyGroupSort; + type SortType = typeof proxyGroupSort - const [anchorEl, setAnchorEl] = useState(null); + const [anchorEl, setAnchorEl] = useState(null) const handleClick = (sort: SortType) => { - setAnchorEl(null); - setProxyGroupSort(sort); - }; + setAnchorEl(null) + setProxyGroupSort(sort) + } const tmaps: { [key: string]: string } = { - default: "Sort by default", - delay: "Sort by delay", - name: "Sort by name", - }; + default: 'Sort by default', + delay: 'Sort by delay', + name: 'Sort by name', + } return ( <> @@ -32,7 +32,7 @@ export const SortSelector = memo(function SortSelector() { size="small" className="!px-2" sx={{ - textTransform: "none", + textTransform: 'none', backgroundColor: alpha(palette.primary.main, 0.1), }} onClick={(e) => setAnchorEl(e.currentTarget)} @@ -50,11 +50,11 @@ export const SortSelector = memo(function SortSelector() { handleClick(key as SortType)}> {t(value)} - ); + ) })} - ); -}); + ) +}) -export default SortSelector; +export default SortSelector diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/utils.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/utils.ts index 46c730e811..9650ee5bce 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/utils.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/utils.ts @@ -1,54 +1,54 @@ -import type { Clash } from "@nyanpasu/interface"; +import type { Clash } from '@nyanpasu/interface' -export type History = Clash.Proxy["history"]; +export type History = Clash.Proxy['history'] export const filterDelay = (history?: History): number => { - if (!history || history.length == 0) { - return -1; + if (!history || history.length === 0) { + return -1 } else { - return history[history.length - 1].delay; + return history[history.length - 1].delay } -}; +} export enum SortType { - Default = "default", - Dealy = "delay", - Name = "name", + Default = 'default', + Dealy = 'delay', + Name = 'name', } export const nodeSortingFn = ( selectedGroup: Clash.Proxy>, type: SortType, ) => { - let sortedList = selectedGroup.all?.slice(); + let sortedList = selectedGroup.all?.slice() switch (type) { case SortType.Dealy: { sortedList = sortedList?.sort((a, b) => { - const delayA = filterDelay(a.history); - const delayB = filterDelay(b.history); + const delayA = filterDelay(a.history) + const delayB = filterDelay(b.history) - if (delayA === -1 || delayA === -2) return 1; - if (delayB === -1 || delayB === -2) return -1; + if (delayA === -1 || delayA === -2) return 1 + if (delayB === -1 || delayB === -2) return -1 - if (delayA === 0) return 1; - if (delayB === 0) return -1; + if (delayA === 0) return 1 + if (delayB === 0) return -1 - return delayA - delayB; - }); + return delayA - delayB + }) - break; + break } case SortType.Name: { - sortedList = sortedList?.sort((a, b) => a.name.localeCompare(b.name)); + sortedList = sortedList?.sort((a, b) => a.name.localeCompare(b.name)) - break; + break } } return { ...selectedGroup, all: sortedList, - }; -}; + } +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/modules/store.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/modules/store.ts index a736e8e20e..18139ae8ae 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/modules/store.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/modules/store.ts @@ -1,8 +1,8 @@ -import { atom } from "jotai"; -import { RefObject } from "react"; -import { Clash } from "@nyanpasu/interface"; +import { atom } from 'jotai' +import { RefObject } from 'react' +import { Clash } from '@nyanpasu/interface' export const atomRulePage = atom<{ - data?: Clash.Rule[]; - scrollRef?: RefObject; -}>(); + data?: Clash.Rule[] + scrollRef?: RefObject +}>() diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-item.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-item.tsx index cb3391e0b2..4f9c93ee93 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-item.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-item.tsx @@ -1,13 +1,13 @@ -import { useTheme } from "@mui/material"; -import { Clash } from "@nyanpasu/interface"; +import { useTheme } from '@mui/material' +import { Clash } from '@nyanpasu/interface' interface Props { - index: number; - value: Clash.Rule; + index: number + value: Clash.Rule } const RuleItem = ({ index, value }: Props) => { - const { palette } = useTheme(); + const { palette } = useTheme() const COLOR = [ palette.primary.main, @@ -15,26 +15,26 @@ const RuleItem = ({ index, value }: Props) => { palette.info.main, palette.warning.main, palette.success.main, - ]; + ] const parseColor = (text: string) => { const TYPE = { - reject: ["REJECT", "REJECT-DROP"], - direct: ["DIRECT"], - }; - - if (TYPE.reject.includes(text)) return palette.error.main; - - if (TYPE.direct.includes(text)) return palette.text.primary; - - let sum = 0; - - for (let i = 0; i < text.length; i++) { - sum += text.charCodeAt(i); + reject: ['REJECT', 'REJECT-DROP'], + direct: ['DIRECT'], } - return COLOR[sum % COLOR.length]; - }; + if (TYPE.reject.includes(text)) return palette.error.main + + if (TYPE.direct.includes(text)) return palette.text.primary + + let sum = 0 + + for (let i = 0; i < text.length; i++) { + sum += text.charCodeAt(i) + } + + return COLOR[sum % COLOR.length] + } return (
@@ -44,7 +44,7 @@ const RuleItem = ({ index, value }: Props) => {
- {value.payload || "-"} + {value.payload || '-'}
@@ -59,7 +59,7 @@ const RuleItem = ({ index, value }: Props) => {
- ); -}; + ) +} -export default RuleItem; +export default RuleItem diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-page.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-page.tsx index 84ac399874..848d82d340 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-page.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/rules/rule-page.tsx @@ -1,24 +1,24 @@ -import { useAtomValue } from "jotai"; -import { useTranslation } from "react-i18next"; -import { Virtualizer } from "virtua"; -import ContentDisplay from "../base/content-display"; -import { atomRulePage } from "./modules/store"; -import RuleItem from "./rule-item"; +import { useAtomValue } from 'jotai' +import { useTranslation } from 'react-i18next' +import { Virtualizer } from 'virtua' +import ContentDisplay from '../base/content-display' +import { atomRulePage } from './modules/store' +import RuleItem from './rule-item' export const RulePage = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const rule = useAtomValue(atomRulePage); + const rule = useAtomValue(atomRulePage) return rule?.data?.length ? ( {rule.data.map((item, index) => { - return ; + return })} ) : ( - - ); -}; + + ) +} -export default RulePage; +export default RulePage diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-core.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-core.tsx index ee2bb0abb2..518af6106d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-core.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-core.tsx @@ -1,93 +1,93 @@ -import { motion } from "framer-motion"; -import { isObject } from "lodash-es"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import ClashRs from "@/assets/image/core/clash-rs.png"; -import ClashMeta from "@/assets/image/core/clash.meta.png"; -import Clash from "@/assets/image/core/clash.png"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import parseTraffic from "@/utils/parse-traffic"; -import FiberManualRecord from "@mui/icons-material/FiberManualRecord"; -import Update from "@mui/icons-material/Update"; -import LoadingButton from "@mui/lab/LoadingButton"; -import ListItem from "@mui/material/ListItem"; -import ListItemButton from "@mui/material/ListItemButton"; -import { alpha, useTheme } from "@mui/material/styles"; -import Tooltip from "@mui/material/Tooltip"; +import { motion } from 'framer-motion' +import { isObject } from 'lodash-es' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import ClashRs from '@/assets/image/core/clash-rs.png' +import ClashMeta from '@/assets/image/core/clash.meta.png' +import Clash from '@/assets/image/core/clash.png' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import parseTraffic from '@/utils/parse-traffic' +import FiberManualRecord from '@mui/icons-material/FiberManualRecord' +import Update from '@mui/icons-material/Update' +import LoadingButton from '@mui/lab/LoadingButton' +import ListItem from '@mui/material/ListItem' +import ListItemButton from '@mui/material/ListItemButton' +import { alpha, useTheme } from '@mui/material/styles' +import Tooltip from '@mui/material/Tooltip' import { ClashCore, Core, InspectUpdater, inspectUpdater, useNyanpasu, -} from "@nyanpasu/interface"; -import { cleanDeepClickEvent, cn } from "@nyanpasu/ui"; +} from '@nyanpasu/interface' +import { cleanDeepClickEvent, cn } from '@nyanpasu/ui' export const getImage = (core: ClashCore) => { switch (core) { - case "mihomo": - case "mihomo-alpha": { - return ClashMeta; + case 'mihomo': + case 'mihomo-alpha': { + return ClashMeta } - case "clash-rs": - case "clash-rs-alpha": { - return ClashRs; + case 'clash-rs': + case 'clash-rs-alpha': { + return ClashRs } default: { - return Clash; + return Clash } } -}; +} const calcProgress = (data?: InspectUpdater) => { return ( (Number(data?.downloader?.downloaded) / Number(data?.downloader?.total)) * 100 - ); -}; + ) +} const CardProgress = ({ data, show, }: { - data?: InspectUpdater; - show?: boolean; + data?: InspectUpdater + show?: boolean }) => { - const { palette } = useTheme(); + const { palette } = useTheme() const parsedState = () => { if (data?.downloader?.state) { - return "waiting"; + return 'waiting' } else if (isObject(data?.downloader.state)) { - return data?.downloader.state.failed; + return data?.downloader.state.failed } else { - return data?.downloader.state; + return data?.downloader.state } - }; + } return ( {parsedState()}
- {calcProgress(data).toFixed(0)}%{""} + {calcProgress(data).toFixed(0)}%{''} ({parseTraffic(data?.downloader.speed || 0)}/s)
- ); -}; + ) +} export interface ClashCoreItemProps { - selected: boolean; - data: Core; - onClick: (core: ClashCore) => void; + selected: boolean + data: Core + onClick: (core: ClashCore) => void } /** @@ -134,84 +134,87 @@ export const ClashCoreItem = ({ data, onClick, }: ClashCoreItemProps) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() - const { updateCore, getClashCore } = useNyanpasu(); + const { updateCore, getClashCore } = useNyanpasu() - const haveNewVersion = data.latest ? data.latest !== data.version : false; + const haveNewVersion = data.latest ? data.latest !== data.version : false - const [downloadState, setDownloadState] = useState(false); + const [downloadState, setDownloadState] = useState(false) - const [updater, setUpdater] = useState(); + const [updater, setUpdater] = useState() const handleUpdateCore = async () => { try { - setDownloadState(true); + setDownloadState(true) - const updaterId = await updateCore(data.core); + const updaterId = await updateCore(data.core) await new Promise((resolve, reject) => { const interval = setInterval(async () => { - const result = await inspectUpdater(updaterId); + const result = await inspectUpdater(updaterId) - setUpdater(result); + setUpdater(result) if ( isObject(result.downloader.state) && - result.downloader.state.hasOwnProperty("failed") + Object.prototype.hasOwnProperty.call( + result.downloader.state, + 'failed', + ) ) { - reject(result.downloader.state.failed); - clearInterval(interval); + reject(result.downloader.state.failed) + clearInterval(interval) } - if (result.state === "done") { - resolve(); - clearInterval(interval); + if (result.state === 'done') { + resolve() + clearInterval(interval) } - }, 100); - }); + }, 100) + }) - getClashCore.mutate(); + getClashCore.mutate() - message(t("Successfully updated the core", { core: `${data.name}` }), { - kind: "info", - title: t("Successful"), - }); + message(t('Successfully updated the core', { core: `${data.name}` }), { + kind: 'info', + title: t('Successful'), + }) } catch (e) { - message(t("Failed to update", { error: `${formatError(e)}` }), { - kind: "error", - title: t("Error"), - }); + message(t('Failed to update', { error: `${formatError(e)}` }), { + kind: 'error', + title: t('Error'), + }) } finally { - setDownloadState(false); + setDownloadState(false) } - }; + } return ( { if (!downloadState) { - onClick(data.core); + onClick(data.core) } }} >
- +
@@ -232,14 +235,14 @@ export const ClashCoreItem = ({
{haveNewVersion && ( - + { - cleanDeepClickEvent(e); - handleUpdateCore(); + cleanDeepClickEvent(e) + handleUpdateCore() }} > @@ -249,5 +252,5 @@ export const ClashCoreItem = ({
- ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-field.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-field.tsx index 9b19945140..d5f317d9b8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-field.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-field.tsx @@ -1,26 +1,26 @@ -import { ChangeEvent, useState } from "react"; -import Marquee from "react-fast-marquee"; -import ArrowForwardIos from "@mui/icons-material/ArrowForwardIos"; -import OpenInNewRounded from "@mui/icons-material/OpenInNewRounded"; -import { alpha, useTheme } from "@mui/material"; -import Box from "@mui/material/Box"; -import ButtonBase, { ButtonBaseProps } from "@mui/material/ButtonBase"; -import Grid from "@mui/material/Grid2"; -import IconButton from "@mui/material/IconButton"; -import Paper from "@mui/material/Paper"; -import { SwitchProps } from "@mui/material/Switch"; -import Tooltip from "@mui/material/Tooltip"; -import Typography from "@mui/material/Typography"; -import { openThat } from "@nyanpasu/interface"; -import { LoadingSwitch } from "@nyanpasu/ui"; +import { ChangeEvent, useState } from 'react' +import Marquee from 'react-fast-marquee' +import ArrowForwardIos from '@mui/icons-material/ArrowForwardIos' +import OpenInNewRounded from '@mui/icons-material/OpenInNewRounded' +import { alpha, useTheme } from '@mui/material' +import Box from '@mui/material/Box' +import ButtonBase, { ButtonBaseProps } from '@mui/material/ButtonBase' +import Grid from '@mui/material/Grid2' +import IconButton from '@mui/material/IconButton' +import Paper from '@mui/material/Paper' +import { SwitchProps } from '@mui/material/Switch' +import Tooltip from '@mui/material/Tooltip' +import Typography from '@mui/material/Typography' +import { openThat } from '@nyanpasu/interface' +import { LoadingSwitch } from '@nyanpasu/ui' export interface LabelSwitchProps extends SwitchProps { - label: string; - url?: string; + label: string + url?: string onChange?: ( event: ChangeEvent, checked: boolean, - ) => Promise | void; + ) => Promise | void } /** @@ -42,9 +42,9 @@ export const LabelSwitch = ({ onChange, ...props }: LabelSwitchProps) => { - const { palette } = useTheme(); + const { palette } = useTheme() - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) const handleChange = async ( event: ChangeEvent, @@ -52,21 +52,21 @@ export const LabelSwitch = ({ ) => { if (onChange) { try { - setLoading(true); + setLoading(true) - await onChange(event, checked); + await onChange(event, checked) } finally { - setLoading(false); + setLoading(false) } } - }; + } return ( */} - ); -}; + ) +} export interface ClashFieldItemProps extends ButtonBaseProps { - label: string; - fields: string[]; + label: string + fields: string[] } /** @@ -114,7 +114,7 @@ export const ClashFieldItem = ({ fields, ...props }: ClashFieldItemProps) => { - const { palette } = useTheme(); + const { palette } = useTheme() return ( @@ -157,7 +157,7 @@ export const ClashFieldItem = ({ Enabled: {fields.map((item, index) => { - return {item}; + return {item} })} @@ -167,5 +167,5 @@ export const ClashFieldItem = ({ - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-web.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-web.tsx index 19f9d9d21c..3848c06927 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-web.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/clash-web.tsx @@ -1,15 +1,15 @@ -import { ReactElement, ReactNode } from "react"; -import Marquee from "react-fast-marquee"; -import DeleteRounded from "@mui/icons-material/DeleteRounded"; -import EditRounded from "@mui/icons-material/EditRounded"; -import OpenInNewRounded from "@mui/icons-material/OpenInNewRounded"; -import Box from "@mui/material/Box"; -import Chip from "@mui/material/Chip"; -import IconButton from "@mui/material/IconButton"; -import Paper, { PaperProps } from "@mui/material/Paper"; -import { alpha, styled } from "@mui/material/styles"; -import Typography from "@mui/material/Typography"; -import { openThat } from "@nyanpasu/interface"; +import { ReactElement, ReactNode } from 'react' +import Marquee from 'react-fast-marquee' +import DeleteRounded from '@mui/icons-material/DeleteRounded' +import EditRounded from '@mui/icons-material/EditRounded' +import OpenInNewRounded from '@mui/icons-material/OpenInNewRounded' +import Box from '@mui/material/Box' +import Chip from '@mui/material/Chip' +import IconButton from '@mui/material/IconButton' +import Paper, { PaperProps } from '@mui/material/Paper' +import { alpha, styled } from '@mui/material/styles' +import Typography from '@mui/material/Typography' +import { openThat } from '@nyanpasu/interface' /** * @example @@ -26,22 +26,22 @@ import { openThat } from "@nyanpasu/interface"; export const renderChip = ( string: string, labels: { - [label: string]: string | number | undefined; + [label: string]: string | number | undefined }, ): (string | ReactElement)[] => { return string.split(/(%[^&?]+)/).map((part, index) => { - if (part.startsWith("%")) { - const label = labels[part.replace("%", "")]; + if (part.startsWith('%')) { + const label = labels[part.replace('%', '')] // TODO: may should return part string if (!label) { - return ""; + return '' } return ( - ); + ) } else { - return part; + return part } - }); -}; + }) +} /** * @example @@ -72,13 +72,13 @@ export const extractServer = ( ): { host: string; port: number } => { if (!string) { // fallback default values - return { host: "127.0.0.1", port: 7890 }; + return { host: '127.0.0.1', port: 7890 } } else { - const [host, port] = string.split(":"); + const [host, port] = string.split(':') - return { host, port: Number(port) }; + return { host, port: Number(port) } } -}; +} /** * @example @@ -95,19 +95,19 @@ export const extractServer = ( export const openWebUrl = ( string: string, labels: { - [label: string]: string | number | undefined; + [label: string]: string | number | undefined }, ): void => { - let url = ""; + let url = '' for (const key in labels) { - const regex = new RegExp(`%${key}`, "g"); + const regex = new RegExp(`%${key}`, 'g') - url = string.replace(regex, labels[key] as string); + url = string.replace(regex, labels[key] as string) } - openThat(url); -}; + openThat(url) +} /** * @example @@ -124,16 +124,16 @@ export const Item = styled(Paper)(({ theme }) => ({ backgroundColor: alpha(theme.palette.primary.main, 0.1), padding: 16, borderRadius: 16, - display: "flex", - flexDirection: "column", + display: 'flex', + flexDirection: 'column', gap: 8, -})) as typeof Paper; +})) as typeof Paper export interface ClashWebItemProps { - label: ReactNode; - onOpen: () => void; - onDelete: () => void; - onEdit: () => void; + label: ReactNode + onOpen: () => void + onDelete: () => void + onEdit: () => void } /** @@ -181,5 +181,5 @@ export const ClashWebItem = ({ - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts index 26f7854a3b..9f4999b8e8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts @@ -1,13 +1,13 @@ -import { useGlobalMutation } from "@/utils/mutation"; -import { SwitchProps } from "@mui/material/Switch/Switch"; -import { Clash, useClash, useNyanpasu, VergeConfig } from "@nyanpasu/interface"; -import { MenuItemProps } from "@nyanpasu/ui"; +import { useGlobalMutation } from '@/utils/mutation' +import { SwitchProps } from '@mui/material/Switch/Switch' +import { Clash, useClash, useNyanpasu, VergeConfig } from '@nyanpasu/interface' +import { MenuItemProps } from '@nyanpasu/ui' -type OptionValue = string | number | boolean; +type OptionValue = string | number | boolean interface CreateMenuPropsOptions { - options: Record; - fallbackSelect: OptionValue; + options: Record + fallbackSelect: OptionValue } export const clash = { @@ -25,11 +25,11 @@ export const clash = { */ useBooleanProps: ( propName: { - [K in keyof Clash.Config]: Clash.Config[K] extends boolean ? K : never; + [K in keyof Clash.Config]: Clash.Config[K] extends boolean ? K : never }[keyof Clash.Config], ): SwitchProps => { - const { getConfigs, setConfigs } = useClash(); - const mutate = useGlobalMutation(); + const { getConfigs, setConfigs } = useClash() + const mutate = useGlobalMutation() return { checked: getConfigs.data?.[propName] || false, onChange: () => { @@ -39,11 +39,11 @@ export const clash = { ]).finally(() => { mutate( (key) => - typeof key === "string" && key.includes("/getRuntimeConfigYaml"), - ); - }); + typeof key === 'string' && key.includes('/getRuntimeConfigYaml'), + ) + }) }, - }; + } }, /** @@ -64,9 +64,9 @@ export const clash = { useMenuProps: ( propName: keyof Clash.Config, { options, fallbackSelect }: CreateMenuPropsOptions, - ): Omit => { - const { getConfigs, setConfigs } = useClash(); - const mutate = useGlobalMutation(); + ): Omit => { + const { getConfigs, setConfigs } = useClash() + const mutate = useGlobalMutation() return { options, @@ -75,13 +75,13 @@ export const clash = { Promise.all([setConfigs({ [propName]: value })]).finally(() => { mutate( (key) => - typeof key === "string" && key.includes("/getRuntimeConfigYaml"), - ); - }); + typeof key === 'string' && key.includes('/getRuntimeConfigYaml'), + ) + }) }, - }; + } }, -}; +} export const nyanpasu = { /** @@ -97,17 +97,17 @@ export const nyanpasu = { * @copyright LibNyanpasu org. 2024 */ useBooleanProps: (propName: keyof VergeConfig): SwitchProps => { - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() - if (typeof nyanpasuConfig?.[propName] !== "boolean") { - throw new Error(`Property ${propName} is not a boolean type`); + if (typeof nyanpasuConfig?.[propName] !== 'boolean') { + throw new Error(`Property ${propName} is not a boolean type`) } return { checked: (nyanpasuConfig?.[propName] as boolean) || false, onChange: async () => { - await setNyanpasuConfig({ [propName]: !nyanpasuConfig?.[propName] }); + await setNyanpasuConfig({ [propName]: !nyanpasuConfig?.[propName] }) }, - }; + } }, -}; +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx index 578e2dd86e..849ab59b77 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx @@ -1,42 +1,42 @@ -import { useLockFn } from "ahooks"; -import { useCallback, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import { Typography } from "@mui/material"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps } from "@nyanpasu/ui"; -import HotkeyInput from "./hotkey-input"; +import { useLockFn } from 'ahooks' +import { useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import { Typography } from '@mui/material' +import { useNyanpasu } from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps } from '@nyanpasu/ui' +import HotkeyInput from './hotkey-input' -export type HotkeyDialogProps = Omit; +export type HotkeyDialogProps = Omit const HOTKEY_FUNC = [ - "open_or_close_dashboard", - "clash_mode_rule", - "clash_mode_global", - "clash_mode_direct", - "clash_mode_script", - "toggle_system_proxy", + 'open_or_close_dashboard', + 'clash_mode_rule', + 'clash_mode_global', + 'clash_mode_direct', + 'clash_mode_script', + 'toggle_system_proxy', // "enable_system_proxy", // "disable_system_proxy", - "toggle_tun_mode", + 'toggle_tun_mode', // "enable_tun_mode", // "disable_tun_mode", -] as const; +] as const -type AllowedHotkeyFunc = (typeof HOTKEY_FUNC)[number]; +type AllowedHotkeyFunc = (typeof HOTKEY_FUNC)[number] -type Key = string; +type Key = string type HotKeyErrorMessages = { - [K in AllowedHotkeyFunc]: string | null; -}; + [K in AllowedHotkeyFunc]: string | null +} type HotKeyLoading = { - [K in AllowedHotkeyFunc]: boolean; -}; + [K in AllowedHotkeyFunc]: boolean +} -type HotkeyMap = { [K in AllowedHotkeyFunc]: Key[] }; +type HotkeyMap = { [K in AllowedHotkeyFunc]: Key[] } export default function HotkeyDialog({ open, @@ -44,102 +44,102 @@ export default function HotkeyDialog({ children, ...rest }: HotkeyDialogProps) { - const { t } = useTranslation(); + const { t } = useTranslation() // 检查是否有快捷键重复 - const [duplicateItems, setDuplicateItems] = useState([]); - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const [duplicateItems, setDuplicateItems] = useState([]) + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() - const [hotkeyMap, setHotkeyMap] = useState({} as HotkeyMap); + const [hotkeyMap, setHotkeyMap] = useState({} as HotkeyMap) useEffect(() => { if (open && Object.keys(hotkeyMap).length === 0) { - const map = {} as typeof hotkeyMap; + const map = {} as typeof hotkeyMap nyanpasuConfig?.hotkeys?.forEach((text) => { - const [func, key] = text.split(",").map((i) => i.trim()); - if (!func || !key) return; + const [func, key] = text.split(',').map((i) => i.trim()) + if (!func || !key) return map[func as AllowedHotkeyFunc] = key - .split("+") + .split('+') .map((e) => e.trim()) - .map((k) => (k === "PLUS" ? "+" : k)); - }); - setHotkeyMap(map); - setDuplicateItems([]); + .map((k) => (k === 'PLUS' ? '+' : k)) + }) + setHotkeyMap(map) + setDuplicateItems([]) } - }, [hotkeyMap, nyanpasuConfig?.hotkeys, open]); + }, [hotkeyMap, nyanpasuConfig?.hotkeys, open]) const [errorMessages, setErrorMessages] = useState( HOTKEY_FUNC.reduce( (acc, cur) => ({ ...acc, [cur]: null }), {} as HotKeyErrorMessages, ), - ); + ) const [loading, setLoading] = useState( HOTKEY_FUNC.reduce( (acc, cur) => ({ ...acc, [cur]: false }), {} as HotKeyLoading, ), - ); + ) const saveState = useLockFn( async (func: AllowedHotkeyFunc, hotkeyMap: HotkeyMap) => { const hotkeys = Object.entries(hotkeyMap) .map(([func, keys]) => { - if (!func || !keys?.length) return ""; + if (!func || !keys?.length) return '' const key = keys .map((k) => k.trim()) .filter(Boolean) - .map((k) => (k === "+" ? "PLUS" : k)) - .join("+"); + .map((k) => (k === '+' ? 'PLUS' : k)) + .join('+') - if (!key) return ""; - return `${func},${key}`; + if (!key) return '' + return `${func},${key}` }) - .filter(Boolean); + .filter(Boolean) try { - await setNyanpasuConfig({ hotkeys }); + await setNyanpasuConfig({ hotkeys }) } catch (err: unknown) { setErrorMessages((prev) => ({ ...prev, [func]: formatError(err), - })); + })) await message(formatError(err), { - kind: "error", - }); + kind: 'error', + }) } }, - ); + ) const onBlurCb = useCallback( (e: React.FocusEvent, func: string) => { - const keys = Object.values(hotkeyMap).flat().filter(Boolean); - const set = new Set(keys); + const keys = Object.values(hotkeyMap).flat().filter(Boolean) + const set = new Set(keys) if (keys.length !== set.size) { - setDuplicateItems([...duplicateItems, func]); - return; + setDuplicateItems([...duplicateItems, func]) + return } else { - setDuplicateItems(duplicateItems.filter((e) => e !== func)); + setDuplicateItems(duplicateItems.filter((e) => e !== func)) } - setLoading((prev) => ({ ...prev, [func]: true })); + setLoading((prev) => ({ ...prev, [func]: true })) saveState(func as AllowedHotkeyFunc, hotkeyMap) .catch(() => { - setDuplicateItems([...duplicateItems, func]); + setDuplicateItems([...duplicateItems, func]) }) .finally(() => { - setLoading((prev) => ({ ...prev, [func]: false })); - }); + setLoading((prev) => ({ ...prev, [func]: false })) + }) }, [duplicateItems, hotkeyMap, saveState], - ); + ) return ( - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.module.scss.d.ts index 255564212e..9a27229f34 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.module.scss.d.ts @@ -1,6 +1,6 @@ declare const classNames: { - readonly wrapper: "wrapper"; - readonly input: "input"; - readonly items: "items"; -}; -export default classNames; + readonly wrapper: 'wrapper' + readonly input: 'input' + readonly items: 'items' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.tsx index ca9d25c864..62fb135854 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-input.tsx @@ -1,18 +1,18 @@ -import { parseHotkey } from "@/utils/parse-hotkey"; -import { Dangerous, DeleteRounded } from "@mui/icons-material"; -import { alpha, CircularProgress, IconButton, useTheme } from "@mui/material"; -import type {} from "@mui/material/themeCssVarsAugmentation"; -import { CSSProperties, useEffect, useRef, useState } from "react"; -import { cn, Kbd } from "@nyanpasu/ui"; -import styles from "./hotkey-input.module.scss"; +import { parseHotkey } from '@/utils/parse-hotkey' +import { Dangerous, DeleteRounded } from '@mui/icons-material' +import { alpha, CircularProgress, IconButton, useTheme } from '@mui/material' +import type {} from '@mui/material/themeCssVarsAugmentation' +import { CSSProperties, useEffect, useRef, useState } from 'react' +import { cn, Kbd } from '@nyanpasu/ui' +import styles from './hotkey-input.module.scss' export interface Props extends React.HTMLAttributes { - isDuplicate?: boolean; - value?: string[]; - onValueChange?: (value: string[]) => void; - func: string; - onBlurCb?: (e: React.FocusEvent, func: string) => void; - loading?: boolean; + isDuplicate?: boolean + value?: string[] + onValueChange?: (value: string[]) => void + func: string + onBlurCb?: (e: React.FocusEvent, func: string) => void + loading?: boolean } export default function HotkeyInput({ @@ -26,65 +26,65 @@ export default function HotkeyInput({ loading, ...rest }: Props) { - const theme = useTheme(); + const theme = useTheme() - const changeRef = useRef([]); - const [keys, setKeys] = useState(value || []); - const [isClearing, setIsClearing] = useState(false); + const changeRef = useRef([]) + const [keys, setKeys] = useState(value || []) + const [isClearing, setIsClearing] = useState(false) useEffect(() => { if (isClearing) { - onBlurCb?.({} as React.FocusEvent, func); - setIsClearing(false); + onBlurCb?.({} as React.FocusEvent, func) + setIsClearing(false) } - }, [func, isClearing, onBlurCb]); + }, [func, isClearing, onBlurCb]) return (
-
+
{ - const ret = changeRef.current.slice(); + const ret = changeRef.current.slice() if (ret.length) { - onValueChange?.(ret); - changeRef.current = []; + onValueChange?.(ret) + changeRef.current = [] } }} onKeyDown={(e) => { - const evt = e.nativeEvent; - e.preventDefault(); - e.stopPropagation(); - const key = parseHotkey(evt.key); - if (key === "UNIDENTIFIED") return; + const evt = e.nativeEvent + e.preventDefault() + e.stopPropagation() + const key = parseHotkey(evt.key) + if (key === 'UNIDENTIFIED') return - changeRef.current = [...new Set([...changeRef.current, key])]; - setKeys(changeRef.current); + changeRef.current = [...new Set([...changeRef.current, key])] + setKeys(changeRef.current) }} onBlur={(e) => { - onBlurCb?.(e, func); + onBlurCb?.(e, func) }} {...rest} />
@@ -114,13 +114,13 @@ export default function HotkeyInput({ title="Delete" color="inherit" onClick={() => { - onValueChange?.([]); - setKeys([]); - setIsClearing(true); + onValueChange?.([]) + setKeys([]) + setIsClearing(true) }} >
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts index 2c32896383..4ff9a3e263 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts @@ -1,2 +1,2 @@ -export * from "./create-props"; -export * from "./clash-web"; +export * from './create-props' +export * from './clash-web' diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/nyanpasu-path.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/nyanpasu-path.tsx index 65b8bc925b..e5806b89dd 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/nyanpasu-path.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/nyanpasu-path.tsx @@ -1,4 +1,4 @@ -import { memo, ReactNode } from "react"; +import { memo, ReactNode } from 'react' import { alpha, ButtonBase, @@ -7,13 +7,13 @@ import { SxProps, Typography, useTheme, -} from "@mui/material"; +} from '@mui/material' export interface PaperButtonProps extends ButtonBaseProps { - label?: string; - children?: ReactNode; - sxPaper?: SxProps; - sxButton?: SxProps; + label?: string + children?: ReactNode + sxPaper?: SxProps + sxButton?: SxProps } export const PaperButton = memo(function PaperButton({ @@ -23,7 +23,7 @@ export const PaperButton = memo(function PaperButton({ sxButton, ...props }: PaperButtonProps) { - const { palette } = useTheme(); + const { palette } = useTheme() return ( {label} @@ -70,5 +70,5 @@ export const PaperButton = memo(function PaperButton({ {children} - ); -}); + ) +}) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/service-manual-prompt-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/service-manual-prompt-dialog.tsx index 0a11baa85b..d3716b35f8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/service-manual-prompt-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/service-manual-prompt-dialog.tsx @@ -1,19 +1,19 @@ -import { useAsyncEffect } from "ahooks"; -import { useAtom, useSetAtom } from "jotai"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import useSWR from "swr"; -import { OS } from "@/consts"; -import { serviceManualPromptDialogAtom } from "@/store/service"; -import { getShikiSingleton } from "@/utils/shiki"; -import { useTheme } from "@mui/material"; -import { getCoreDir, getServiceInstallPrompt } from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps, cn } from "@nyanpasu/ui"; -import styles from "./service-manual-prompt-dialog.module.scss"; +import { useAsyncEffect } from 'ahooks' +import { useAtom, useSetAtom } from 'jotai' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import useSWR from 'swr' +import { OS } from '@/consts' +import { serviceManualPromptDialogAtom } from '@/store/service' +import { getShikiSingleton } from '@/utils/shiki' +import { useTheme } from '@mui/material' +import { getCoreDir, getServiceInstallPrompt } from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps, cn } from '@nyanpasu/ui' +import styles from './service-manual-prompt-dialog.module.scss' -export type ServerManualPromptDialogProps = Omit & { - operation: "uninstall" | "install" | "start" | "stop" | null; -}; +export type ServerManualPromptDialogProps = Omit & { + operation: 'uninstall' | 'install' | 'start' | 'stop' | null +} // TODO: maybe support more commands prompt? export default function ServerManualPromptDialog({ @@ -22,54 +22,54 @@ export default function ServerManualPromptDialog({ operation, ...props }: ServerManualPromptDialogProps) { - const { t } = useTranslation(); - const theme = useTheme(); + const { t } = useTranslation() + const theme = useTheme() const { data: serviceInstallPrompt, error } = useSWR( - operation === "install" ? "/service_install_prompt" : null, + operation === 'install' ? '/service_install_prompt' : null, getServiceInstallPrompt, - ); - const { data: coreDir } = useSWR("/core_dir", () => getCoreDir()); - const [codes, setCodes] = useState(null); + ) + const { data: coreDir } = useSWR('/core_dir', () => getCoreDir()) + const [codes, setCodes] = useState(null) useAsyncEffect(async () => { - if (operation === "install" && serviceInstallPrompt) { - const shiki = await getShikiSingleton(); + if (operation === 'install' && serviceInstallPrompt) { + const shiki = await getShikiSingleton() const code = await shiki.codeToHtml( `cd "${coreDir}\n${serviceInstallPrompt}"`, { - lang: "shell", + lang: 'shell', themes: { - dark: "nord", - light: "min-light", + dark: 'nord', + light: 'min-light', }, }, - ); - setCodes(code); - } else if (!!operation) { - const shiki = await getShikiSingleton(); + ) + setCodes(code) + } else if (operation) { + const shiki = await getShikiSingleton() const code = await shiki.codeToHtml( - `cd "${coreDir}"\n${OS !== "windows" ? "sudo " : ""}./nyanpasu-service ${operation}`, + `cd "${coreDir}"\n${OS !== 'windows' ? 'sudo ' : ''}./nyanpasu-service ${operation}`, { - lang: "shell", + lang: 'shell', themes: { - dark: "nord", - light: "min-light", + dark: 'nord', + light: 'min-light', }, }, - ); - setCodes(code); + ) + setCodes(code) } - }, [serviceInstallPrompt, operation, coreDir]); + }, [serviceInstallPrompt, operation, coreDir]) return (

- {t("Unable to operation the service automatically", { + {t('Unable to operation the service automatically', { operation: t(`${operation}`), })}

@@ -77,8 +77,8 @@ export default function ServerManualPromptDialog({ {!!codes && (
- ); + ) } export function ServerManualPromptDialogWrapper() { - const [prompt, setPrompt] = useAtom(serviceManualPromptDialogAtom); + const [prompt, setPrompt] = useAtom(serviceManualPromptDialogAtom) return ( setPrompt(null)} operation={prompt} /> - ); + ) } export function useServerManualPromptDialog() { - const setPrompt = useSetAtom(serviceManualPromptDialogAtom); + const setPrompt = useSetAtom(serviceManualPromptDialogAtom) return { - show: (prompt: "install" | "uninstall" | "stop" | "start") => + show: (prompt: 'install' | 'uninstall' | 'stop' | 'start') => setPrompt(prompt), close: () => setPrompt(null), - }; + } } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/system-proxy.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/system-proxy.tsx index 2edef37e09..07e50652e8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/system-proxy.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/system-proxy.tsx @@ -1,16 +1,16 @@ -import { useControllableValue } from "ahooks"; -import { merge } from "lodash-es"; -import { memo, ReactNode } from "react"; -import { alpha, CircularProgress, SxProps, useTheme } from "@mui/material"; -import { PaperButton, PaperButtonProps } from "./nyanpasu-path"; +import { useControllableValue } from 'ahooks' +import { merge } from 'lodash-es' +import { memo, ReactNode } from 'react' +import { alpha, CircularProgress, SxProps, useTheme } from '@mui/material' +import { PaperButton, PaperButtonProps } from './nyanpasu-path' export interface PaperSwitchButtonProps extends PaperButtonProps { - label?: string; - checked: boolean; - loading?: boolean; - children?: ReactNode; - onClick?: () => Promise | void; - sxPaper?: SxProps; + label?: string + checked: boolean + loading?: boolean + children?: ReactNode + onClick?: () => Promise | void + sxPaper?: SxProps } export const PaperSwitchButton = memo(function PaperSwitchButton({ @@ -22,22 +22,22 @@ export const PaperSwitchButton = memo(function PaperSwitchButton({ sxPaper, ...props }: PaperSwitchButtonProps) { - const { palette } = useTheme(); + const { palette } = useTheme() const [pending, setPending] = useControllableValue( { loading }, { defaultValue: false, }, - ); + ) const handleClick = async () => { if (onClick) { - setPending(true); - await onClick(); - setPending(false); + setPending(true) + await onClick() + setPending(false) } - }; + } return ( - ); -}); + ) +}) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/tray-icon-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/tray-icon-dialog.tsx index 8b1503b3c0..1f945112d2 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/tray-icon-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/tray-icon-dialog.tsx @@ -1,67 +1,67 @@ -import { useMemoizedFn } from "ahooks"; -import { useState, useTransition } from "react"; -import { useTranslation } from "react-i18next"; -import useSWR from "swr"; -import { formatError, sleep } from "@/utils"; -import { message } from "@/utils/notification"; -import { LoadingButton } from "@mui/lab"; +import { useMemoizedFn } from 'ahooks' +import { useState, useTransition } from 'react' +import { useTranslation } from 'react-i18next' +import useSWR from 'swr' +import { formatError, sleep } from '@/utils' +import { message } from '@/utils/notification' +import { LoadingButton } from '@mui/lab' import { getServerPort, isTrayIconSet, setTrayIcon as setTrayIconCall, -} from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps } from "@nyanpasu/ui"; -import { open } from "@tauri-apps/plugin-dialog"; +} from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps } from '@nyanpasu/ui' +import { open } from '@tauri-apps/plugin-dialog' -function TrayIconItem({ mode }: { mode: "system_proxy" | "tun" | "normal" }) { - const { t } = useTranslation(); - const [ts, setTs] = useState(Date.now()); +function TrayIconItem({ mode }: { mode: 'system_proxy' | 'tun' | 'normal' }) { + const { t } = useTranslation() + const [ts, setTs] = useState(Date.now()) const { data: isSetTrayIcon, isLoading, mutate, - } = useSWR("/isSetTrayIcon?mode=" + mode, () => isTrayIconSet(mode), { + } = useSWR('/isSetTrayIcon?mode=' + mode, () => isTrayIconSet(mode), { revalidateOnFocus: true, - }); - const { data: serverPort } = useSWR("/getServerPort", getServerPort); - const src = `http://localhost:${serverPort}/tray/icon?mode=${mode}&ts=${ts}`; - const [loading, startTransition] = useTransition(); + }) + const { data: serverPort } = useSWR('/getServerPort', getServerPort) + const src = `http://localhost:${serverPort}/tray/icon?mode=${mode}&ts=${ts}` + const [loading, startTransition] = useTransition() const selectImage = async () => { const selected = await open({ directory: false, multiple: false, filters: [ - { name: "Images", extensions: ["png", "jpg", "jpeg", "bmp", "ico"] }, + { name: 'Images', extensions: ['png', 'jpg', 'jpeg', 'bmp', 'ico'] }, ], - }); + }) if (Array.isArray(selected)) { - throw new Error("Not Support"); + throw new Error('Not Support') } else if (selected === null) { - return null; + return null } else { - return selected; + return selected } - }; + } const setTrayIcon = useMemoizedFn((reset?: boolean) => { startTransition(async () => { try { - const selected = reset ? undefined : await selectImage(); + const selected = reset ? undefined : await selectImage() if (selected === null) { - return; + return } - return await setTrayIconCall(mode, selected); + return await setTrayIconCall(mode, selected) } catch (e) { message(formatError(e), { - kind: "error", - }); + kind: 'error', + }) } finally { - setTs(Date.now()); - await sleep(2000); - await mutate(); + setTs(Date.now()) + await sleep(2000) + await mutate() } - }); - }); + }) + }) return (
@@ -78,7 +78,7 @@ function TrayIconItem({ mode }: { mode: "system_proxy" | "tun" | "normal" }) { disabled={loading || isLoading} onClick={() => setTrayIcon()} > - {t("Edit")} + {t('Edit')} setTrayIcon(true)} > - {t("Reset")} + {t('Reset')}
) : ( @@ -96,25 +96,25 @@ function TrayIconItem({ mode }: { mode: "system_proxy" | "tun" | "normal" }) { disabled={loading || isLoading} onClick={() => setTrayIcon()} > - {t("Set")} + {t('Set')} )}
- ); + ) } -export type TrayIconDialogProps = Omit; +export type TrayIconDialogProps = Omit export default function TrayIconDialog({ open, onClose, ...props }: TrayIconDialogProps) { - const { t } = useTranslation(); + const { t } = useTranslation() return (
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-base.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-base.tsx index a64f1ec41d..c5b6fbba60 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-base.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-base.tsx @@ -1,110 +1,110 @@ -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { useCoreType } from "@/hooks/use-store"; -import getSystem from "@/utils/get-system"; -import { useGlobalMutation } from "@/utils/mutation"; -import { message } from "@/utils/notification"; -import { Button, List, ListItem, ListItemText } from "@mui/material"; -import { pullupUWPTool, useNyanpasu, VergeConfig } from "@nyanpasu/interface"; -import { BaseCard, MenuItem, SwitchItem } from "@nyanpasu/ui"; -import { clash } from "./modules"; +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import { useCoreType } from '@/hooks/use-store' +import getSystem from '@/utils/get-system' +import { useGlobalMutation } from '@/utils/mutation' +import { message } from '@/utils/notification' +import { Button, List, ListItem, ListItemText } from '@mui/material' +import { pullupUWPTool, useNyanpasu, VergeConfig } from '@nyanpasu/interface' +import { BaseCard, MenuItem, SwitchItem } from '@nyanpasu/ui' +import { clash } from './modules' const { useBooleanProps: createBooleanProps, useMenuProps: createMenuProps } = - clash; + clash -const isWIN = getSystem() === "windows"; +const isWIN = getSystem() === 'windows' export const SettingClashBase = () => { - const { t } = useTranslation(); - const [coreType] = useCoreType(); - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { t } = useTranslation() + const [coreType] = useCoreType() + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() const clickUWP = async () => { try { - await pullupUWPTool(); + await pullupUWPTool() } catch (e) { message(`Failed to Open UWP Tools.\n${JSON.stringify(e)}`, { - title: t("Error"), - kind: "error", - }); + title: t('Error'), + kind: 'error', + }) } - }; + } const tunStackOptions = useMemo(() => { const options: { - [key: string]: string; + [key: string]: string } = { - system: "System", - gvisor: "gVisor", - mixed: "Mixed", - }; - if (coreType === "clash") { - delete options.mixed; + system: 'System', + gvisor: 'gVisor', + mixed: 'Mixed', } - return options; - }, [coreType]); + if (coreType === 'clash') { + delete options.mixed + } + return options + }, [coreType]) const tunStackSelected = useMemo(() => { - const stack = nyanpasuConfig?.tun_stack || "gvisor"; - return stack in tunStackOptions ? stack : "gvisor"; - }, [nyanpasuConfig?.tun_stack, tunStackOptions]); - const mutate = useGlobalMutation(); + const stack = nyanpasuConfig?.tun_stack || 'gvisor' + return stack in tunStackOptions ? stack : 'gvisor' + }, [nyanpasuConfig?.tun_stack, tunStackOptions]) + const mutate = useGlobalMutation() return ( - + - + - {coreType !== "clash-rs" && ( + {coreType !== 'clash-rs' && ( { const payload = { - tun_stack: value as NonNullable, - } as Partial; + tun_stack: value as NonNullable, + } as Partial if (nyanpasuConfig?.enable_tun_mode) { - payload.enable_tun_mode = true; // just to reload clash config + payload.enable_tun_mode = true // just to reload clash config } - setNyanpasuConfig(payload); + setNyanpasuConfig(payload) mutate( (key) => - typeof key === "string" && - key.includes("/getRuntimeConfigYaml"), - ); + typeof key === 'string' && + key.includes('/getRuntimeConfigYaml'), + ) }} /> )} {isWIN && ( - + )} - ); -}; + ) +} -export default SettingClashBase; +export default SettingClashBase diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-core.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-core.tsx index a94f699365..4be8c32e1a 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-core.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-core.tsx @@ -1,23 +1,23 @@ -import { useLockFn, useReactive } from "ahooks"; -import { motion } from "framer-motion"; -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { OS } from "@/consts"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import { Box, List, ListItem } from "@mui/material"; -import { ClashCore, useClash, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, ExpandMore, LoadingButton } from "@nyanpasu/ui"; -import { ClashCoreItem } from "./modules/clash-core"; +import { useLockFn, useReactive } from 'ahooks' +import { motion } from 'framer-motion' +import { useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { OS } from '@/consts' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import { Box, List, ListItem } from '@mui/material' +import { ClashCore, useClash, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, ExpandMore, LoadingButton } from '@nyanpasu/ui' +import { ClashCoreItem } from './modules/clash-core' export const SettingClashCore = () => { - const { t } = useTranslation(); + const { t } = useTranslation() const loading = useReactive({ mask: false, - }); + }) - const [expand, setExpand] = useState(false); + const [expand, setExpand] = useState(false) const { nyanpasuConfig, setClashCore, @@ -27,118 +27,118 @@ export const SettingClashCore = () => { } = useNyanpasu({ onLatestCoreError: (error) => { message(`Fetch latest core failed: ${formatError(error)}`, { - kind: "error", - title: t("Error"), - }); + kind: 'error', + title: t('Error'), + }) }, - }); + }) - const { getVersion, deleteConnections } = useClash(); + const { getVersion, deleteConnections } = useClash() const version = useMemo(() => { - const data = getVersion.data; + const data = getVersion.data return data?.premium ? `${data.version} Premium` : data?.meta ? `${data.version} Meta` - : data?.version || "-"; - }, [getVersion.data]); + : data?.version || '-' + }, [getVersion.data]) const changeClashCore = useLockFn(async (core: ClashCore) => { try { - loading.mask = true; + loading.mask = true try { - await deleteConnections(); + await deleteConnections() } catch (e) { - console.error(e); + console.error(e) } - await setClashCore(core); + await setClashCore(core) message( - t("Successfully switched to the clash core", { core: `${core}` }), + t('Successfully switched to the clash core', { core: `${core}` }), { - kind: "info", - title: t("Successful"), + kind: 'info', + title: t('Successful'), }, - ); + ) } catch (e) { message( - t("Failed to switch. You could see the details in the log", { + t('Failed to switch. You could see the details in the log', { error: `${e instanceof Error ? e.message : String(e)}`, }), { - kind: "error", - title: t("Error"), + kind: 'error', + title: t('Error'), }, - ); + ) } finally { - loading.mask = false; + loading.mask = false } - }); + }) const handleRestart = async () => { try { - await restartSidecar(); + await restartSidecar() - message(t("Successfully restarted the core"), { - kind: "info", - title: t("Successful"), - }); + message(t('Successfully restarted the core'), { + kind: 'info', + title: t('Successful'), + }) } catch (e) { message( - t("Failed to restart. You could see the details in the log") + + t('Failed to restart. You could see the details in the log') + formatError(e), { - kind: "error", - title: t("Error"), + kind: 'error', + title: t('Error'), }, - ); + ) } - }; + } const handleCheckUpdates = async () => { try { - await getLatestCore.mutate(); + await getLatestCore.mutate() } catch (e) { - message(t("Failed to fetch. Please check your network connection"), { - kind: "error", - title: t("Error"), - }); + message(t('Failed to fetch. Please check your network connection'), { + kind: 'error', + title: t('Error'), + }) } - }; + } const mergeCores = useMemo(() => { return getClashCore.data?.map((item) => { const latest = getLatestCore.data?.find( - (i) => i.core == item.core, - )?.latest; + (i) => i.core === item.core, + )?.latest return { ...item, latest, - }; - }); - }, [getClashCore.data, getLatestCore.data]); + } + }) + }, [getClashCore.data, getLatestCore.data]) return ( {version}} > {mergeCores?.map((item) => { - const show = expand || item.core == nyanpasuConfig?.clash_core; + const show = expand || item.core === nyanpasuConfig?.clash_core return ( { }, }} transition={{ - type: "spring", + type: 'spring', bounce: 0, duration: 0.35, }} > changeClashCore(item.core)} /> - ); + ) })} - {t("Restart")} + {t('Restart')} {/** TODO: Support Linux when Manifest v2 released */} - {OS !== "linux" && ( + {OS !== 'linux' && ( - {t("Check Updates")} + {t('Check Updates')} )} @@ -192,7 +192,7 @@ export const SettingClashCore = () => { - ); -}; + ) +} -export default SettingClashCore; +export default SettingClashCore diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-external.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-external.tsx index e327c2c8d2..80624ca5f5 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-external.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-external.tsx @@ -1,9 +1,9 @@ -import { ChangeEvent, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useGlobalMutation } from "@/utils/mutation"; -import { message } from "@/utils/notification"; -import Done from "@mui/icons-material/Done"; -import LoadingButton from "@mui/lab/LoadingButton"; +import { ChangeEvent, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useGlobalMutation } from '@/utils/mutation' +import { message } from '@/utils/notification' +import Done from '@mui/icons-material/Done' +import LoadingButton from '@mui/lab/LoadingButton' import { Box, List, @@ -11,61 +11,61 @@ import { ListItemText, TextField, TextFieldProps, -} from "@mui/material"; -import { useClash, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, Expand, MenuItem } from "@nyanpasu/ui"; +} from '@mui/material' +import { useClash, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, Expand, MenuItem } from '@nyanpasu/ui' export const SettingClashExternal = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() - const { getClashInfo, setConfigs } = useClash(); - const mutate = useGlobalMutation(); + const { getClashInfo, setConfigs } = useClash() + const mutate = useGlobalMutation() - type PortStrategy = "fixed" | "random" | "allow_fallback"; + type PortStrategy = 'fixed' | 'random' | 'allow_fallback' const portStrategyOptions = { - allow_fallback: t("Allow Fallback"), - fixed: t("Fixed"), - random: t("Random"), - }; + allow_fallback: t('Allow Fallback'), + fixed: t('Fixed'), + random: t('Random'), + } const textFieldProps: TextFieldProps = { - size: "small", - variant: "outlined", + size: 'small', + variant: 'outlined', sx: { width: 160 }, inputProps: { - "aria-autocomplete": "none", + 'aria-autocomplete': 'none', }, - }; + } // What even are these fields????? // I had to write the shit code to make it run like a pile of crap. const [config, setConfig] = useState({ portStrategy: nyanpasuConfig?.clash_strategy?.external_controller_port_strategy || - "allow_fallback", - controller: getClashInfo.data?.server || "", - secret: getClashInfo.data?.secret || "", - }); + 'allow_fallback', + controller: getClashInfo.data?.server || '', + secret: getClashInfo.data?.secret || '', + }) useEffect(() => { setConfig({ portStrategy: nyanpasuConfig?.clash_strategy?.external_controller_port_strategy || - "allow_fallback", - controller: getClashInfo.data?.server || "", - secret: getClashInfo.data?.secret || "", - }); - }, [nyanpasuConfig, getClashInfo.data]); + 'allow_fallback', + controller: getClashInfo.data?.server || '', + secret: getClashInfo.data?.secret || '', + }) + }, [nyanpasuConfig, getClashInfo.data]) - const [expand, setExpand] = useState(false); + const [expand, setExpand] = useState(false) - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) const apply = async () => { - setLoading(true); + setLoading(true) try { await Promise.all([ @@ -76,39 +76,39 @@ export const SettingClashExternal = () => { }), setConfigs({ - "external-controller": config.controller, + 'external-controller': config.controller, secret: config.secret, }), - ]); + ]) } catch (e) { message(JSON.stringify(e), { - title: t("Error"), - kind: "error", - }); + title: t('Error'), + kind: 'error', + }) } finally { - setExpand(false); + setExpand(false) setTimeout(() => { - setLoading(false); + setLoading(false) mutate( (key) => - typeof key === "string" && key.includes("/getRuntimeConfigYaml"), - ); - }, 300); + typeof key === 'string' && key.includes('/getRuntimeConfigYaml'), + ) + }, 300) } - }; + } return ( - + - + ) => { - setConfig((v) => ({ ...v, controller: e.target.value })); - setExpand(true); + setConfig((v) => ({ ...v, controller: e.target.value })) + setExpand(true) }} {...textFieldProps} disabled={loading} @@ -116,29 +116,29 @@ export const SettingClashExternal = () => { { setConfig((v) => ({ ...v, portStrategy: value as PortStrategy, - })); - setExpand(true); + })) + setExpand(true) }} selectSx={{ width: 160 }} disabled={loading} /> - + ) => { - setConfig((v) => ({ ...v, secret: e.target.value })); - setExpand(true); + setConfig((v) => ({ ...v, secret: e.target.value })) + setExpand(true) }} {...textFieldProps} /> @@ -152,13 +152,13 @@ export const SettingClashExternal = () => { startIcon={} onClick={apply} > - {t("Apply")} + {t('Apply')} - ); -}; + ) +} -export default SettingClashExternal; +export default SettingClashExternal diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-field.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-field.tsx index d7c084a412..f6a2cf8ac8 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-field.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-field.tsx @@ -1,11 +1,11 @@ -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import CLASH_FIELD from "@/assets/json/clash-field.json"; -import { Box, Typography } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useClash, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, BaseDialog } from "@nyanpasu/ui"; -import { ClashFieldItem, LabelSwitch } from "./modules/clash-field"; +import { useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import CLASH_FIELD from '@/assets/json/clash-field.json' +import { Box, Typography } from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useClash, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, BaseDialog } from '@nyanpasu/ui' +import { ClashFieldItem, LabelSwitch } from './modules/clash-field' const FieldsControl = ({ label, @@ -13,23 +13,23 @@ const FieldsControl = ({ enabledFields, onChange, }: { - label: string; - fields: { [key: string]: string }; - enabledFields?: string[]; - onChange?: (key: string) => void; + label: string + fields: { [key: string]: string } + enabledFields?: string[] + onChange?: (key: string) => void }) => { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) // Nyanpasu Control Fields object key - const disabled = label === "default" || label === "handle"; + const disabled = label === 'default' || label === 'handle' const showFields: string[] = disabled ? Object.entries(fields).map(([key]) => key) - : (enabledFields as string[]); + : (enabledFields as string[]) const Item = () => { return Object.entries(fields).map(([fKey, fValue], fIndex) => { - const checked = enabledFields?.includes(fKey); + const checked = enabledFields?.includes(fKey) return ( onChange(fKey) : undefined} /> - ); - }); - }; + ) + }) + } return ( <> @@ -58,7 +58,7 @@ const FieldsControl = ({ close="Close" onClose={() => setOpen(false)} divider - contentStyle={{ overflow: "auto" }} + contentStyle={{ overflow: 'auto' }} > {disabled && Clash Nyanpasu Control Fields.} @@ -67,17 +67,17 @@ const FieldsControl = ({ - ); -}; + ) +} const ClashFieldSwitch = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() return ( setNyanpasuConfig({ @@ -85,13 +85,13 @@ const ClashFieldSwitch = () => { }) } /> - ); -}; + ) +} export const SettingClashField = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { getRuntimeExists, getProfiles, setProfilesConfig } = useClash(); + const { getRuntimeExists, getProfiles, setProfilesConfig } = useClash() const mergeFields = useMemo( () => [ @@ -99,45 +99,48 @@ export const SettingClashField = () => { ...(getProfiles.data?.valid ?? []), ], [getRuntimeExists.data, getProfiles.data], - ); + ) const filteredField = (fields: { [key: string]: string }): string[] => { - const usedObjects = []; + const usedObjects = [] for (const key in fields) { - if (fields.hasOwnProperty(key) && mergeFields.includes(key)) { - usedObjects.push(key); + if ( + Object.prototype.hasOwnProperty.call(fields, key) && + mergeFields.includes(key) + ) { + usedObjects.push(key) } } - return usedObjects; - }; + return usedObjects + } const updateFiled = async (key: string) => { const getFields = (): string[] => { - const valid = getProfiles.data?.valid ?? []; + const valid = getProfiles.data?.valid ?? [] if (valid.includes(key)) { - return valid.filter((item) => item !== key); + return valid.filter((item) => item !== key) } else { - valid.push(key); + valid.push(key) - return valid; + return valid } - }; + } - await setProfilesConfig({ valid: getFields() }); - }; + await setProfilesConfig({ valid: getFields() }) + } return ( - + {Object.entries(CLASH_FIELD).map(([key, value], index) => { - const filtered = filteredField(value); + const filtered = filteredField(value) return ( { enabledFields={filtered} onChange={updateFiled} /> - ); + ) })} - ); -}; + ) +} -export default SettingClashField; +export default SettingClashField diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx index b697827acf..2bbe053e87 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx @@ -1,63 +1,63 @@ -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { message } from "@/utils/notification"; -import { List } from "@mui/material"; -import { useClash, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, NumberItem, SwitchItem } from "@nyanpasu/ui"; +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import { message } from '@/utils/notification' +import { List } from '@mui/material' +import { useClash, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, NumberItem, SwitchItem } from '@nyanpasu/ui' export const SettingClashPort = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() - const { getConfigs, setConfigs } = useClash(); + const { getConfigs, setConfigs } = useClash() const port = useMemo(() => { return ( - getConfigs.data?.["mixed-port"] || + getConfigs.data?.['mixed-port'] || nyanpasuConfig?.verge_mixed_port || 7890 - ); - }, [getConfigs.data, nyanpasuConfig?.verge_mixed_port]); + ) + }, [getConfigs.data, nyanpasuConfig?.verge_mixed_port]) return ( - + input > 65535 || input < 1} checkLabel="Port must be between 1 and 65535." onApply={(value) => { - setConfigs({ "mixed-port": value }); - setNyanpasuConfig({ verge_mixed_port: value }); + setConfigs({ 'mixed-port': value }) + setNyanpasuConfig({ verge_mixed_port: value }) }} /> { try { await setNyanpasuConfig({ enable_random_port: !nyanpasuConfig?.enable_random_port, - }); + }) } catch (e) { message(JSON.stringify(e), { - title: t("Error"), - kind: "error", - }); + title: t('Error'), + kind: 'error', + }) } finally { - message(t("After restart to take effect"), { - title: t("Successful"), - kind: "info", - }); + message(t('After restart to take effect'), { + title: t('Successful'), + kind: 'info', + }) } }} /> - ); -}; + ) +} -export default SettingClashPort; +export default SettingClashPort diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-web.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-web.tsx index 8f59cd1534..cabdc93e01 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-web.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-web.tsx @@ -1,6 +1,6 @@ -import { useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import AddIcon from "@mui/icons-material/Add"; +import { useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import AddIcon from '@mui/icons-material/Add' import { Box, Chip, @@ -9,68 +9,68 @@ import { TextField, Tooltip, Typography, -} from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useClash, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, BaseDialog, Expand } from "@nyanpasu/ui"; -import { ClashWebItem, extractServer, openWebUrl, renderChip } from "./modules"; +} from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useClash, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, BaseDialog, Expand } from '@nyanpasu/ui' +import { ClashWebItem, extractServer, openWebUrl, renderChip } from './modules' export const SettingClashWeb = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() - const { getClashInfo } = useClash(); + const { getClashInfo } = useClash() const labels = useMemo(() => { - const { host, port } = extractServer(getClashInfo.data?.server); + const { host, port } = extractServer(getClashInfo.data?.server) return { host, port, secret: getClashInfo.data?.secret, - }; - }, [getClashInfo.data]); + } + }, [getClashInfo.data]) - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) - const [editString, setEditString] = useState(""); + const [editString, setEditString] = useState('') - const [editIndex, setEditIndex] = useState(null); + const [editIndex, setEditIndex] = useState(null) const deleteItem = (index: number) => { setNyanpasuConfig({ web_ui_list: nyanpasuConfig?.web_ui_list ?.slice(0, index) .concat(nyanpasuConfig?.web_ui_list?.slice(index + 1)), - }); - }; + }) + } const updateItem = () => { - const list = [...(nyanpasuConfig?.web_ui_list || [])]; + const list = [...(nyanpasuConfig?.web_ui_list || [])] - if (!list) return; + if (!list) return if (editIndex !== null) { - list[editIndex] = editString; + list[editIndex] = editString } else { - list.push(editString); + list.push(editString) } - setNyanpasuConfig({ web_ui_list: list }); - }; + setNyanpasuConfig({ web_ui_list: list }) + } return ( <> + { - setEditString(""); - setEditIndex(null); - setOpen(true); + setEditString('') + setEditIndex(null) + setOpen(true) }} > @@ -92,41 +92,41 @@ export const SettingClashWeb = () => { label={renderChip(item, labels)} onOpen={() => openWebUrl(item, labels)} onEdit={() => { - setEditIndex(index); - setEditString(item); - setOpen(true); + setEditIndex(index) + setEditString(item) + setOpen(true) }} onDelete={() => deleteItem(index)} /> - ); + ) })} { - setOpen(false); - setEditIndex(null); + setOpen(false) + setEditIndex(null) }} onOk={() => { - updateItem(); - setOpen(false); - setEditIndex(null); - setEditString(""); + updateItem() + setOpen(false) + setEditIndex(null) + setEditString('') }} ok="Submit" close="Close" - contentStyle={{ overflow: editString ? "auto" : "hidden" }} + contentStyle={{ overflow: editString ? 'auto' : 'hidden' }} divider > - {t("Input")} + {t('Input')} { onChange={(e) => setEditString(e.target.value)} /> - - {t("Replace host, port, and secret with")} + + {t('Replace host, port, and secret with')} {Object.entries(labels).map(([key], index) => { - return ; + return })} @@ -148,9 +148,9 @@ export const SettingClashWeb = () => { - {t("Result")} + {t('Result')} - + {renderChip(editString, labels)} @@ -158,7 +158,7 @@ export const SettingClashWeb = () => { - ); -}; + ) +} -export default SettingClashWeb; +export default SettingClashWeb diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-misc.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-misc.tsx index aa6999a969..8605b1f36c 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-misc.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-misc.tsx @@ -1,80 +1,80 @@ -import { useTranslation } from "react-i18next"; -import { List } from "@mui/material"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, MenuItem, SwitchItem, TextItem } from "@nyanpasu/ui"; -import { nyanpasu } from "./modules/create-props"; +import { useTranslation } from 'react-i18next' +import { List } from '@mui/material' +import { useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, MenuItem, SwitchItem, TextItem } from '@nyanpasu/ui' +import { nyanpasu } from './modules/create-props' -const { useBooleanProps: createBooleanProps } = nyanpasu; +const { useBooleanProps: createBooleanProps } = nyanpasu export const SettingNyanpasuMisc = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() const logOptions = { - trace: "Trace", - debug: "Debug", - info: "Info", - warn: "Warn", - error: "Error", - silent: "Silent", - }; + trace: 'Trace', + debug: 'Debug', + info: 'Info', + warn: 'Warn', + error: 'Error', + silent: 'Silent', + } const trayProxiesSelectorMode = { - normal: t("Normal"), - hidden: t("Hidden"), - submenu: t("Submenu"), - }; + normal: t('Normal'), + hidden: t('Hidden'), + submenu: t('Submenu'), + } return ( - + setNyanpasuConfig({ app_log_level: value as string }) } /> setNyanpasuConfig({ - clash_tray_selector: value as "normal" | "hidden" | "submenu", + clash_tray_selector: value as 'normal' | 'hidden' | 'submenu', }) } /> setNyanpasuConfig({ default_latency_test: value }) } /> - ); -}; + ) +} -export default SettingNyanpasuMisc; +export default SettingNyanpasuMisc diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-path.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-path.tsx index 620c062078..289976a7e0 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-path.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-path.tsx @@ -1,9 +1,9 @@ -import { useLockFn } from "ahooks"; -import { useTranslation } from "react-i18next"; -import { OS } from "@/consts"; -import { sleep } from "@/utils"; -import { message } from "@/utils/notification"; -import Grid from "@mui/material/Grid2"; +import { useLockFn } from 'ahooks' +import { useTranslation } from 'react-i18next' +import { OS } from '@/consts' +import { sleep } from '@/utils' +import { message } from '@/utils/notification' +import Grid from '@mui/material/Grid2' import { collectLogs, openAppConfigDir, @@ -12,13 +12,13 @@ import { openLogsDir, restartApplication, setCustomAppDir, -} from "@nyanpasu/interface"; -import { BaseCard } from "@nyanpasu/ui"; -import { open } from "@tauri-apps/plugin-dialog"; -import { PaperButton } from "./modules/nyanpasu-path"; +} from '@nyanpasu/interface' +import { BaseCard } from '@nyanpasu/ui' +import { open } from '@tauri-apps/plugin-dialog' +import { PaperButton } from './modules/nyanpasu-path' export const SettingNyanpasuPath = () => { - const { t } = useTranslation(); + const { t } = useTranslation() const migrateAppPath = useLockFn(async () => { try { @@ -26,54 +26,54 @@ export const SettingNyanpasuPath = () => { const selected = await open({ directory: true, multiple: false, - }); + }) // user cancelled the selection if (!selected) { - return; + return } if (Array.isArray(selected)) { - message(t("Multiple directories are not supported"), { - title: t("Error"), - kind: "error", - }); + message(t('Multiple directories are not supported'), { + title: t('Error'), + kind: 'error', + }) - return; + return } - await setCustomAppDir(selected); + await setCustomAppDir(selected) - message(t("Successfully changed the app directory"), { - title: t("Successful"), - kind: "error", - }); + message(t('Successfully changed the app directory'), { + title: t('Successful'), + kind: 'error', + }) - await sleep(1000); + await sleep(1000) - await restartApplication(); + await restartApplication() } catch (e) { - message(t("Failed to migrate", { error: `${JSON.stringify(e)}` }), { - title: t("Error"), - kind: "error", - }); + message(t('Failed to migrate', { error: `${JSON.stringify(e)}` }), { + title: t('Error'), + kind: 'error', + }) } - }); + }) const gridLists = [ - { label: t("Open Config Dir"), onClick: openAppConfigDir }, - { label: t("Open Data Dir"), onClick: openAppDataDir }, - OS === "windows" && { - label: t("Migrate App Path"), + { label: t('Open Config Dir'), onClick: openAppConfigDir }, + { label: t('Open Data Dir'), onClick: openAppDataDir }, + OS === 'windows' && { + label: t('Migrate App Path'), onClick: migrateAppPath, }, - { label: t("Open Core Dir"), onClick: openCoreDir }, - { label: t("Open Logs Dir"), onClick: openLogsDir }, - { label: t("Collect Logs"), onClick: collectLogs }, - ].filter((x) => !!x); + { label: t('Open Core Dir'), onClick: openCoreDir }, + { label: t('Open Logs Dir'), onClick: openLogsDir }, + { label: t('Collect Logs'), onClick: collectLogs }, + ].filter((x) => !!x) return ( - + {gridLists.map(({ label, onClick }) => ( { ))} - ); -}; + ) +} -export default SettingNyanpasuPath; +export default SettingNyanpasuPath diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-tasks.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-tasks.tsx index 1b9d5d46f8..76b24e4701 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-tasks.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-tasks.tsx @@ -1,26 +1,26 @@ -import { useTranslation } from "react-i18next"; -import { List } from "@mui/material"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, NumberItem } from "@nyanpasu/ui"; +import { useTranslation } from 'react-i18next' +import { List } from '@mui/material' +import { useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, NumberItem } from '@nyanpasu/ui' export const SettingNyanpasuTasks = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() return ( - + value <= 0} checkLabel="Value must larger than 0." onApply={(value) => setNyanpasuConfig({ max_log_files: value })} /> - ); -}; + ) +} -export default SettingNyanpasuTasks; +export default SettingNyanpasuTasks diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx index a1d7d7f46e..b062ee84ed 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx @@ -1,65 +1,65 @@ -import { useAtom } from "jotai"; -import { MuiColorInput } from "mui-color-input"; -import { useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { isHexColor } from "validator"; -import { defaultTheme } from "@/pages/-theme"; -import { atomIsDrawerOnlyIcon } from "@/store"; -import { languageOptions } from "@/utils/language"; -import Done from "@mui/icons-material/Done"; -import { Box, Button, List, ListItem, ListItemText } from "@mui/material"; -import { useNyanpasu, VergeConfig } from "@nyanpasu/interface"; -import { BaseCard, Expand, MenuItem, SwitchItem } from "@nyanpasu/ui"; +import { useAtom } from 'jotai' +import { MuiColorInput } from 'mui-color-input' +import { useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { isHexColor } from 'validator' +import { defaultTheme } from '@/pages/-theme' +import { atomIsDrawerOnlyIcon } from '@/store' +import { languageOptions } from '@/utils/language' +import Done from '@mui/icons-material/Done' +import { Box, Button, List, ListItem, ListItemText } from '@mui/material' +import { useNyanpasu, VergeConfig } from '@nyanpasu/interface' +import { BaseCard, Expand, MenuItem, SwitchItem } from '@nyanpasu/ui' export const SettingNyanpasuUI = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() const themeOptions = { - dark: t("theme.dark"), - light: t("theme.light"), - system: t("theme.system"), - }; + dark: t('theme.dark'), + light: t('theme.light'), + system: t('theme.system'), + } const [themeColor, setThemeColor] = useState( nyanpasuConfig?.theme_setting?.primary_color, - ); - const themeColorRef = useRef(themeColor); + ) + const themeColorRef = useRef(themeColor) const commonSx = { width: 128, - }; + } - const [onlyIcon, setOnlyIcon] = useAtom(atomIsDrawerOnlyIcon); + const [onlyIcon, setOnlyIcon] = useAtom(atomIsDrawerOnlyIcon) return ( - + setNyanpasuConfig({ language: value as string }) } /> setNyanpasuConfig({ - theme_mode: value as VergeConfig["theme_mode"], + theme_mode: value as VergeConfig['theme_mode'], }) } /> - + { if ( !isHexColor(themeColorRef.current ?? defaultTheme.primary_color) ) { - setThemeColor(themeColorRef.current); - return; + setThemeColor(themeColorRef.current) + return } - themeColorRef.current = themeColor; + themeColorRef.current = themeColor }} onChange={(color: string) => setThemeColor(color)} /> @@ -98,7 +98,7 @@ export const SettingNyanpasuUI = () => { ...nyanpasuConfig?.theme_setting, primary_color: themeColor, }, - }); + }) }} > Apply @@ -107,13 +107,13 @@ export const SettingNyanpasuUI = () => { setOnlyIcon(!onlyIcon)} /> - ); -}; + ) +} -export default SettingNyanpasuUI; +export default SettingNyanpasuUI diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx index 7bf747eeba..cb946fe346 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-version.tsx @@ -1,13 +1,13 @@ -import { useLockFn } from "ahooks"; -import { useSetAtom } from "jotai"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import LogoSvg from "@/assets/image/logo.svg?react"; -import { useUpdaterPlatformSupported } from "@/hooks/use-updater"; -import { UpdaterInstanceAtom } from "@/store/updater"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import LoadingButton from "@mui/lab/LoadingButton"; +import { useLockFn } from 'ahooks' +import { useSetAtom } from 'jotai' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import LogoSvg from '@/assets/image/logo.svg?react' +import { useUpdaterPlatformSupported } from '@/hooks/use-updater' +import { UpdaterInstanceAtom } from '@/store/updater' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import LoadingButton from '@mui/lab/LoadingButton' import { alpha, Box, @@ -16,21 +16,21 @@ import { Paper, Typography, useTheme, -} from "@mui/material"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard } from "@nyanpasu/ui"; -import { version } from "@root/package.json"; -import { check as checkUpdate } from "@tauri-apps/plugin-updater"; -import { LabelSwitch } from "./modules/clash-field"; +} from '@mui/material' +import { useNyanpasu } from '@nyanpasu/interface' +import { BaseCard } from '@nyanpasu/ui' +import { version } from '@root/package.json' +import { check as checkUpdate } from '@tauri-apps/plugin-updater' +import { LabelSwitch } from './modules/clash-field' const AutoCheckUpdate = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() return ( setNyanpasuConfig({ @@ -38,47 +38,47 @@ const AutoCheckUpdate = () => { }) } /> - ); -}; + ) +} export const SettingNyanpasuVersion = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { palette } = useTheme(); + const { palette } = useTheme() - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) - const setUpdaterInstance = useSetAtom(UpdaterInstanceAtom); - const isPlatformSupported = useUpdaterPlatformSupported(); + const setUpdaterInstance = useSetAtom(UpdaterInstanceAtom) + const isPlatformSupported = useUpdaterPlatformSupported() const onCheckUpdate = useLockFn(async () => { try { - setLoading(true); + setLoading(true) - const update = await checkUpdate(); + const update = await checkUpdate() if (!update?.available) { - message(t("No update available."), { - title: t("Info"), - kind: "info", - }); + message(t('No update available.'), { + title: t('Info'), + kind: 'info', + }) } else { - setUpdaterInstance(update || null); + setUpdaterInstance(update || null) } } catch (e) { message( `Update check failed. Please verify your network connection.\n\n${formatError(e)}`, { - title: t("Error"), - kind: "error", + title: t('Error'), + kind: 'error', }, - ); + ) } finally { - setLoading(false); + setLoading(false) } - }); + }) return ( - + { padding: 2, backgroundColor: alpha(palette.primary.main, 0.1), borderRadius: 6, - width: "100%", + width: '100%', }} > { - {"Clash Nyanpasu~(∠・ω< )⌒☆"}​ + {'Clash Nyanpasu~(∠・ω< )⌒☆'}  @@ -121,16 +121,16 @@ export const SettingNyanpasuVersion = () => { size="large" loading={loading} onClick={onCheckUpdate} - sx={{ width: "100%" }} + sx={{ width: '100%' }} > - {t("Check for Updates")} + {t('Check for Updates')} )} - ); -}; + ) +} -export default SettingNyanpasuVersion; +export default SettingNyanpasuVersion diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-page.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-page.tsx index 57270ec4fc..0e5592b241 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-page.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-page.tsx @@ -1,29 +1,29 @@ -import { useAtomValue } from "jotai"; -import { useWindowSize } from "react-use"; -import { useIsAppImage } from "@/hooks/use-consts"; -import { atomIsDrawerOnlyIcon } from "@/store"; -import Masonry from "@mui/lab/Masonry"; -import SettingClashBase from "./setting-clash-base"; -import SettingClashCore from "./setting-clash-core"; -import SettingClashExternal from "./setting-clash-external"; -import SettingClashField from "./setting-clash-field"; -import SettingClashPort from "./setting-clash-port"; -import SettingClashWeb from "./setting-clash-web"; -import SettingNyanpasuMisc from "./setting-nyanpasu-misc"; -import SettingNyanpasuPath from "./setting-nyanpasu-path"; -import SettingNyanpasuTasks from "./setting-nyanpasu-tasks"; -import SettingNyanpasuUI from "./setting-nyanpasu-ui"; -import SettingNyanpasuVersion from "./setting-nyanpasu-version"; -import SettingSystemBehavior from "./setting-system-behavior"; -import SettingSystemProxy from "./setting-system-proxy"; -import SettingSystemService from "./setting-system-service"; +import { useAtomValue } from 'jotai' +import { useWindowSize } from 'react-use' +import { useIsAppImage } from '@/hooks/use-consts' +import { atomIsDrawerOnlyIcon } from '@/store' +import Masonry from '@mui/lab/Masonry' +import SettingClashBase from './setting-clash-base' +import SettingClashCore from './setting-clash-core' +import SettingClashExternal from './setting-clash-external' +import SettingClashField from './setting-clash-field' +import SettingClashPort from './setting-clash-port' +import SettingClashWeb from './setting-clash-web' +import SettingNyanpasuMisc from './setting-nyanpasu-misc' +import SettingNyanpasuPath from './setting-nyanpasu-path' +import SettingNyanpasuTasks from './setting-nyanpasu-tasks' +import SettingNyanpasuUI from './setting-nyanpasu-ui' +import SettingNyanpasuVersion from './setting-nyanpasu-version' +import SettingSystemBehavior from './setting-system-behavior' +import SettingSystemProxy from './setting-system-proxy' +import SettingSystemService from './setting-system-service' export const SettingPage = () => { - const isAppImage = useIsAppImage(); + const isAppImage = useIsAppImage() - const isDrawerOnlyIcon = useAtomValue(atomIsDrawerOnlyIcon); + const isDrawerOnlyIcon = useAtomValue(atomIsDrawerOnlyIcon) - const { width } = useWindowSize(); + const { width } = useWindowSize() return ( { - ); -}; + ) +} -export default SettingPage; +export default SettingPage diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-behavior.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-behavior.tsx index 44cb684d05..832c0087f1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-behavior.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-behavior.tsx @@ -1,20 +1,20 @@ -import { useTranslation } from "react-i18next"; -import Grid from "@mui/material/Grid2"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard } from "@nyanpasu/ui"; -import { PaperSwitchButton } from "./modules/system-proxy"; +import { useTranslation } from 'react-i18next' +import Grid from '@mui/material/Grid2' +import { useNyanpasu } from '@nyanpasu/interface' +import { BaseCard } from '@nyanpasu/ui' +import { PaperSwitchButton } from './modules/system-proxy' export const SettingSystemBehavior = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu() return ( - + setNyanpasuConfig({ @@ -30,7 +30,7 @@ export const SettingSystemBehavior = () => { }} > setNyanpasuConfig({ @@ -41,7 +41,7 @@ export const SettingSystemBehavior = () => { - ); -}; + ) +} -export default SettingSystemBehavior; +export default SettingSystemBehavior diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-proxy.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-proxy.tsx index 2f07226c8a..a60118bbab 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-proxy.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-proxy.tsx @@ -1,8 +1,8 @@ -import { useLockFn, useReactive } from "ahooks"; -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { message } from "@/utils/notification"; -import { Done } from "@mui/icons-material"; +import { useLockFn, useReactive } from 'ahooks' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { message } from '@/utils/notification' +import { Done } from '@mui/icons-material' import { Box, Button, @@ -11,56 +11,56 @@ import { ListItem, TextField, Typography, -} from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useNyanpasu } from "@nyanpasu/interface"; +} from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useNyanpasu } from '@nyanpasu/interface' import { BaseCard, Expand, ExpandMore, NumberItem, SwitchItem, -} from "@nyanpasu/ui"; -import { PaperSwitchButton } from "./modules/system-proxy"; +} from '@nyanpasu/ui' +import { PaperSwitchButton } from './modules/system-proxy' export const SettingSystemProxy = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { nyanpasuConfig, setNyanpasuConfig, getSystemProxy } = useNyanpasu(); + const { nyanpasuConfig, setNyanpasuConfig, getSystemProxy } = useNyanpasu() const loading = useReactive({ enable_tun_mode: false, enable_system_proxy: false, - }); + }) const handleClick = useLockFn( - async (key: "enable_system_proxy" | "enable_tun_mode") => { + async (key: 'enable_system_proxy' | 'enable_tun_mode') => { try { - loading[key] = true; + loading[key] = true await setNyanpasuConfig({ [key]: !nyanpasuConfig?.[key], - }); + }) } catch (e) { message(`Activation failed!`, { - title: t("Error"), - kind: "error", - }); + title: t('Error'), + kind: 'error', + }) } finally { - loading[key] = false; + loading[key] = false } }, - ); + ) - const [expand, setExpand] = useState(false); + const [expand, setExpand] = useState(false) const [proxyBypass, setProxyBypass] = useState( - nyanpasuConfig?.system_proxy_bypass || "", - ); + nyanpasuConfig?.system_proxy_bypass || '', + ) return ( setExpand(!expand)} /> } @@ -72,19 +72,19 @@ export const SettingSystemProxy = () => { }} > handleClick("enable_tun_mode")} + onClick={() => handleClick('enable_tun_mode')} /> handleClick("enable_system_proxy")} + onClick={() => handleClick('enable_system_proxy')} /> @@ -92,7 +92,7 @@ export const SettingSystemProxy = () => { setNyanpasuConfig({ @@ -102,16 +102,16 @@ export const SettingSystemProxy = () => { /> input <= 0} - checkLabel={t("The interval must be greater than 0 second")} + checkLabel={t('The interval must be greater than 0 second')} onApply={(value) => { - setNyanpasuConfig({ proxy_guard_interval: value }); + setNyanpasuConfig({ proxy_guard_interval: value }) }} textFieldProps={{ inputProps: { - "aria-autocomplete": "none", + 'aria-autocomplete': 'none', }, InputProps: { endAdornment: s, @@ -122,32 +122,32 @@ export const SettingSystemProxy = () => { setProxyBypass(e.target.value)} /> - + - - {t("Current System Proxy")} + + {t('Current System Proxy')} {Object.entries(getSystemProxy?.data ?? []).map( @@ -155,14 +155,14 @@ export const SettingSystemProxy = () => { return ( {key}: {String(value)} - ); + ) }, )} @@ -170,7 +170,7 @@ export const SettingSystemProxy = () => { - ); -}; + ) +} -export default SettingSystemProxy; +export default SettingSystemProxy diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx index dd936220f3..9ec8be3356 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx @@ -1,139 +1,139 @@ -import { useMemoizedFn } from "ahooks"; -import { ChangeEvent, useTransition } from "react"; -import { useTranslation } from "react-i18next"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import { LoadingButton } from "@mui/lab"; -import { List, ListItem, ListItemText, Typography } from "@mui/material"; -import { restartSidecar, useNyanpasu } from "@nyanpasu/interface"; -import { BaseCard, SwitchItem } from "@nyanpasu/ui"; -import { nyanpasu } from "./modules/create-props"; +import { useMemoizedFn } from 'ahooks' +import { ChangeEvent, useTransition } from 'react' +import { useTranslation } from 'react-i18next' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import { LoadingButton } from '@mui/lab' +import { List, ListItem, ListItemText, Typography } from '@mui/material' +import { restartSidecar, useNyanpasu } from '@nyanpasu/interface' +import { BaseCard, SwitchItem } from '@nyanpasu/ui' +import { nyanpasu } from './modules/create-props' import { ServerManualPromptDialogWrapper, useServerManualPromptDialog, -} from "./modules/service-manual-prompt-dialog"; +} from './modules/service-manual-prompt-dialog' -const { useBooleanProps: createBooleanProps } = nyanpasu; +const { useBooleanProps: createBooleanProps } = nyanpasu export const SettingSystemService = () => { - const { t } = useTranslation(); + const { t } = useTranslation() - const { getServiceStatus, setServiceStatus } = useNyanpasu(); + const { getServiceStatus, setServiceStatus } = useNyanpasu() const getInstallButtonString = () => { switch (getServiceStatus.data) { - case "running": - case "stopped": { - return t("uninstall"); + case 'running': + case 'stopped': { + return t('uninstall') } - case "not_installed": { - return t("install"); + case 'not_installed': { + return t('install') } } - }; + } const getControlButtonString = () => { switch (getServiceStatus.data) { - case "running": { - return t("stop"); + case 'running': { + return t('stop') } - case "stopped": { - return t("start"); + case 'stopped': { + return t('start') } } - }; + } - const isDisabled = getServiceStatus.data === "not_installed"; + const isDisabled = getServiceStatus.data === 'not_installed' - const promptDialog = useServerManualPromptDialog(); + const promptDialog = useServerManualPromptDialog() - const [installOrUninstallPending, startInstallOrUninstall] = useTransition(); + const [installOrUninstallPending, startInstallOrUninstall] = useTransition() const handleInstallClick = useMemoizedFn(() => { startInstallOrUninstall(async () => { try { switch (getServiceStatus.data) { - case "running": - case "stopped": - await setServiceStatus("uninstall"); - break; + case 'running': + case 'stopped': + await setServiceStatus('uninstall') + break - case "not_installed": - await setServiceStatus("install"); - break; + case 'not_installed': + await setServiceStatus('install') + break default: - break; + break } - await restartSidecar(); + await restartSidecar() } catch (e) { const errorMessage = `${ - getServiceStatus.data === "not_installed" - ? t("Failed to install") - : t("Failed to uninstall") - }: ${formatError(e)}`; + getServiceStatus.data === 'not_installed' + ? t('Failed to install') + : t('Failed to uninstall') + }: ${formatError(e)}` message(errorMessage, { - kind: "error", - title: t("Error"), - }); + kind: 'error', + title: t('Error'), + }) // If the installation fails, prompt the user to manually install the service promptDialog.show( - getServiceStatus.data === "not_installed" ? "install" : "uninstall", - ); + getServiceStatus.data === 'not_installed' ? 'install' : 'uninstall', + ) } - }); - }); + }) + }) - const [serviceControlPending, startServiceControl] = useTransition(); + const [serviceControlPending, startServiceControl] = useTransition() const handleControlClick = useMemoizedFn(() => { startServiceControl(async () => { try { switch (getServiceStatus.data) { - case "running": - await setServiceStatus("stop"); - break; + case 'running': + await setServiceStatus('stop') + break - case "stopped": - await setServiceStatus("start"); - break; + case 'stopped': + await setServiceStatus('start') + break default: - break; + break } - await restartSidecar(); + await restartSidecar() } catch (e) { const errorMessage = - getServiceStatus.data === "running" + getServiceStatus.data === 'running' ? `Stop failed: ${formatError(e)}` - : `Start failed: ${formatError(e)}`; + : `Start failed: ${formatError(e)}` message(errorMessage, { - kind: "error", - title: t("Error"), - }); + kind: 'error', + title: t('Error'), + }) // If start failed show a prompt to user to start the service manually promptDialog.show( - getServiceStatus.data === "running" ? "stop" : "start", - ); + getServiceStatus.data === 'running' ? 'stop' : 'start', + ) } - }); - }); - const serviceToggleProps = createBooleanProps("enable_service_mode"); + }) + }) + const serviceToggleProps = createBooleanProps('enable_service_mode') const onChange = async ( event: ChangeEvent, checked: boolean, ) => { - await serviceToggleProps.onChange?.(event, checked); - await restartSidecar(); - }; + await serviceToggleProps.onChange?.(event, checked) + await restartSidecar() + } return ( - + { {t( - "Information: To enable service mode, make sure the Clash Nyanpasu service is installed and started", + 'Information: To enable service mode, make sure the Clash Nyanpasu service is installed and started', )} @@ -151,7 +151,7 @@ export const SettingSystemService = () => { @@ -179,7 +179,7 @@ export const SettingSystemService = () => { - ); -}; + ) +} -export default SettingSystemService; +export default SettingSystemService diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog-wrapper.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog-wrapper.tsx index 7910d835e1..6672e2a352 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog-wrapper.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog-wrapper.tsx @@ -1,25 +1,25 @@ -import { useAtom } from "jotai"; -import { lazy, Suspense, useState } from "react"; -import { UpdaterInstanceAtom } from "@/store/updater"; +import { useAtom } from 'jotai' +import { lazy, Suspense, useState } from 'react' +import { UpdaterInstanceAtom } from '@/store/updater' -const UpdaterDialog = lazy(() => import("./updater-dialog")); +const UpdaterDialog = lazy(() => import('./updater-dialog')) export const UpdaterDialogWrapper = () => { - const [open, setOpen] = useState(true); - const [manifest, setManifest] = useAtom(UpdaterInstanceAtom); - if (!manifest) return null; + const [open, setOpen] = useState(true) + const [manifest, setManifest] = useAtom(UpdaterInstanceAtom) + if (!manifest) return null return ( { - setOpen(false); - setManifest(null); + setOpen(false) + setManifest(null) }} update={manifest} /> - ); -}; + ) +} -export default UpdaterDialogWrapper; +export default UpdaterDialogWrapper diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.module.scss.d.ts index 17eb5c902d..3334b5a0e5 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.module.scss.d.ts @@ -1,5 +1,5 @@ declare const classNames: { - readonly UpdaterDialog: "UpdaterDialog"; - readonly MarkdownContent: "MarkdownContent"; -}; -export default classNames; + readonly UpdaterDialog: 'UpdaterDialog' + readonly MarkdownContent: 'MarkdownContent' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.tsx index 49a480a13e..320213775d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/updater/updater-dialog.tsx @@ -1,22 +1,22 @@ -import { useLockFn } from "ahooks"; -import dayjs from "dayjs"; -import { useSetAtom } from "jotai"; -import { lazy, Suspense, useCallback, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { UpdaterIgnoredAtom } from "@/store/updater"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import { Button, LinearProgress } from "@mui/material"; -import { cleanupProcesses, openThat } from "@nyanpasu/interface"; -import { BaseDialog, BaseDialogProps, cn } from "@nyanpasu/ui"; -import { relaunch } from "@tauri-apps/plugin-process"; -import { DownloadEvent, type Update } from "@tauri-apps/plugin-updater"; -import styles from "./updater-dialog.module.scss"; +import { useLockFn } from 'ahooks' +import dayjs from 'dayjs' +import { useSetAtom } from 'jotai' +import { lazy, Suspense, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { UpdaterIgnoredAtom } from '@/store/updater' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import { Button, LinearProgress } from '@mui/material' +import { cleanupProcesses, openThat } from '@nyanpasu/interface' +import { BaseDialog, BaseDialogProps, cn } from '@nyanpasu/ui' +import { relaunch } from '@tauri-apps/plugin-process' +import { DownloadEvent, type Update } from '@tauri-apps/plugin-updater' +import styles from './updater-dialog.module.scss' -const Markdown = lazy(() => import("react-markdown")); +const Markdown = lazy(() => import('react-markdown')) -export interface UpdaterDialogProps extends Omit { - update: Update; +export interface UpdaterDialogProps extends Omit { + update: Update } export default function UpdaterDialog({ @@ -25,58 +25,58 @@ export default function UpdaterDialog({ onClose, ...others }: UpdaterDialogProps) { - const { t } = useTranslation(); - const setUpdaterIgnore = useSetAtom(UpdaterIgnoredAtom); - const [contentLength, setContentLength] = useState(0); - const [contentDownloaded, setContentDownloaded] = useState(0); + const { t } = useTranslation() + const setUpdaterIgnore = useSetAtom(UpdaterIgnoredAtom) + const [contentLength, setContentLength] = useState(0) + const [contentDownloaded, setContentDownloaded] = useState(0) const progress = contentDownloaded && contentLength ? (contentDownloaded / contentLength) * 100 - : 0; + : 0 const onDownloadEvent = useCallback((e: DownloadEvent) => { switch (e.event) { - case "Started": - setContentLength(e.data.contentLength || 0); - break; - case "Progress": - setContentDownloaded((prev) => prev + e.data.chunkLength); - break; + case 'Started': + setContentLength(e.data.contentLength || 0) + break + case 'Progress': + setContentDownloaded((prev) => prev + e.data.chunkLength) + break } - }, []); + }, []) const handleUpdate = useLockFn(async () => { try { // Install the update. This will also restart the app on Windows! - await update.download(onDownloadEvent); - await cleanupProcesses(); + await update.download(onDownloadEvent) + await cleanupProcesses() // cleanup and stop core - await update.install(); + await update.install() // On macOS and Linux you will need to restart the app manually. // You could use this step to display another confirmation dialog. - await relaunch(); + await relaunch() } catch (e) { - console.error(e); - message(formatError(e), { kind: "error", title: t("Error") }); + console.error(e) + message(formatError(e), { kind: 'error', title: t('Error') }) } - }); + }) return ( { - setUpdaterIgnore(update.version); // TODO: control this behavior - onClose?.(); + setUpdaterIgnore(update.version) // TODO: control this behavior + onClose?.() }} onOk={handleUpdate} - close={t("updater.close")} - ok={t("updater.update")} + close={t('updater.close')} + ok={t('updater.update')} divider >
@@ -84,8 +84,8 @@ export default function UpdaterDialog({
{update.version} - {dayjs(update.date, "YYYY-MM-DD H:mm:ss Z").format( - "YYYY-MM-DD HH:mm:ss", + {dayjs(update.date, 'YYYY-MM-DD H:mm:ss Z').format( + 'YYYY-MM-DD HH:mm:ss', )}
@@ -95,36 +95,36 @@ export default function UpdaterDialog({ onClick={() => { openThat( `https://github.com/libnyanpasu/clash-nyanpasu/releases/tag/v${update.version}`, - ); + ) }} > - {t("updater.go")} + {t('updater.go')}
- {t("loading")}
}> + {t('loading')}
}> { - e.preventDefault(); - e.stopPropagation(); - openThat(node.properties.href); + e.preventDefault() + e.stopPropagation() + openThat(node.properties.href) }} > {children} - ); + ) }, }} > - {update.body || "New version available."} + {update.body || 'New version available.'}
@@ -142,5 +142,5 @@ export default function UpdaterDialog({ )}
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/consts.ts b/clash-nyanpasu/frontend/nyanpasu/src/consts.ts index 5c22470f45..2e07473b0b 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/consts.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/consts.ts @@ -1,3 +1,3 @@ -import { getSystem } from "@nyanpasu/ui"; +import { getSystem } from '@nyanpasu/ui' -export const OS = getSystem(); +export const OS = getSystem() diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/theme.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/theme.ts index 628fd9522a..566dfcce29 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/theme.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/theme.ts @@ -1,25 +1,25 @@ -import { useTheme } from "@mui/material"; +import { useTheme } from '@mui/material' export const useColorForDelay = (delay: number): string => { - const { palette } = useTheme(); + const { palette } = useTheme() const delayColorMapping: { [key: string]: string } = { - "-1": palette.text.primary, - "0": palette.text.secondary, - "1": palette.text.secondary, - "500": palette.success.main, - "2000": palette.warning.main, - "10000": palette.error.main, - }; + '-1': palette.text.primary, + '0': palette.text.secondary, + '1': palette.text.secondary, + '500': palette.success.main, + '2000': palette.warning.main, + '10000': palette.error.main, + } - let color: string = palette.text.secondary; + let color: string = palette.text.secondary for (const key in delayColorMapping) { if (delay <= parseInt(key)) { - color = delayColorMapping[key]; - break; + color = delayColorMapping[key] + break } } - return color; -}; + return color +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts index 09f61f0063..99bdb58415 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts @@ -1,11 +1,11 @@ -import useSWR, { SWRConfiguration } from "swr"; -import { isAppImage } from "@nyanpasu/interface"; +import useSWR, { SWRConfiguration } from 'swr' +import { isAppImage } from '@nyanpasu/interface' export const useIsAppImage = (config?: Partial) => { - return useSWR("/api/is_appimage", isAppImage, { + return useSWR('/api/is_appimage', isAppImage, { ...(config || {}), revalidateOnFocus: false, revalidateOnReconnect: false, refreshInterval: 0, - }); -}; + }) +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-element-breakpoints.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-element-breakpoints.ts index 23110ef9c9..ccb4114191 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-element-breakpoints.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-element-breakpoints.ts @@ -1,30 +1,28 @@ -import { RefObject, useEffect, useState } from "react"; +import { RefObject, useEffect, useState } from 'react' export const useElementBreakpoints = ( element: RefObject, breakpoints: { [key: string]: number }, defaultBreakpoint: string, ) => { - const [breakpoint, setBreakpoint] = useState( - defaultBreakpoint, - ); + const [breakpoint, setBreakpoint] = useState(defaultBreakpoint) useEffect(() => { - let observer: ResizeObserver | null = null; + let observer: ResizeObserver | null = null if (element.current) { observer = new ResizeObserver(() => { - const { width } = element.current.getBoundingClientRect(); + const { width } = element.current.getBoundingClientRect() const breakpoint = Object.entries(breakpoints).find( ([, value]) => width >= value, - )?.[0]; + )?.[0] if (breakpoint) { - setBreakpoint(breakpoint); + setBreakpoint(breakpoint) } - }); - observer.observe(element.current); + }) + observer.observe(element.current) } - return () => observer?.disconnect(); - }, [element, breakpoints]); + return () => observer?.disconnect() + }, [element, breakpoints]) - return breakpoint; -}; + return breakpoint +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-store.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-store.ts index 4ce5490daf..604dbfc934 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-store.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-store.ts @@ -1,40 +1,40 @@ -import { useAtom } from "jotai"; -import { useEffect } from "react"; -import { dispatchStorageValueChanged } from "@/services/storage"; -import { coreTypeAtom } from "@/store/clash"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { listen, UnlistenFn } from "@tauri-apps/api/event"; +import { useAtom } from 'jotai' +import { useEffect } from 'react' +import { dispatchStorageValueChanged } from '@/services/storage' +import { coreTypeAtom } from '@/store/clash' +import { useNyanpasu } from '@nyanpasu/interface' +import { listen, UnlistenFn } from '@tauri-apps/api/event' export function useCoreType() { - const [coreType, setCoreType] = useAtom(coreTypeAtom); + const [coreType, setCoreType] = useAtom(coreTypeAtom) const { setNyanpasuConfig } = useNyanpasu({ onSuccess(data) { - setCoreType(data?.clash_core || "mihomo"); + setCoreType(data?.clash_core || 'mihomo') }, - }); + }) const setter = (value: typeof coreType) => { - setCoreType(value); - setNyanpasuConfig({ clash_core: value }); - }; - return [coreType, setter] as const; + setCoreType(value) + setNyanpasuConfig({ clash_core: value }) + } + return [coreType, setter] as const } export function useNyanpasuStorageSubscribers() { useEffect(() => { - let unlisten: UnlistenFn | null = null; - listen<[string, string | null]>("storage_value_changed", (event) => { - const [key, value] = event.payload; + let unlisten: UnlistenFn | null = null + listen<[string, string | null]>('storage_value_changed', (event) => { + const [key, value] = event.payload dispatchStorageValueChanged( key, - typeof value === "string" ? JSON.parse(value) : value, - ); + typeof value === 'string' ? JSON.parse(value) : value, + ) }).then((fn) => { - unlisten = fn; - }); + unlisten = fn + }) return () => { if (unlisten) { - unlisten(); + unlisten() } - }; - }); + } + }) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-updater.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-updater.ts index 473d376bcd..c836f7ac78 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-updater.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-updater.ts @@ -1,48 +1,48 @@ -import { useAtomValue, useSetAtom } from "jotai"; -import { useEffect, useState } from "react"; -import { OS } from "@/consts"; -import { UpdaterIgnoredAtom, UpdaterInstanceAtom } from "@/store/updater"; -import { useNyanpasu } from "@nyanpasu/interface"; -import { check as checkUpdate } from "@tauri-apps/plugin-updater"; -import { useIsAppImage } from "./use-consts"; +import { useAtomValue, useSetAtom } from 'jotai' +import { useEffect, useState } from 'react' +import { OS } from '@/consts' +import { UpdaterIgnoredAtom, UpdaterInstanceAtom } from '@/store/updater' +import { useNyanpasu } from '@nyanpasu/interface' +import { check as checkUpdate } from '@tauri-apps/plugin-updater' +import { useIsAppImage } from './use-consts' export function useUpdaterPlatformSupported() { - const [supported, setSupported] = useState(false); - const isAppImage = useIsAppImage(); + const [supported, setSupported] = useState(false) + const isAppImage = useIsAppImage() useEffect(() => { switch (OS) { - case "macos": - case "windows": - setSupported(true); - break; - case "linux": - setSupported(!!isAppImage.data); - break; + case 'macos': + case 'windows': + setSupported(true) + break + case 'linux': + setSupported(!!isAppImage.data) + break } - }, [isAppImage.data]); - return supported; + }, [isAppImage.data]) + return supported } export default function useUpdater() { - const { nyanpasuConfig } = useNyanpasu(); - const updaterIgnored = useAtomValue(UpdaterIgnoredAtom); - const setUpdaterInstance = useSetAtom(UpdaterInstanceAtom); - const isPlatformSupported = useUpdaterPlatformSupported(); + const { nyanpasuConfig } = useNyanpasu() + const updaterIgnored = useAtomValue(UpdaterIgnoredAtom) + const setUpdaterInstance = useSetAtom(UpdaterInstanceAtom) + const isPlatformSupported = useUpdaterPlatformSupported() useEffect(() => { const run = async () => { if (nyanpasuConfig?.enable_auto_check_update && isPlatformSupported) { - const updater = await checkUpdate(); + const updater = await checkUpdate() if (updater?.available && updaterIgnored !== updater?.version) { - setUpdaterInstance(updater || null); + setUpdaterInstance(updater || null) } } - }; - run().catch(console.error); + } + run().catch(console.error) }, [ isPlatformSupported, nyanpasuConfig?.enable_auto_check_update, setUpdaterInstance, updaterIgnored, - ]); + ]) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-visibility.ts b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-visibility.ts index 31d6d3d735..0c8d547d99 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-visibility.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/hooks/use-visibility.ts @@ -1,27 +1,27 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState } from 'react' export const useVisibility = () => { - const [visible, setVisible] = useState(true); + const [visible, setVisible] = useState(true) useEffect(() => { const handleVisibilityChange = () => { - setVisible(document.visibilityState === "visible"); - }; + setVisible(document.visibilityState === 'visible') + } - const handleFocus = () => setVisible(true); - const handleClick = () => setVisible(true); + const handleFocus = () => setVisible(true) + const handleClick = () => setVisible(true) - handleVisibilityChange(); - document.addEventListener("focus", handleFocus); - document.addEventListener("pointerdown", handleClick); - document.addEventListener("visibilitychange", handleVisibilityChange); + handleVisibilityChange() + document.addEventListener('focus', handleFocus) + document.addEventListener('pointerdown', handleClick) + document.addEventListener('visibilitychange', handleVisibilityChange) return () => { - document.removeEventListener("focus", handleFocus); - document.removeEventListener("pointerdown", handleClick); - document.removeEventListener("visibilitychange", handleVisibilityChange); - }; - }, []); + document.removeEventListener('focus', handleFocus) + document.removeEventListener('pointerdown', handleClick) + document.removeEventListener('visibilitychange', handleVisibilityChange) + } + }, []) - return visible; -}; + return visible +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/main.tsx b/clash-nyanpasu/frontend/nyanpasu/src/main.tsx index b222795c83..426bc42aa6 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/main.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/main.tsx @@ -1,38 +1,38 @@ /// /// -import React from "react"; -import { createRoot } from "react-dom/client"; -import { ResizeObserver } from "@juggle/resize-observer"; +import React from 'react' +import { createRoot } from 'react-dom/client' +import { ResizeObserver } from '@juggle/resize-observer' // Styles -import "@csstools/normalize.css/normalize.css"; -import "@csstools/normalize.css/opinionated.css"; -import { createRouter, RouterProvider } from "@tanstack/react-router"; -import "./assets/styles/index.scss"; -import "./assets/styles/tailwind.css"; -import { routeTree } from "./routeTree.gen"; -import "./services/i18n"; +import '@csstools/normalize.css/normalize.css' +import '@csstools/normalize.css/opinionated.css' +import { createRouter, RouterProvider } from '@tanstack/react-router' +import './assets/styles/index.scss' +import './assets/styles/tailwind.css' +import { routeTree } from './routeTree.gen' +import './services/i18n' if (!window.ResizeObserver) { - window.ResizeObserver = ResizeObserver; + window.ResizeObserver = ResizeObserver } // Set up a Router instance const router = createRouter({ routeTree, - defaultPreload: "intent", -}); + defaultPreload: 'intent', +}) // Register things for typesafety -declare module "@tanstack/react-router" { +declare module '@tanstack/react-router' { interface Register { - router: typeof router; + router: typeof router } } -const container = document.getElementById("root")!; +const container = document.getElementById('root')! createRoot(container).render( , -); +) diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/-__root.module.scss.d.ts b/clash-nyanpasu/frontend/nyanpasu/src/pages/-__root.module.scss.d.ts index f89d4b345e..c64cf9b69d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/-__root.module.scss.d.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/-__root.module.scss.d.ts @@ -1,5 +1,5 @@ declare const classNames: { - readonly oops: "oops"; - readonly dark: "dark"; -}; -export default classNames; + readonly oops: 'oops' + readonly dark: 'dark' +} +export default classNames diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/-theme.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/-theme.tsx index 030fdb22e7..f07d47c898 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/-theme.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/-theme.tsx @@ -1,19 +1,19 @@ // default theme setting export const defaultTheme = { - primary_color: "#1867c0", - secondary_color: "#3a88bb", - primary_text: "#1d1d1f", - secondary_text: "#424245", - info_color: "#0288d1", - error_color: "#d32f2f", - warning_color: "#ed6c02", - success_color: "#2e7d32", + primary_color: '#1867c0', + secondary_color: '#3a88bb', + primary_text: '#1d1d1f', + secondary_text: '#424245', + info_color: '#0288d1', + error_color: '#d32f2f', + warning_color: '#ed6c02', + success_color: '#2e7d32', font_family: `"Roboto", "Helvetica", "Arial", sans-serif, "Color Emoji Flags"," Color Emoji"`, -}; +} // dark mode export const defaultDarkTheme = { ...defaultTheme, - primary_text: "#E8E8ED", - secondary_text: "#bbbbbb", -}; + primary_text: '#E8E8ED', + secondary_text: '#bbbbbb', +} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx index 1b8acc6980..f84d37d9a7 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx @@ -1,49 +1,49 @@ -import { useMount } from "ahooks"; -import dayjs from "dayjs"; -import AppContainer from "@/components/app/app-container"; -import LocalesProvider from "@/components/app/locales-provider"; -import MutationProvider from "@/components/layout/mutation-provider"; -import NoticeProvider from "@/components/layout/notice-provider"; -import PageTransition from "@/components/layout/page-transition"; -import SchemeProvider from "@/components/layout/scheme-provider"; +import { useMount } from 'ahooks' +import dayjs from 'dayjs' +import AppContainer from '@/components/app/app-container' +import LocalesProvider from '@/components/app/locales-provider' +import MutationProvider from '@/components/layout/mutation-provider' +import NoticeProvider from '@/components/layout/notice-provider' +import PageTransition from '@/components/layout/page-transition' +import SchemeProvider from '@/components/layout/scheme-provider' import { ThemeModeProvider, useCustomTheme, -} from "@/components/layout/use-custom-theme"; -import LogProvider from "@/components/logs/log-provider"; -import UpdaterDialog from "@/components/updater/updater-dialog-wrapper"; -import { useNyanpasuStorageSubscribers } from "@/hooks/use-store"; -import useUpdater from "@/hooks/use-updater"; -import { FileRouteTypes } from "@/routeTree.gen"; -import { atomIsDrawer, memorizedRoutePathAtom } from "@/store"; -import { CssBaseline, useTheme } from "@mui/material"; -import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles"; -import { cn, useBreakpoint } from "@nyanpasu/ui"; +} from '@/components/layout/use-custom-theme' +import LogProvider from '@/components/logs/log-provider' +import UpdaterDialog from '@/components/updater/updater-dialog-wrapper' +import { useNyanpasuStorageSubscribers } from '@/hooks/use-store' +import useUpdater from '@/hooks/use-updater' +import { FileRouteTypes } from '@/routeTree.gen' +import { atomIsDrawer, memorizedRoutePathAtom } from '@/store' +import { CssBaseline, useTheme } from '@mui/material' +import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles' +import { cn, useBreakpoint } from '@nyanpasu/ui' import { createRootRoute, ErrorComponentProps, useLocation, -} from "@tanstack/react-router"; -import { emit } from "@tauri-apps/api/event"; -import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; -import "dayjs/locale/ru"; -import "dayjs/locale/zh-cn"; -import customParseFormat from "dayjs/plugin/customParseFormat"; -import relativeTime from "dayjs/plugin/relativeTime"; -import { useAtom, useSetAtom } from "jotai"; -import { lazy, useEffect } from "react"; -import { SWRConfig } from "swr"; -import styles from "./-__root.module.scss"; +} from '@tanstack/react-router' +import { emit } from '@tauri-apps/api/event' +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' +import 'dayjs/locale/ru' +import 'dayjs/locale/zh-cn' +import customParseFormat from 'dayjs/plugin/customParseFormat' +import relativeTime from 'dayjs/plugin/relativeTime' +import { useAtom, useSetAtom } from 'jotai' +import { lazy, useEffect } from 'react' +import { SWRConfig } from 'swr' +import styles from './-__root.module.scss' -dayjs.extend(relativeTime); -dayjs.extend(customParseFormat); +dayjs.extend(relativeTime) +dayjs.extend(customParseFormat) export const Catch = ({ error }: ErrorComponentProps) => { - const theme = useTheme(); + const theme = useTheme() return (

Oops!

Something went wrong... Caught at _root error boundary.

@@ -52,61 +52,61 @@ export const Catch = ({ error }: ErrorComponentProps) => { {error.stack}
- ); -}; + ) +} -export const Pending = () =>
Loading from _root...
; +export const Pending = () =>
Loading from _root...
const TanStackRouterDevtools = import.meta.env.PROD ? () => null // Render nothing in production : lazy(() => // Lazy load in development - import("@tanstack/router-devtools").then((res) => ({ + import('@tanstack/router-devtools').then((res) => ({ default: res.TanStackRouterDevtools, // For Embedded Mode // default: res.TanStackRouterDevtoolsPanel })), - ); + ) export const Route = createRootRoute({ component: App, errorComponent: Catch, pendingComponent: Pending, -}); +}) export default function App() { - const { theme } = useCustomTheme(); + const { theme } = useCustomTheme() - const breakpoint = useBreakpoint(); + const breakpoint = useBreakpoint() - const setMemorizedPath = useSetAtom(memorizedRoutePathAtom); + const setMemorizedPath = useSetAtom(memorizedRoutePathAtom) const pathname = useLocation({ select: (location) => location.pathname, - }); + }) useEffect(() => { - if (pathname !== "/") { - setMemorizedPath(pathname as FileRouteTypes["fullPaths"]); + if (pathname !== '/') { + setMemorizedPath(pathname as FileRouteTypes['fullPaths']) } - }, [pathname, setMemorizedPath]); + }, [pathname, setMemorizedPath]) - const [isDrawer, setIsDrawer] = useAtom(atomIsDrawer); + const [isDrawer, setIsDrawer] = useAtom(atomIsDrawer) - useUpdater(); - useNyanpasuStorageSubscribers(); + useUpdater() + useNyanpasuStorageSubscribers() useEffect(() => { - setIsDrawer(breakpoint === "sm" || breakpoint === "xs"); - }, [breakpoint, setIsDrawer]); + setIsDrawer(breakpoint === 'sm' || breakpoint === 'xs') + }, [breakpoint, setIsDrawer]) useMount(() => { - const appWindow = getCurrentWebviewWindow(); + const appWindow = getCurrentWebviewWindow() Promise.all([ appWindow.show(), appWindow.unminimize(), appWindow.setFocus(), - ]).finally(() => emit("react_app_mounted")); - }); + ]).finally(() => emit('react_app_mounted')) + }) return ( - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/_layout.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/_layout.tsx index 880f322ba7..b38b236cf9 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/_layout.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/_layout.tsx @@ -2,26 +2,26 @@ import { createFileRoute, ErrorComponentProps, Outlet, -} from "@tanstack/react-router"; +} from '@tanstack/react-router' const Catch = ({ error }: ErrorComponentProps) => { return ( -
+

Oops!

Something went wrong... Caught at _layout error boundary.

{error.message}
- ); -}; + ) +} -const Pending = () =>
Loading from _layout...
; +const Pending = () =>
Loading from _layout...
-export const Route = createFileRoute("/_layout")({ +export const Route = createFileRoute('/_layout')({ component: Layout, errorComponent: Catch, pendingComponent: Pending, -}); +}) function Layout() { - return ; + return } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/connections.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/connections.tsx index 19af922308..c87aaac628 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/connections.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/connections.tsx @@ -1,54 +1,52 @@ -import { useThrottle } from "ahooks"; -import { lazy, Suspense, useDeferredValue, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { SearchTermCtx } from "@/components/connections/connection-search-term"; -import HeaderSearch from "@/components/connections/header-search"; -import { FilterAlt } from "@mui/icons-material"; -import { IconButton } from "@mui/material"; -import { BasePage } from "@nyanpasu/ui"; -import { createFileRoute, useBlocker } from "@tanstack/react-router"; +import { useThrottle } from 'ahooks' +import { lazy, Suspense, useDeferredValue, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { SearchTermCtx } from '@/components/connections/connection-search-term' +import HeaderSearch from '@/components/connections/header-search' +import { FilterAlt } from '@mui/icons-material' +import { IconButton } from '@mui/material' +import { BasePage } from '@nyanpasu/ui' +import { createFileRoute, useBlocker } from '@tanstack/react-router' -const Component = lazy( - () => import("@/components/connections/connection-page"), -); +const Component = lazy(() => import('@/components/connections/connection-page')) const ColumnFilterDialog = lazy( - () => import("@/components/connections/connections-column-filter"), -); + () => import('@/components/connections/connections-column-filter'), +) const ConnectionTotal = lazy( - () => import("@/components/connections/connections-total"), -); + () => import('@/components/connections/connections-total'), +) -export const Route = createFileRoute("/connections")({ +export const Route = createFileRoute('/connections')({ component: Connections, -}); +}) function Connections() { - const { t } = useTranslation(); + const { t } = useTranslation() - const [openColumnFilter, setOpenColumnFilter] = useState(false); + const [openColumnFilter, setOpenColumnFilter] = useState(false) - const [searchTerm, setSearchTerm] = useState(); - const throttledSearchTerm = useThrottle(searchTerm, { wait: 150 }); + const [searchTerm, setSearchTerm] = useState() + const throttledSearchTerm = useThrottle(searchTerm, { wait: 150 }) - const [mountTable, setMountTable] = useState(true); - const deferredMountTable = useDeferredValue(mountTable); + const [mountTable, setMountTable] = useState(true) + const deferredMountTable = useDeferredValue(mountTable) const { proceed } = useBlocker({ blockerFn: () => setMountTable(false), condition: !mountTable, - }); + }) useEffect(() => { if (!deferredMountTable) { - proceed(); + proceed() } - }, [proceed, deferredMountTable]); + }, [proceed, deferredMountTable]) return ( @@ -74,5 +72,5 @@ function Connections() { {mountTable && } - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx index 5a36f6ee38..77129ed37d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/dashboard.tsx @@ -1,21 +1,21 @@ -import { useTranslation } from "react-i18next"; -import DataPanel from "@/components/dashboard/data-panel"; -import HealthPanel from "@/components/dashboard/health-panel"; -import ProxyShortcuts from "@/components/dashboard/proxy-shortcuts"; -import ServiceShortcuts from "@/components/dashboard/service-shortcuts"; -import Grid from "@mui/material/Grid2"; -import { BasePage } from "@nyanpasu/ui"; -import { createFileRoute } from "@tanstack/react-router"; +import { useTranslation } from 'react-i18next' +import DataPanel from '@/components/dashboard/data-panel' +import HealthPanel from '@/components/dashboard/health-panel' +import ProxyShortcuts from '@/components/dashboard/proxy-shortcuts' +import ServiceShortcuts from '@/components/dashboard/service-shortcuts' +import Grid from '@mui/material/Grid2' +import { BasePage } from '@nyanpasu/ui' +import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute("/dashboard")({ +export const Route = createFileRoute('/dashboard')({ component: Dashboard, -}); +}) function Dashboard() { - const { t } = useTranslation(); + const { t } = useTranslation() return ( - + @@ -26,5 +26,5 @@ function Dashboard() { - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/index.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/index.tsx index 25f138c2d6..e97ffa580d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/index.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/index.tsx @@ -1,22 +1,22 @@ -import { useAtomValue } from "jotai"; -import { useEffect } from "react"; -import { memorizedRoutePathAtom } from "@/store"; -import { createFileRoute, useNavigate } from "@tanstack/react-router"; +import { useAtomValue } from 'jotai' +import { useEffect } from 'react' +import { memorizedRoutePathAtom } from '@/store' +import { createFileRoute, useNavigate } from '@tanstack/react-router' -export const Route = createFileRoute("/")({ +export const Route = createFileRoute('/')({ component: IndexPage, -}); +}) function IndexPage() { - const navigate = useNavigate(); - const memorizedNavigate = useAtomValue(memorizedRoutePathAtom); + const navigate = useNavigate() + const memorizedNavigate = useAtomValue(memorizedRoutePathAtom) useEffect(() => { navigate({ to: - memorizedNavigate && memorizedNavigate !== "/" + memorizedNavigate && memorizedNavigate !== '/' ? memorizedNavigate - : "/dashboard", - }); - }, [memorizedNavigate, navigate]); - return null; + : '/dashboard', + }) + }, [memorizedNavigate, navigate]) + return null } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/logs.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/logs.tsx index 155a7d9d70..68d8c586d1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/logs.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/logs.tsx @@ -1,28 +1,28 @@ -import { lazy, RefObject, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import LogHeader from "@/components/logs/los-header"; -import { BasePage } from "@nyanpasu/ui"; -import { createFileRoute } from "@tanstack/react-router"; +import { lazy, RefObject, useRef } from 'react' +import { useTranslation } from 'react-i18next' +import LogHeader from '@/components/logs/los-header' +import { BasePage } from '@nyanpasu/ui' +import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute("/logs")({ +export const Route = createFileRoute('/logs')({ component: LogPage, -}); +}) function LogPage() { - const { t } = useTranslation(); + const { t } = useTranslation() - const viewportRef = useRef(null); + const viewportRef = useRef(null) - const Component = lazy(() => import("@/components/logs/log-page")); + const Component = lazy(() => import('@/components/logs/log-page')) return ( } viewportRef={viewportRef} > } /> - ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/profiles.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/profiles.tsx index 8dd78cb10a..324b034cf6 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/profiles.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/profiles.tsx @@ -1,156 +1,154 @@ -import MdiTextBoxCheckOutline from "~icons/mdi/text-box-check-outline"; -import { useLockFn } from "ahooks"; -import { AnimatePresence, motion } from "framer-motion"; -import { useAtom } from "jotai"; -import { useMemo, useState, useTransition } from "react"; -import { useTranslation } from "react-i18next"; -import { useWindowSize } from "react-use"; -import { z } from "zod"; +import MdiTextBoxCheckOutline from '~icons/mdi/text-box-check-outline' +import { useLockFn } from 'ahooks' +import { AnimatePresence, motion } from 'framer-motion' +import { useAtom } from 'jotai' +import { useMemo, useState, useTransition } from 'react' +import { useTranslation } from 'react-i18next' +import { useWindowSize } from 'react-use' +import { z } from 'zod' import { atomChainsSelected, atomGlobalChainCurrent, -} from "@/components/profiles/modules/store"; -import NewProfileButton from "@/components/profiles/new-profile-button"; +} from '@/components/profiles/modules/store' +import NewProfileButton from '@/components/profiles/new-profile-button' import { AddProfileContext, AddProfileContextValue, -} from "@/components/profiles/profile-dialog"; -import ProfileItem from "@/components/profiles/profile-item"; -import ProfileSide from "@/components/profiles/profile-side"; -import { GlobalUpdatePendingContext } from "@/components/profiles/provider"; -import { QuickImport } from "@/components/profiles/quick-import"; -import RuntimeConfigDiffDialog from "@/components/profiles/runtime-config-diff-dialog"; -import { filterProfiles } from "@/components/profiles/utils"; -import { formatError } from "@/utils"; -import { message } from "@/utils/notification"; -import { Public, Update } from "@mui/icons-material"; -import { Badge, Button, CircularProgress, IconButton } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { Profile, updateProfile, useClash } from "@nyanpasu/interface"; -import { FloatingButton, SidePage } from "@nyanpasu/ui"; -import { createFileRoute, useLocation } from "@tanstack/react-router"; -import { zodSearchValidator } from "@tanstack/router-zod-adapter"; +} from '@/components/profiles/profile-dialog' +import ProfileItem from '@/components/profiles/profile-item' +import ProfileSide from '@/components/profiles/profile-side' +import { GlobalUpdatePendingContext } from '@/components/profiles/provider' +import { QuickImport } from '@/components/profiles/quick-import' +import RuntimeConfigDiffDialog from '@/components/profiles/runtime-config-diff-dialog' +import { filterProfiles } from '@/components/profiles/utils' +import { formatError } from '@/utils' +import { message } from '@/utils/notification' +import { Public, Update } from '@mui/icons-material' +import { Badge, Button, CircularProgress, IconButton } from '@mui/material' +import Grid from '@mui/material/Grid2' +import { Profile, updateProfile, useClash } from '@nyanpasu/interface' +import { FloatingButton, SidePage } from '@nyanpasu/ui' +import { createFileRoute, useLocation } from '@tanstack/react-router' +import { zodSearchValidator } from '@tanstack/router-zod-adapter' const profileSearchParams = z.object({ subscribeName: z.string().optional(), subscribeUrl: z.string().url().optional(), subscribeDesc: z.string().optional(), -}); +}) -export const Route = createFileRoute("/profiles")({ +export const Route = createFileRoute('/profiles')({ validateSearch: zodSearchValidator(profileSearchParams), component: ProfilePage, -}); +}) function ProfilePage() { - const { t } = useTranslation(); - const { getProfiles, getRuntimeLogs } = useClash(); + const { t } = useTranslation() + const { getProfiles, getRuntimeLogs } = useClash() const maxLogLevelTriggered = useMemo(() => { const currentProfileChains = getProfiles.data?.items?.find( // TODO: 支持多 Profile - (item) => getProfiles.data?.current[0] == item.uid, - )?.chain || []; + (item) => getProfiles.data?.current[0] === item.uid, + )?.chain || [] return Object.entries(getRuntimeLogs.data || {}).reduce( (acc, [key, value]) => { - const accKey = currentProfileChains.includes(key) - ? "current" - : "global"; - if (acc[accKey] == "error") { - return acc; + const accKey = currentProfileChains.includes(key) ? 'current' : 'global' + if (acc[accKey] === 'error') { + return acc } for (const log of value) { switch (log[0]) { - case "error": - return { ...acc, [accKey]: "error" }; - case "warn": - acc = { ...acc, [accKey]: "warn" }; - break; - case "info": - if (acc[accKey] != "warn") { - acc = { ...acc, [accKey]: "info" }; + case 'error': + return { ...acc, [accKey]: 'error' } + case 'warn': + acc = { ...acc, [accKey]: 'warn' } + break + case 'info': + if (acc[accKey] !== 'warn') { + acc = { ...acc, [accKey]: 'info' } } - break; + break } } - return acc; + return acc }, {} as { - global: undefined | "info" | "error" | "warn"; - current: undefined | "info" | "error" | "warn"; + global: undefined | 'info' | 'error' | 'warn' + current: undefined | 'info' | 'error' | 'warn' }, - ); - }, [getRuntimeLogs.data, getProfiles.data]); - const { profiles } = filterProfiles(getProfiles.data?.items); + ) + }, [getRuntimeLogs.data, getProfiles.data]) + const { profiles } = filterProfiles(getProfiles.data?.items) - const [globalChain, setGlobalChain] = useAtom(atomGlobalChainCurrent); + const [globalChain, setGlobalChain] = useAtom(atomGlobalChainCurrent) - const [chainsSelected, setChainsSelected] = useAtom(atomChainsSelected); + const [chainsSelected, setChainsSelected] = useAtom(atomChainsSelected) const handleGlobalChainClick = () => { - setChainsSelected(undefined); - setGlobalChain(!globalChain); - }; + setChainsSelected(undefined) + setGlobalChain(!globalChain) + } const onClickChains = (profile: Profile.Item) => { - setGlobalChain(false); + setGlobalChain(false) - if (chainsSelected == profile.uid) { - setChainsSelected(undefined); + if (chainsSelected === profile.uid) { + setChainsSelected(undefined) } else { - setChainsSelected(profile.uid); + setChainsSelected(profile.uid) } - }; + } const handleSideClose = () => { - setChainsSelected(undefined); - setGlobalChain(false); - }; + setChainsSelected(undefined) + setGlobalChain(false) + } - const [runtimeConfigViewerOpen, setRuntimeConfigViewerOpen] = useState(false); - const location = useLocation(); + const [runtimeConfigViewerOpen, setRuntimeConfigViewerOpen] = useState(false) + const location = useLocation() const addProfileCtxValue = useMemo(() => { if (!location.search || !location.search.subscribeUrl) { - return null; + return null } return { name: location.search.subscribeName!, desc: location.search.subscribeDesc!, url: location.search.subscribeUrl, - } satisfies AddProfileContextValue; - }, [location.search]); + } satisfies AddProfileContextValue + }, [location.search]) - const hasSide = globalChain || chainsSelected; + const hasSide = globalChain || chainsSelected - const { width } = useWindowSize(); + const { width } = useWindowSize() - const [globalUpdatePending, startGlobalUpdate] = useTransition(); + const [globalUpdatePending, startGlobalUpdate] = useTransition() const handleGlobalProfileUpdate = useLockFn(async () => { await startGlobalUpdate(async () => { const remoteProfiles = - profiles?.filter((item) => item.type == "remote") || []; - const updates: Array> = []; + profiles?.filter((item) => item.type === 'remote') || [] + const updates: Array> = [] for (const profile of remoteProfiles) { const options: Profile.Option = profile.option || { with_proxy: false, self_proxy: false, - }; + } - updates.push(updateProfile(profile.uid, options)); + updates.push(updateProfile(profile.uid, options)) } try { - await Promise.all(updates); + await Promise.all(updates) } catch (e) { message(`failed to update profiles: \n${formatError(e)}`, { - kind: "error", - }); + kind: 'error', + }) } - }); - }); + }) + }) return ( @@ -161,9 +159,9 @@ function ProfilePage() { { - setRuntimeConfigViewerOpen(true); + setRuntimeConfigViewerOpen(true) }} >
@@ -225,7 +223,7 @@ function ProfilePage() { onClickChains={onClickChains} selected={getProfiles.data?.current.includes(item.uid)} maxLogLevelTriggered={maxLogLevelTriggered} - chainsSelected={chainsSelected == item.uid} + chainsSelected={chainsSelected === item.uid} /> @@ -244,12 +242,12 @@ function ProfilePage() { (theme) => ({ backgroundColor: theme.palette.grey[200], boxShadow: 4, - "&:hover": { + '&:hover': { backgroundColor: theme.palette.grey[300], }, - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { backgroundColor: theme.palette.grey[800], - "&:hover": { + '&:hover': { backgroundColor: theme.palette.grey[700], }, }), @@ -263,5 +261,5 @@ function ProfilePage() {
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx index 55b6530b8b..bffdda331a 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/providers.tsx @@ -1,30 +1,30 @@ -import { useTranslation } from "react-i18next"; -import ProxiesProvider from "@/components/providers/proxies-provider"; -import RulesProvider from "@/components/providers/rules-provider"; -import UpdateProviders from "@/components/providers/update-providers"; -import UpdateProxiesProviders from "@/components/providers/update-proxies-providers"; -import { Chip } from "@mui/material"; -import Grid from "@mui/material/Grid2"; -import { useClashCore } from "@nyanpasu/interface"; -import { BasePage } from "@nyanpasu/ui"; -import { createFileRoute } from "@tanstack/react-router"; +import { useTranslation } from 'react-i18next' +import ProxiesProvider from '@/components/providers/proxies-provider' +import RulesProvider from '@/components/providers/rules-provider' +import UpdateProviders from '@/components/providers/update-providers' +import UpdateProxiesProviders from '@/components/providers/update-proxies-providers' +import { Chip } from '@mui/material' +import Grid from '@mui/material/Grid2' +import { useClashCore } from '@nyanpasu/interface' +import { BasePage } from '@nyanpasu/ui' +import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute("/providers")({ +export const Route = createFileRoute('/providers')({ component: ProvidersPage, -}); +}) function ProvidersPage() { - const { t } = useTranslation(); + const { t } = useTranslation() - const { getRulesProviders, getProxiesProviders } = useClashCore(); + const { getRulesProviders, getProxiesProviders } = useClashCore() return ( - +
@@ -54,7 +54,7 @@ function ProvidersPage() {
@@ -79,5 +79,5 @@ function ProvidersPage() { )}
- ); + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/proxies.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/proxies.tsx index 1b52dfcc18..b70a67afec 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/proxies.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/proxies.tsx @@ -1,19 +1,19 @@ -import { useAtom } from "jotai"; -import { RefObject, useEffect, useMemo, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import ContentDisplay from "@/components/base/content-display"; +import { useAtom } from 'jotai' +import { RefObject, useEffect, useMemo, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' +import ContentDisplay from '@/components/base/content-display' import { DelayButton, GroupList, NodeList, NodeListRef, -} from "@/components/proxies"; -import ProxyGroupName from "@/components/proxies/proxy-group-name"; -import ScrollCurrentNode from "@/components/proxies/scroll-current-node"; -import SortSelector from "@/components/proxies/sort-selector"; -import { proxyGroupAtom } from "@/store"; -import { proxiesFilterAtom } from "@/store/proxies"; -import { Check } from "@mui/icons-material"; +} from '@/components/proxies' +import ProxyGroupName from '@/components/proxies/proxy-group-name' +import ScrollCurrentNode from '@/components/proxies/scroll-current-node' +import SortSelector from '@/components/proxies/sort-selector' +import { proxyGroupAtom } from '@/store' +import { proxiesFilterAtom } from '@/store/proxies' +import { Check } from '@mui/icons-material' import { alpha, Box, @@ -21,19 +21,19 @@ import { ButtonGroup, TextField, useTheme, -} from "@mui/material"; -import { Clash, useClashCore, useNyanpasu } from "@nyanpasu/interface"; -import { cn, SidePage } from "@nyanpasu/ui"; -import { createFileRoute } from "@tanstack/react-router"; +} from '@mui/material' +import { Clash, useClashCore, useNyanpasu } from '@nyanpasu/interface' +import { cn, SidePage } from '@nyanpasu/ui' +import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute("/proxies")({ +export const Route = createFileRoute('/proxies')({ component: ProxyPage, -}); +}) function SideBar() { - const { palette } = useTheme(); - const [proxiesFilter, setProxiesFilter] = useAtom(proxiesFilterAtom); - const { t } = useTranslation(); + const { palette } = useTheme() + const [proxiesFilter, setProxiesFilter] = useAtom(proxiesFilterAtom) + const { t } = useTranslation() return ( setProxiesFilter(!e.target.value.trim().length ? null : e.target.value) } @@ -54,34 +54,34 @@ function SideBar() { backgroundColor: alpha(palette.primary.main, 0.1), fieldset: { - border: "none", + border: 'none', }, }, }} /> - ); + ) } function ProxyPage() { - const { t } = useTranslation(); + const { t } = useTranslation() - const { getCurrentMode, setCurrentMode } = useNyanpasu(); + const { getCurrentMode, setCurrentMode } = useNyanpasu() - const { data, updateGroupDelay } = useClashCore(); + const { data, updateGroupDelay } = useClashCore() - const [proxyGroup] = useAtom(proxyGroupAtom); + const [proxyGroup] = useAtom(proxyGroupAtom) const [group, setGroup] = - useState | string>>(); + useState | string>>() useEffect(() => { if (getCurrentMode.global) { - setGroup(data?.global); + setGroup(data?.global) } else if (getCurrentMode.direct) { - setGroup(data?.direct); + setGroup(data?.direct) } else { if (proxyGroup.selector !== null) { - setGroup(data?.groups[proxyGroup.selector]); + setGroup(data?.groups[proxyGroup.selector]) } } }, [ @@ -90,29 +90,29 @@ function ProxyPage() { getCurrentMode, data?.global, data?.direct, - ]); + ]) const handleDelayClick = async () => { - await updateGroupDelay(proxyGroup.selector as number); - }; + await updateGroupDelay(proxyGroup.selector as number) + } - const hasProxies = Boolean(data?.groups.length); + const hasProxies = Boolean(data?.groups.length) - const nodeListRef = useRef(null); + const nodeListRef = useRef(null) const Header = useMemo(() => { const handleSwitch = (key: string) => { - setCurrentMode(key); - }; + setCurrentMode(key) + } return ( {Object.entries(getCurrentMode).map(([key, enabled]) => ( - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/index.ts b/clash-nyanpasu/frontend/ui/src/materialYou/components/index.ts index 599ed129de..68875f1e33 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/index.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/index.ts @@ -1,12 +1,12 @@ -export * from "./baseCard"; -export * from "./baseDialog"; -export * from "./basePage"; -export * from "./expand"; -export * from "./expandMore"; -export * from "./floatingButton"; -export * from "./item"; -export * from "./kbd"; -export * from "./lazyImage"; -export * from "./loadingButton"; -export * from "./loadingSwitch"; -export * from "./sidePage"; +export * from './baseCard' +export * from './baseDialog' +export * from './basePage' +export * from './expand' +export * from './expandMore' +export * from './floatingButton' +export * from './item' +export * from './kbd' +export * from './lazyImage' +export * from './loadingButton' +export * from './loadingSwitch' +export * from './sidePage' diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/baseItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/baseItem.tsx index 2170be4f3e..cebecb59be 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/baseItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/baseItem.tsx @@ -1,13 +1,13 @@ -import { FC, memo, ReactNode } from "react"; -import { SxProps } from "@mui/material"; -import ListItem from "@mui/material/ListItem"; -import ListItemText from "@mui/material/ListItemText"; +import { FC, memo, ReactNode } from 'react' +import { SxProps } from '@mui/material' +import ListItem from '@mui/material/ListItem' +import ListItemText from '@mui/material/ListItemText' export interface BaseItemProps { - title: ReactNode; - children: ReactNode; - sxItem?: SxProps; - sxItemText?: SxProps; + title: ReactNode + children: ReactNode + sxItem?: SxProps + sxItemText?: SxProps } export const BaseItem: FC = memo(function BaseItem({ @@ -22,5 +22,5 @@ export const BaseItem: FC = memo(function BaseItem({ {children} - ); -}); + ) +}) diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/index.ts b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/index.ts index a24113ab6b..0d22756edd 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/index.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/index.ts @@ -1,4 +1,4 @@ -export * from "./switchItem"; -export * from "./menuItem"; -export * from "./numberItem"; -export * from "./textItem"; +export * from './switchItem' +export * from './menuItem' +export * from './numberItem' +export * from './textItem' diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/menuItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/menuItem.tsx index c3c074d16f..dd28633ee5 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/menuItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/menuItem.tsx @@ -1,15 +1,15 @@ -import { MenuItem as MuiMenuItem, Select, SxProps } from "@mui/material"; -import { BaseItem } from "./baseItem"; +import { MenuItem as MuiMenuItem, Select, SxProps } from '@mui/material' +import { BaseItem } from './baseItem' -type OptionValue = string | number | boolean; +type OptionValue = string | number | boolean export interface MenuItemProps { - label: string; - options: Record; - selected: OptionValue; - onSelected: (value: OptionValue) => void; - selectSx?: SxProps; - disabled?: boolean; + label: string + options: Record + selected: OptionValue + onSelected: (value: OptionValue) => void + selectSx?: SxProps + disabled?: boolean } /** @@ -45,9 +45,9 @@ export const MenuItem = ({ - ); -}; + ) +} -export default MenuItem; +export default MenuItem diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx index daee983905..828708fdab 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx @@ -1,6 +1,6 @@ -import { ChangeEvent, useMemo, useState } from "react"; -import { useTranslation } from "react-i18next"; -import Done from "@mui/icons-material/Done"; +import { ChangeEvent, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Done from '@mui/icons-material/Done' import { Box, Button, @@ -8,25 +8,25 @@ import { TextField, TextFieldProps, Typography, -} from "@mui/material"; -import { Expand } from "../expand"; -import { BaseItem } from "./baseItem"; +} from '@mui/material' +import { Expand } from '../expand' +import { BaseItem } from './baseItem' -export interface NumberItemprops { - label: string; - vaule: number; - checkEvent: (input: number) => boolean; - checkLabel: string; - onApply: (input: number) => void; - divider?: boolean; - textFieldProps?: TextFieldProps; +export interface NumberItemProps { + label: string + value: number + checkEvent: (input: number) => boolean + checkLabel: string + onApply: (input: number) => void + divider?: boolean + textFieldProps?: TextFieldProps } /** * @example * input > 65535 || input < 1} checkLabel="Port must be between 1 and 65535." onApply={(value) => { @@ -44,36 +44,36 @@ export interface NumberItemprops { */ export const NumberItem = ({ label, - vaule, + value, checkEvent, checkLabel, onApply, divider, textFieldProps, -}: NumberItemprops) => { - const { t } = useTranslation(); +}: NumberItemProps) => { + const { t } = useTranslation() - const [changed, setChanged] = useState(false); + const [changed, setChanged] = useState(false) - const [input, setInput] = useState(null); + const [input, setInput] = useState(null) const applyCheck = useMemo( () => checkEvent(input as number), [checkEvent, input], - ); + ) return ( <> ) => { - setInput(Number(e.target.value)); - setChanged(true); + setInput(Number(e.target.value)) + setChanged(true) }} {...textFieldProps} /> @@ -99,16 +99,16 @@ export const NumberItem = ({ startIcon={} disabled={applyCheck} onClick={() => { - onApply(input as number); - setChanged(false); + onApply(input as number) + setChanged(false) }} > - {t("Apply")} + {t('Apply')} {divider && } - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/switchItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/switchItem.tsx index 3b2849feb1..09b0a57bac 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/switchItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/switchItem.tsx @@ -1,18 +1,18 @@ -import { ChangeEvent, useState } from "react"; -import { SwitchProps } from "@mui/material"; -import LoadingSwitch from "../loadingSwitch"; -import { BaseItem } from "./baseItem"; +import { ChangeEvent, useState } from 'react' +import { SwitchProps } from '@mui/material' +import LoadingSwitch from '../loadingSwitch' +import { BaseItem } from './baseItem' interface Props extends SwitchProps { - label: string; + label: string onChange?: ( event: ChangeEvent, checked: boolean, - ) => Promise | void; + ) => Promise | void } export const SwitchItem = ({ label, onChange, ...switchProps }: Props) => { - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) const handleChange = async ( event: ChangeEvent, @@ -20,14 +20,14 @@ export const SwitchItem = ({ label, onChange, ...switchProps }: Props) => { ) => { if (onChange) { try { - setLoading(true); + setLoading(true) - await onChange(event, checked); + await onChange(event, checked) } finally { - setLoading(false); + setLoading(false) } } - }; + } return ( @@ -37,5 +37,5 @@ export const SwitchItem = ({ label, onChange, ...switchProps }: Props) => { {...switchProps} /> - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/textItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/textItem.tsx index 433e74651f..b03fb076a1 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/textItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/textItem.tsx @@ -1,18 +1,18 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; -import Done from "@mui/icons-material/Done"; -import Box from "@mui/material/Box"; -import Button from "@mui/material/Button"; -import ListItem from "@mui/material/ListItem"; -import TextField from "@mui/material/TextField"; -import { Expand } from "../expand"; +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import Done from '@mui/icons-material/Done' +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import ListItem from '@mui/material/ListItem' +import TextField from '@mui/material/TextField' +import { Expand } from '../expand' export interface TextItemProps { - value: string; - label: string; - onApply: (value: string) => void; - applyLabel?: string; - placeholder?: string; + value: string + label: string + onApply: (value: string) => void + applyLabel?: string + placeholder?: string } export const TextItem = ({ @@ -22,9 +22,9 @@ export const TextItem = ({ applyLabel, placeholder, }: TextItemProps) => { - const { t } = useTranslation(); + const { t } = useTranslation() - const [textString, setTextString] = useState(value); + const [textString, setTextString] = useState(value) return ( <> @@ -33,7 +33,7 @@ export const TextItem = ({ value={textString} label={label} variant="outlined" - sx={{ width: "100%" }} + sx={{ width: '100%' }} multiline onChange={(e) => setTextString(e.target.value)} placeholder={placeholder} @@ -47,10 +47,10 @@ export const TextItem = ({ startIcon={} onClick={() => onApply(textString)} > - {applyLabel ?? t("Apply")} + {applyLabel ?? t('Apply')} - ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.module.scss.d.ts b/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.module.scss.d.ts index bcd7b72bfa..fbbb242850 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.module.scss.d.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.module.scss.d.ts @@ -1,5 +1,5 @@ declare const classNames: { - readonly kbd: "kbd"; - readonly dark: "dark"; -}; -export default classNames; + readonly kbd: 'kbd' + readonly dark: 'dark' +} +export default classNames diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.tsx index 8f4c44de52..47b2e2a425 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/kbd/index.tsx @@ -1,24 +1,24 @@ -import { cn } from "@/utils"; -import { useTheme } from "@mui/material"; -import styles from "./index.module.scss"; +import { cn } from '@/utils' +import { useTheme } from '@mui/material' +import styles from './index.module.scss' export type Props = React.DetailedHTMLProps< React.HTMLAttributes, HTMLElement ->; +> export function Kbd({ className, children, ...rest }: Props) { - const theme = useTheme(); + const theme = useTheme() return ( {children} - ); + ) } diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/lazyImage/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/lazyImage/index.tsx index e13977735d..e7de52c17c 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/lazyImage/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/lazyImage/index.tsx @@ -1,32 +1,32 @@ -import { useState } from "react"; -import { cn } from "@/utils"; +import { useState } from 'react' +import { cn } from '@/utils' export interface LazyImageProps extends React.ImgHTMLAttributes { - loadingClassName?: string; + loadingClassName?: string } export function LazyImage({ className, loadingClassName, ...others }: LazyImageProps) { - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(true) return ( <>
setLoading(false)} - className={cn(className, loading ? "hidden" : "inline-block")} + className={cn(className, loading ? 'hidden' : 'inline-block')} /> - ); + ) } diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingButton/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingButton/index.tsx index 8acb10ad64..943178e555 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingButton/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingButton/index.tsx @@ -1,12 +1,12 @@ -import { useControllableValue } from "ahooks"; -import { MouseEventHandler } from "react"; +import { useControllableValue } from 'ahooks' +import { MouseEventHandler } from 'react' import MuiLoadingButton, { LoadingButtonProps as MuiLoadingButtonProps, -} from "@mui/lab/LoadingButton"; +} from '@mui/lab/LoadingButton' export interface LoadingButtonProps - extends Omit { - onClick?: MouseEventHandler; + extends Omit { + onClick?: MouseEventHandler } export const LoadingButton = ({ @@ -19,22 +19,20 @@ export const LoadingButton = ({ { defaultValue: false, }, - ); + ) const handleClick: MouseEventHandler = async (e) => { if (onClick) { - setPending(true); + setPending(true) try { - await onClick(e); + await onClick(e) } catch (error) { - console.error(error); + console.error(error) } finally { - setPending(false); + setPending(false) } } - }; + } - return ( - - ); -}; + return +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/index.tsx index d7d88ed91d..c64cd38e9c 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/index.tsx @@ -1,9 +1,9 @@ -import CircularProgress from "@mui/material/CircularProgress"; -import Switch, { SwitchProps } from "@mui/material/Switch"; -import style from "./style.module.scss"; +import CircularProgress from '@mui/material/CircularProgress' +import Switch, { SwitchProps } from '@mui/material/Switch' +import style from './style.module.scss' interface LoadingSwitchProps extends SwitchProps { - loading?: boolean; + loading?: boolean } /** @@ -26,11 +26,11 @@ export const LoadingSwitch = ({ ...props }: LoadingSwitchProps) => { return ( -
+
{loading && (
- ); -}; + ) +} -export default LoadingSwitch; +export default LoadingSwitch diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/style.module.scss.d.ts b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/style.module.scss.d.ts index cfcaa00728..138610fff1 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/style.module.scss.d.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/loadingSwitch/style.module.scss.d.ts @@ -1,6 +1,6 @@ declare const classNames: { - readonly "MDYSwitch-container": "MDYSwitch-container"; - readonly CircularProgress: "CircularProgress"; - readonly "CircularProgress-checked": "CircularProgress-checked"; -}; -export default classNames; + readonly 'MDYSwitch-container': 'MDYSwitch-container' + readonly CircularProgress: 'CircularProgress' + readonly 'CircularProgress-checked': 'CircularProgress-checked' +} +export default classNames diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/index.tsx index ba3fa86b88..592059cca3 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/index.tsx @@ -1,23 +1,23 @@ -import { motion } from "framer-motion"; -import { FC, ReactNode, Ref } from "react"; -import { cn } from "@/utils"; -import * as ScrollArea from "@radix-ui/react-scroll-area"; -import { BaseErrorBoundary } from "../basePage/baseErrorBoundary"; -import Header from "../basePage/header"; -import style from "./style.module.scss"; +import { motion } from 'framer-motion' +import { FC, ReactNode, Ref } from 'react' +import { cn } from '@/utils' +import * as ScrollArea from '@radix-ui/react-scroll-area' +import { BaseErrorBoundary } from '../basePage/baseErrorBoundary' +import Header from '../basePage/header' +import style from './style.module.scss' interface Props { - title?: ReactNode; - header?: ReactNode; - children?: ReactNode; - sideBar?: ReactNode; - side?: ReactNode; - sideClassName?: string; - portalRightRoot?: ReactNode; - noChildrenScroll?: boolean; - flexReverse?: boolean; - leftViewportRef?: Ref; - rightViewportRef?: Ref; + title?: ReactNode + header?: ReactNode + children?: ReactNode + sideBar?: ReactNode + side?: ReactNode + sideClassName?: string + portalRightRoot?: ReactNode + noChildrenScroll?: boolean + flexReverse?: boolean + leftViewportRef?: Ref + rightViewportRef?: Ref } export const SidePage: FC = ({ @@ -33,42 +33,42 @@ export const SidePage: FC = ({ rightViewportRef, }) => { const sideBarStyle = { - height: sideBar ? "calc(100% - 56px)" : undefined, - }; + height: sideBar ? 'calc(100% - 56px)' : undefined, + } return ( -
+
-
+
= ({ div]:!block", + style['Container-common'], + 'relative w-full [&>div]:!block', sideClassName, )} style={sideBarStyle} @@ -89,16 +89,16 @@ export const SidePage: FC = ({ @@ -108,12 +108,12 @@ export const SidePage: FC = ({ {portalRightRoot} div]:!block")} + className={cn('relative h-full w-full [&>div]:!block')} ref={rightViewportRef} > {children} @@ -132,5 +132,5 @@ export const SidePage: FC = ({
- ); -}; + ) +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/style.module.scss.d.ts b/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/style.module.scss.d.ts index a88fc73f39..ea148e75b9 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/style.module.scss.d.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/sidePage/style.module.scss.d.ts @@ -1,7 +1,7 @@ declare const classNames: { - readonly "MDYSidePage-Main": "MDYSidePage-Main"; - readonly "MDYSidePage-Container": "MDYSidePage-Container"; - readonly "Container-common": "Container-common"; - readonly "ScrollArea-Thumb": "ScrollArea-Thumb"; -}; -export default classNames; + readonly 'MDYSidePage-Main': 'MDYSidePage-Main' + readonly 'MDYSidePage-Container': 'MDYSidePage-Container' + readonly 'Container-common': 'Container-common' + readonly 'ScrollArea-Thumb': 'ScrollArea-Thumb' +} +export default classNames diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/createTheme.ts b/clash-nyanpasu/frontend/ui/src/materialYou/createTheme.ts index 183df2e0a0..531da2c41f 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/createTheme.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/createTheme.ts @@ -2,9 +2,9 @@ import { argbFromHex, hexFromArgb, themeFromSourceColor, -} from "@material/material-color-utilities"; -import { createTheme } from "@mui/material/styles"; -import createPalette from "@mui/material/styles/createPalette"; +} from '@material/material-color-utilities' +import { createTheme } from '@mui/material/styles' +import createPalette from '@mui/material/styles/createPalette' import { MuiButton, MuiButtonGroup, @@ -18,27 +18,27 @@ import { MuiMenu, MuiPaper, MuiSwitch, -} from "./themeComponents"; -import { MUI_BREAKPOINTS } from "./themeConsts.mjs"; +} from './themeComponents' +import { MUI_BREAKPOINTS } from './themeConsts.mjs' interface ThemeSchema { - primary_color: string; - secondary_color: string; - primary_text: string; - secondary_text: string; - info_color: string; - error_color: string; - warning_color: string; - success_color: string; - font_family?: string; + primary_color: string + secondary_color: string + primary_text: string + secondary_text: string + info_color: string + error_color: string + warning_color: string + success_color: string + font_family?: string } export const createMDYTheme = (themeSchema: ThemeSchema) => { const materialColor = themeFromSourceColor( argbFromHex(themeSchema.primary_color), - ); + ) - const generatePalette = (mode: "light" | "dark") => { + const generatePalette = (mode: 'light' | 'dark') => { return createPalette({ mode, primary: { @@ -56,21 +56,21 @@ export const createMDYTheme = (themeSchema: ThemeSchema) => { materialColor.schemes[mode].onSecondaryContainer, ), }, - }); - }; + }) + } const colorSchemes = { light: { - palette: generatePalette("light"), + palette: generatePalette('light'), }, dark: { - palette: generatePalette("dark"), + palette: generatePalette('dark'), }, - }; - console.log(colorSchemes); + } + console.log(colorSchemes) const theme = createTheme( { cssVariables: { - colorSchemeSelector: "class", + colorSchemeSelector: 'class', }, colorSchemes: { light: true, @@ -98,7 +98,7 @@ export const createMDYTheme = (themeSchema: ThemeSchema) => { { colorSchemes, }, - ); + ) - return theme; -}; + return theme +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/index.ts b/clash-nyanpasu/frontend/ui/src/materialYou/index.ts index d526efa6e2..4592cf8227 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/index.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/index.ts @@ -1,2 +1,2 @@ -export * from "./createTheme"; -export * from "./components"; +export * from './createTheme' +export * from './components' diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButton.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButton.ts index bca24cc3df..e9ad6997fb 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButton.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButton.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiButton: Components["MuiButton"] = { +export const MuiButton: Components['MuiButton'] = { styleOverrides: { root: { - borderRadius: "48px", + borderRadius: '48px', }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButtonGroup.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButtonGroup.ts index ee84f63233..2afc5df670 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButtonGroup.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiButtonGroup.ts @@ -1,24 +1,24 @@ -import { alpha, darken, Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { alpha, darken, Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiButtonGroup: Components["MuiButtonGroup"] = { +export const MuiButtonGroup: Components['MuiButtonGroup'] = { styleOverrides: { grouped: ({ theme }) => ({ fontWeight: 700, - height: "2.5em", - padding: "0 1.25em", + height: '2.5em', + padding: '0 1.25em', border: `1px solid ${darken(theme.palette.primary.main, 0.09)}`, color: darken(theme.palette.primary.main, 0.2), - "&.MuiButton-contained.MuiButton-colorPrimary": { - boxShadow: "none", + '&.MuiButton-contained.MuiButton-colorPrimary': { + boxShadow: 'none', border: `1px solid ${theme.palette.primary.mainChannel}`, backgroundColor: alpha(theme.palette.primary.main, 0.2), color: theme.palette.primary.main, - "&::before": { - content: "none", + '&::before': { + content: 'none', }, - "&:hover": { + '&:hover': { backgroundColor: alpha(theme.palette.primary.main, 0.3), }, }, @@ -27,33 +27,33 @@ export const MuiButtonGroup: Components["MuiButtonGroup"] = { borderTopLeftRadius: 48, borderBottomLeftRadius: 48, - "&.MuiButton-sizeSmall": { - paddingLeft: "1.5em", + '&.MuiButton-sizeSmall': { + paddingLeft: '1.5em', }, - "&.MuiButton-sizeMedium": { - paddingLeft: "20px", + '&.MuiButton-sizeMedium': { + paddingLeft: '20px', }, - "&.MuiButton-sizeLarge": { - paddingLeft: "26px", + '&.MuiButton-sizeLarge': { + paddingLeft: '26px', }, }, lastButton: { borderTopRightRadius: 48, borderBottomRightRadius: 48, - "&.MuiButton-sizeSmall": { - paddingRight: "1.5em", + '&.MuiButton-sizeSmall': { + paddingRight: '1.5em', }, - "&.MuiButton-sizeMedium": { - paddingRight: "20px", + '&.MuiButton-sizeMedium': { + paddingRight: '20px', }, - "&.MuiButton-sizeLarge": { - paddingRight: "26px", + '&.MuiButton-sizeLarge': { + paddingRight: '26px', }, }, }, -} satisfies Components["MuiButtonGroup"]; +} satisfies Components['MuiButtonGroup'] diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCard.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCard.ts index be2a5f8ffd..d17648e6a6 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCard.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCard.ts @@ -1,11 +1,11 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiCard: Components["MuiCard"] = { +export const MuiCard: Components['MuiCard'] = { defaultProps: { sx: { borderRadius: 6, elevation: 0, }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCardContent.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCardContent.ts index 8c01c240b6..7e43ae0078 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCardContent.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiCardContent.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiCardContent: Components["MuiCardContent"] = { +export const MuiCardContent: Components['MuiCardContent'] = { defaultProps: { sx: { padding: 3, }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialog.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialog.ts index a398205a42..585654aa35 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialog.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialog.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiDialog: Components["MuiDialog"] = { +export const MuiDialog: Components['MuiDialog'] = { styleOverrides: { paper: { borderRadius: 24, }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogActions.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogActions.ts index 78ddbba793..fdf73140c4 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogActions.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogActions.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiDialogActions: Components["MuiDialogActions"] = { +export const MuiDialogActions: Components['MuiDialogActions'] = { styleOverrides: { root: { padding: 24, }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogContent.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogContent.ts index b33b88e305..12d4072689 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogContent.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogContent.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiDialogContent: Components["MuiDialogContent"] = { +export const MuiDialogContent: Components['MuiDialogContent'] = { styleOverrides: { root: { - padding: "0 24px", + padding: '0 24px', }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogTitle.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogTitle.ts index 46e0cf0968..a4f757580e 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogTitle.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiDialogTitle.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiDialogTitle: Components["MuiDialogTitle"] = { +export const MuiDialogTitle: Components['MuiDialogTitle'] = { styleOverrides: { root: { padding: 24, }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiLinearProgress.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiLinearProgress.ts index d529ea710c..66436a0a8d 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiLinearProgress.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiLinearProgress.ts @@ -1,14 +1,14 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiLinearProgress: Components["MuiLinearProgress"] = { +export const MuiLinearProgress: Components['MuiLinearProgress'] = { styleOverrides: { root: { - height: "8px", - borderRadius: "8px", + height: '8px', + borderRadius: '8px', }, bar: { - borderRadius: "8px", + borderRadius: '8px', }, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiMenu.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiMenu.ts index c3edee8650..646342699c 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiMenu.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiMenu.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiMenu: Components["MuiMenu"] = { +export const MuiMenu: Components['MuiMenu'] = { styleOverrides: { paper: ({ theme }) => ({ boxShadow: `${theme.shadows[8]} !important`, }), }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiPaper.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiPaper.ts index bf65f87670..4cb75e8b06 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiPaper.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiPaper.ts @@ -1,10 +1,10 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' -export const MuiPaper: Components["MuiPaper"] = { +export const MuiPaper: Components['MuiPaper'] = { styleOverrides: { root: () => ({ - boxShadow: "none", + boxShadow: 'none', }), }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiSwitch.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiSwitch.ts index 5de4ec2ece..5c04c5ee3e 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiSwitch.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/MuiSwitch.ts @@ -1,52 +1,52 @@ -import { Theme } from "@mui/material"; -import { Components } from "@mui/material/styles/components"; -import type {} from "@mui/material/themeCssVarsAugmentation"; +import { Theme } from '@mui/material' +import { Components } from '@mui/material/styles/components' +import type {} from '@mui/material/themeCssVarsAugmentation' -export const MuiSwitch: Components["MuiSwitch"] = { +export const MuiSwitch: Components['MuiSwitch'] = { styleOverrides: { root: ({ theme }) => ({ padding: 0, margin: 0, - "& .Mui-checked": { - "& .MuiSwitch-thumb": { + '& .Mui-checked': { + '& .MuiSwitch-thumb': { color: theme.palette.grey.A100, }, }, - "&:has(.Mui-checked) .MuiSwitch-track::before": { + '&:has(.Mui-checked) .MuiSwitch-track::before': { opacity: 0, }, - "&:has(.Mui-disabled) .MuiSwitch-track": { - opacity: "0.5 !important", - cursor: "not-allowed", + '&:has(.Mui-disabled) .MuiSwitch-track': { + opacity: '0.5 !important', + cursor: 'not-allowed', }, variants: [ { props: { - size: "medium", + size: 'medium', }, style: { height: 32, - "& .MuiSwitch-switchBase": { - padding: "6px", + '& .MuiSwitch-switchBase': { + padding: '6px', }, - "& .MuiSwitch-thumb": { + '& .MuiSwitch-thumb': { width: 14, height: 14, margin: 3, }, - "& .Mui-checked": { - "&.MuiSwitch-switchBase": { - marginLeft: "6px", + '& .Mui-checked': { + '&.MuiSwitch-switchBase': { + marginLeft: '6px', }, - "& .MuiSwitch-thumb": { + '& .MuiSwitch-thumb': { width: 24, height: 24, margin: -2, @@ -56,27 +56,27 @@ export const MuiSwitch: Components["MuiSwitch"] = { }, { props: { - size: "small", + size: 'small', }, style: { height: 24, - "& .MuiSwitch-switchBase": { - padding: "3px", + '& .MuiSwitch-switchBase': { + padding: '3px', }, - "& .MuiSwitch-thumb": { + '& .MuiSwitch-thumb': { width: 12, height: 12, margin: 3, }, - "& .Mui-checked": { - "&.MuiSwitch-switchBase": { - marginLeft: "1px", + '& .Mui-checked': { + '&.MuiSwitch-switchBase': { + marginLeft: '1px', }, - "& .MuiSwitch-thumb": { + '& .MuiSwitch-thumb': { width: 17, height: 17, margin: 0, @@ -88,37 +88,37 @@ export const MuiSwitch: Components["MuiSwitch"] = { }), track: ({ theme }) => ({ - borderRadius: "48px", + borderRadius: '48px', backgroundColor: theme.palette.grey.A200, opacity: `1 !important`, - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { backgroundColor: theme.palette.grey.A700, opacity: `0.7 !important`, }), - "&::before": { + '&::before': { content: '""', border: `solid 2px ${theme.palette.grey.A700}`, - width: "100%", - height: "100%", + width: '100%', + height: '100%', opacity: 1, - position: "absolute", - borderRadius: "inherit", - boxSizing: "border-box", - transitionProperty: "opacity, background-color", - transitionTimingFunction: "linear", - transitionDuration: "100ms", + position: 'absolute', + borderRadius: 'inherit', + boxSizing: 'border-box', + transitionProperty: 'opacity, background-color', + transitionTimingFunction: 'linear', + transitionDuration: '100ms', }, }), thumb: ({ theme }) => ({ - boxShadow: "none", + boxShadow: 'none', color: theme.palette.grey.A700, - ...theme.applyStyles("dark", { + ...theme.applyStyles('dark', { backgroundColor: theme.palette.grey.A200, }), }), }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/index.ts b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/index.ts index 820fec9c81..9e9db9a335 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/index.ts +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeComponents/index.ts @@ -1,12 +1,12 @@ -export * from "./MuiButton"; -export * from "./MuiButtonGroup"; -export * from "./MuiPaper"; -export * from "./MuiCard"; -export * from "./MuiCardContent"; -export * from "./MuiSwitch"; -export * from "./MuiDialog"; -export * from "./MuiDialogActions"; -export * from "./MuiDialogContent"; -export * from "./MuiDialogTitle"; -export * from "./MuiLinearProgress"; -export * from "./MuiMenu"; +export * from './MuiButton' +export * from './MuiButtonGroup' +export * from './MuiPaper' +export * from './MuiCard' +export * from './MuiCardContent' +export * from './MuiSwitch' +export * from './MuiDialog' +export * from './MuiDialogActions' +export * from './MuiDialogContent' +export * from './MuiDialogTitle' +export * from './MuiLinearProgress' +export * from './MuiMenu' diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/themeConsts.mjs b/clash-nyanpasu/frontend/ui/src/materialYou/themeConsts.mjs index cfd1df8366..3e08d0e2cc 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/themeConsts.mjs +++ b/clash-nyanpasu/frontend/ui/src/materialYou/themeConsts.mjs @@ -7,4 +7,4 @@ export const MUI_BREAKPOINTS = { lg: 1200, xl: 1600, }, -}; +} diff --git a/clash-nyanpasu/frontend/ui/src/utils/cn.ts b/clash-nyanpasu/frontend/ui/src/utils/cn.ts index ba0e6b64d1..4b1566702b 100644 --- a/clash-nyanpasu/frontend/ui/src/utils/cn.ts +++ b/clash-nyanpasu/frontend/ui/src/utils/cn.ts @@ -1,4 +1,4 @@ -import clsx, { type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; +import clsx, { type ClassValue } from 'clsx' +import { twMerge } from 'tailwind-merge' -export const cn = (...classes: ClassValue[]) => twMerge(clsx(...classes)); +export const cn = (...classes: ClassValue[]) => twMerge(clsx(...classes)) diff --git a/clash-nyanpasu/frontend/ui/src/utils/event.ts b/clash-nyanpasu/frontend/ui/src/utils/event.ts index 8fdb5b3afc..96deeaae5f 100644 --- a/clash-nyanpasu/frontend/ui/src/utils/event.ts +++ b/clash-nyanpasu/frontend/ui/src/utils/event.ts @@ -1,6 +1,6 @@ export const cleanDeepClickEvent = ( - e: Pick, + e: Pick, ) => { - e.preventDefault(); - e.stopPropagation(); -}; + e.preventDefault() + e.stopPropagation() +} diff --git a/clash-nyanpasu/frontend/ui/src/utils/index.ts b/clash-nyanpasu/frontend/ui/src/utils/index.ts index b24a427fb8..837812a31a 100644 --- a/clash-nyanpasu/frontend/ui/src/utils/index.ts +++ b/clash-nyanpasu/frontend/ui/src/utils/index.ts @@ -1,2 +1,2 @@ -export { cn } from "./cn"; -export * from "./event"; +export { cn } from './cn' +export * from './event' diff --git a/clash-nyanpasu/frontend/ui/tsconfig.json b/clash-nyanpasu/frontend/ui/tsconfig.json index 9298da0821..86a262142e 100644 --- a/clash-nyanpasu/frontend/ui/tsconfig.json +++ b/clash-nyanpasu/frontend/ui/tsconfig.json @@ -25,5 +25,5 @@ "plugins": [{ "name": "typescript-plugin-css-modules" }], "outDir": "./dist", }, - "include": ["src"], + "include": ["vite.config.ts", "src/"], } diff --git a/clash-nyanpasu/frontend/ui/vite.config.ts b/clash-nyanpasu/frontend/ui/vite.config.ts index 006ab2a04c..e6c0cf05a5 100644 --- a/clash-nyanpasu/frontend/ui/vite.config.ts +++ b/clash-nyanpasu/frontend/ui/vite.config.ts @@ -1,25 +1,25 @@ -import { defineConfig } from "vite"; -import dts from "vite-plugin-dts"; -import tsconfigPaths from "vite-tsconfig-paths"; -import react from "@vitejs/plugin-react"; +import { defineConfig } from 'vite' +import dts from 'vite-plugin-dts' +import tsconfigPaths from 'vite-tsconfig-paths' +import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [dts({ rollupTypes: true }), react(), tsconfigPaths()], build: { lib: { - entry: "src/index.ts", - fileName: "index", - formats: ["es"], + entry: 'src/index.ts', + fileName: 'index', + formats: ['es'], }, rollupOptions: { - external: ["react", "react-dom", "@tauri-apps/api"], + external: ['react', 'react-dom', '@tauri-apps/api'], output: { globals: { - react: "React", - "react-dom": "ReactDOM", - OS_PLATFORM: "OS_PLATFORM", + react: 'React', + 'react-dom': 'ReactDOM', + OS_PLATFORM: 'OS_PLATFORM', }, }, }, }, -}); +}) diff --git a/clash-nyanpasu/knip.config.ts b/clash-nyanpasu/knip.config.ts index d3ac062511..ca1d8e0a1c 100644 --- a/clash-nyanpasu/knip.config.ts +++ b/clash-nyanpasu/knip.config.ts @@ -1,10 +1,10 @@ -import { KnipConfig } from "knip"; +import { KnipConfig } from 'knip' export default { entry: [ - "frontend/nyanpasu/src/main.tsx", - "frontend/nyanpasu/src/pages/**/*.tsx", - "scripts/*.{js,ts}", + 'frontend/nyanpasu/src/main.tsx', + 'frontend/nyanpasu/src/pages/**/*.tsx', + 'scripts/*.{js,ts}', ], - project: ["frontend/**/*.{ts,js,jsx,tsx}", "scripts/**/*.{js,ts}"], -} satisfies KnipConfig; + project: ['frontend/**/*.{ts,js,jsx,tsx}', 'scripts/**/*.{js,ts}'], +} satisfies KnipConfig diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index c2bc72b270..48d5432625 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,10 +2,10 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.0", - "mihomo_alpha": "alpha-e22b61e", + "mihomo_alpha": "alpha-3f6823b", "clash_rs": "v0.7.3", "clash_premium": "2023-09-05-gdcc8d87", - "clash_rs_alpha": "0.7.3-alpha+sha.e711fd9" + "clash_rs_alpha": "0.7.3-alpha+sha.7c07bed" }, "arch_template": { "mihomo": { @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2024-12-15T22:20:50.073Z" + "updated_at": "2024-12-16T22:20:47.148Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index b7c4854d0d..f970b776e1 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -59,18 +59,19 @@ "devDependencies": { "@commitlint/cli": "19.6.1", "@commitlint/config-conventional": "19.6.0", + "@eslint/compat": "1.2.4", "@ianvs/prettier-plugin-sort-imports": "4.4.0", "@tauri-apps/cli": "2.1.0", "@types/fs-extra": "11.0.4", "@types/lodash-es": "4.17.12", "@types/node": "22.10.2", - "@typescript-eslint/eslint-plugin": "8.18.0", - "@typescript-eslint/parser": "8.18.0", + "@typescript-eslint/eslint-plugin": "8.18.1", + "@typescript-eslint/parser": "8.18.1", "autoprefixer": "10.4.20", "conventional-changelog-conventionalcommits": "8.0.0", "cross-env": "7.0.3", "dedent": "1.5.3", - "eslint": "8.57.1", + "eslint": "9.17.0", "eslint-config-prettier": "9.1.0", "eslint-config-standard": "17.1.0", "eslint-import-resolver-alias": "1.1.2", @@ -80,10 +81,12 @@ "eslint-plugin-prettier": "5.2.1", "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.2", - "eslint-plugin-react-compiler": "0.0.0-experimental-fcabbc1-20241106", - "eslint-plugin-react-hooks": "4.6.2", + "eslint-plugin-react-compiler": "19.0.0-beta-df7b47d-20241124", + "eslint-plugin-react-hooks": "5.1.0", + "globals": "^15.13.0", "knip": "5.40.0", "lint-staged": "15.2.11", + "neostandard": "^0.12.0", "npm-run-all2": "7.0.1", "postcss": "8.4.49", "postcss-html": "1.7.0", @@ -102,7 +105,8 @@ "stylelint-scss": "6.10.0", "tailwindcss": "3.4.16", "tsx": "4.19.2", - "typescript": "5.7.2" + "typescript": "5.7.2", + "typescript-eslint": "8.18.0" }, "packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c", "engines": { diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index c0334d7846..7a861d39d6 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -24,6 +24,9 @@ importers: '@commitlint/config-conventional': specifier: 19.6.0 version: 19.6.0 + '@eslint/compat': + specifier: 1.2.4 + version: 1.2.4(eslint@9.17.0(jiti@2.4.1)) '@ianvs/prettier-plugin-sort-imports': specifier: 4.4.0 version: 4.4.0(prettier@3.4.2) @@ -40,11 +43,11 @@ importers: specifier: 22.10.2 version: 22.10.2 '@typescript-eslint/eslint-plugin': - specifier: 8.18.0 - version: 8.18.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) + specifier: 8.18.1 + version: 8.18.1(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) '@typescript-eslint/parser': - specifier: 8.18.0 - version: 8.18.0(eslint@8.57.1)(typescript@5.7.2) + specifier: 8.18.1 + version: 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) autoprefixer: specifier: 10.4.20 version: 10.4.20(postcss@8.4.49) @@ -58,47 +61,53 @@ importers: specifier: 1.5.3 version: 1.5.3(babel-plugin-macros@3.1.0) eslint: - specifier: 8.57.1 - version: 8.57.1 + specifier: 9.17.0 + version: 9.17.0(jiti@2.4.1) eslint-config-prettier: specifier: 9.1.0 - version: 9.1.0(eslint@8.57.1) + version: 9.1.0(eslint@9.17.0(jiti@2.4.1)) eslint-config-standard: specifier: 17.1.0 - version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1))(eslint-plugin-n@17.15.0(eslint@8.57.1))(eslint-plugin-promise@7.2.1(eslint@8.57.1))(eslint@8.57.1) + version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint-plugin-n@17.15.0(eslint@9.17.0(jiti@2.4.1)))(eslint-plugin-promise@7.2.1(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1)) eslint-import-resolver-alias: specifier: 1.1.2 - version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)) + version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))) eslint-plugin-html: specifier: 8.1.2 version: 8.1.2 eslint-plugin-import: specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1) + version: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-n: specifier: 17.15.0 - version: 17.15.0(eslint@8.57.1) + version: 17.15.0(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-prettier: specifier: 5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1))(prettier@3.4.2) eslint-plugin-promise: specifier: 7.2.1 - version: 7.2.1(eslint@8.57.1) + version: 7.2.1(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-react: specifier: 7.37.2 - version: 7.37.2(eslint@8.57.1) + version: 7.37.2(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-react-compiler: - specifier: 0.0.0-experimental-fcabbc1-20241106 - version: 0.0.0-experimental-fcabbc1-20241106(eslint@8.57.1) + specifier: 19.0.0-beta-df7b47d-20241124 + version: 19.0.0-beta-df7b47d-20241124(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-react-hooks: - specifier: 4.6.2 - version: 4.6.2(eslint@8.57.1) + specifier: 5.1.0 + version: 5.1.0(eslint@9.17.0(jiti@2.4.1)) + globals: + specifier: ^15.13.0 + version: 15.13.0 knip: specifier: 5.40.0 version: 5.40.0(@types/node@22.10.2)(typescript@5.7.2) lint-staged: specifier: 15.2.11 version: 15.2.11 + neostandard: + specifier: ^0.12.0 + version: 0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) npm-run-all2: specifier: 7.0.1 version: 7.0.1 @@ -156,6 +165,9 @@ importers: typescript: specifier: 5.7.2 version: 5.7.2 + typescript-eslint: + specifier: 8.18.0 + version: 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) frontend/interface: dependencies: @@ -303,8 +315,8 @@ importers: specifier: 11.14.0 version: 11.14.0(@types/react@19.0.1)(react@19.0.0) '@iconify/json': - specifier: 2.2.283 - version: 2.2.283 + specifier: 2.2.285 + version: 2.2.285 '@monaco-editor/react': specifier: 4.6.0 version: 4.6.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -316,7 +328,7 @@ importers: version: 1.89.2(@tanstack/react-router@1.89.2(@tanstack/router-generator@1.87.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/router-plugin': specifier: 1.87.13 - version: 1.87.13(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 1.87.13(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.2.0 version: 2.2.0 @@ -352,13 +364,13 @@ importers: version: 13.12.2 '@vitejs/plugin-legacy': specifier: 6.0.0 - version: 6.0.0(terser@5.36.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 6.0.0(terser@5.36.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) '@vitejs/plugin-react': specifier: 4.3.4 - version: 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) '@vitejs/plugin-react-swc': specifier: 3.7.2 - version: 3.7.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 3.7.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) change-case: specifier: 5.4.4 version: 5.4.4 @@ -380,7 +392,7 @@ importers: nanoid: specifier: 5.0.9 version: 5.0.9 - sass: + sass-embedded: specifier: 1.83.0 version: 1.83.0 shiki: @@ -400,16 +412,16 @@ importers: version: 13.12.0 vite: specifier: 6.0.3 - version: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + version: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) vite-plugin-sass-dts: specifier: 1.3.29 - version: 1.3.29(postcss@8.4.49)(prettier@3.4.2)(sass-embedded@1.78.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 1.3.29(postcss@8.4.49)(prettier@3.4.2)(sass-embedded@1.83.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) vite-plugin-svgr: specifier: 4.3.0 - version: 4.3.0(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 4.3.0(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) zod: specifier: 3.24.1 version: 3.24.1 @@ -445,7 +457,7 @@ importers: version: 19.0.1 '@vitejs/plugin-react': specifier: 4.3.4 - version: 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) ahooks: specifier: 3.8.4 version: 3.8.4(react@19.0.0) @@ -472,10 +484,10 @@ importers: version: 17.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) vite: specifier: 6.0.3 - version: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + version: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) devDependencies: '@emotion/react': specifier: 11.14.0 @@ -489,7 +501,7 @@ importers: d3-interpolate-path: specifier: 2.3.0 version: 2.3.0 - sass: + sass-embedded: specifier: 1.83.0 version: 1.83.0 tailwind-merge: @@ -500,7 +512,7 @@ importers: version: 5.1.0(typescript@5.7.2) vite-plugin-dts: specifier: 4.3.0 - version: 4.3.0(@types/node@22.10.2)(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) + version: 4.3.0(@types/node@22.10.2)(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)) scripts: dependencies: @@ -557,8 +569,8 @@ importers: specifier: 2.26.8 version: 2.26.8 undici: - specifier: 7.1.0 - version: 7.1.0 + specifier: 7.1.1 + version: 7.1.1 packages: @@ -723,11 +735,6 @@ packages: resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.1': - resolution: {integrity: sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.26.2': resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} engines: {node: '>=6.0.0'} @@ -768,13 +775,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-proposal-private-methods@7.18.6': - resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -1170,8 +1170,8 @@ packages: resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} - '@bufbuild/protobuf@1.10.0': - resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==} + '@bufbuild/protobuf@2.2.3': + resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==} '@commitlint/cli@19.6.1': resolution: {integrity: sha512-8hcyA6ZoHwWXC76BoC8qVOSr8xHy00LZhZpauiD0iO0VYbVhMnED0da85lTfIULxl7Lj4c6vZgF0Wu/ed1+jlQ==} @@ -1649,12 +1649,6 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/eslint-utils@4.4.1': resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1665,13 +1659,42 @@ packages: resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/compat@1.2.4': + resolution: {integrity: sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^9.10.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/config-array@0.19.1': + resolution: {integrity: sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.9.1': + resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.17.0': + resolution: {integrity: sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.5': + resolution: {integrity: sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.4': + resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} @@ -1695,18 +1718,28 @@ packages: '@fullhuman/postcss-purgecss@2.3.0': resolution: {integrity: sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/gitignore-to-minimatch@1.0.2': + resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} '@ianvs/prettier-plugin-sort-imports@4.4.0': resolution: {integrity: sha512-f4/e+/ANGk3tHuwRW0uh2YuBR50I4h1ZjGQ+5uD8sWfinHTivQsnieR5cz24t8M6Vx4rYvZ5v/IEKZhYpzQm9Q==} @@ -1717,14 +1750,14 @@ packages: '@vue/compiler-sfc': optional: true - '@iconify/json@2.2.283': - resolution: {integrity: sha512-Je/7d+MeStySzSz4DhRYWREd4+kpf+JW+884In115s1uuZcnRNH14avaSdf5SU6u1VOUN4HvpcG8fUaVvhg97w==} + '@iconify/json@2.2.285': + resolution: {integrity: sha512-oyH9NQ3aMdPuBl7miNcX7IavISwv5o07O6MBTQhW+X1mvyzrGwTxFf5bZmGYOsH3yB0MDGZkir3v+JiQE3UInA==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@iconify/utils@2.2.0': - resolution: {integrity: sha512-9A5eZQV9eKlNCXlI/SgYsGRS7YmGmB1oAsRpNVIYBmIzGJRgH+hfG+lo4069s+GFWFNnBAtDg10c53vQZBLfnA==} + '@iconify/utils@2.2.1': + resolution: {integrity: sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -2006,6 +2039,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + '@octokit/app@15.1.0': resolution: {integrity: sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg==} engines: {node: '>= 18'} @@ -2511,6 +2548,12 @@ packages: engines: {node: '>=8.10'} hasBin: true + '@stylistic/eslint-plugin@2.11.0': + resolution: {integrity: sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} @@ -2980,9 +3023,6 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -3086,6 +3126,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/eslint-plugin@8.18.1': + resolution: {integrity: sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/parser@8.18.0': resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3093,10 +3141,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/parser@8.18.1': + resolution: {integrity: sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/scope-manager@8.18.0': resolution: {integrity: sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.18.1': + resolution: {integrity: sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/type-utils@8.18.0': resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3104,16 +3163,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/type-utils@8.18.1': + resolution: {integrity: sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/types@8.18.0': resolution: {integrity: sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.18.1': + resolution: {integrity: sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.18.0': resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/typescript-estree@8.18.1': + resolution: {integrity: sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@8.18.0': resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3121,10 +3197,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@8.18.1': + resolution: {integrity: sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/visitor-keys@8.18.0': resolution: {integrity: sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.18.1': + resolution: {integrity: sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -3199,11 +3286,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -3640,6 +3722,9 @@ packages: colorize-template@1.0.0: resolution: {integrity: sha512-beJ9v9RjpbYZ8OdwJgIRZD3YUkZPXmi1MK+yX0J24UupKVHa9yk0jiARgt2i6MBX6AKjYA0SNsBn65bUPuVQiw==} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -3769,6 +3854,10 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + crypto-random-string@1.0.0: resolution: {integrity: sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==} engines: {node: '>=4'} @@ -4297,6 +4386,19 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + eslint-import-resolver-typescript@3.7.0: + resolution: {integrity: sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + eslint-module-utils@2.12.0: resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} @@ -4328,6 +4430,12 @@ packages: resolution: {integrity: sha512-pbRchDV2SmqbCi/Ev/q3aAikzG9BcFe0IjjqjtMn8eTLq71ZUggyJB6CDmuwGAXmYZHrXI12XTfCqvgcnPRqGw==} engines: {node: '>=16.0.0'} + eslint-plugin-import-x@4.5.0: + resolution: {integrity: sha512-l0OTfnPF8RwmSXfjT75N8d6ZYLVrVYWpaGlgvVkVqFERCI5SyBfDP7QEMr3kt0zWi2sOa9EQ47clbdFsHkF83Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + eslint-plugin-import@2.31.0: resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} @@ -4364,17 +4472,17 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-react-compiler@0.0.0-experimental-fcabbc1-20241106: - resolution: {integrity: sha512-lP00yCyYRWvqGAe4N2iPBSx3lh+cl1jUpO6AefwNw8/zO4Mek4gNUfD0FXvBOmuFoP+/9LfsqGFFDCulK2xiaA==} + eslint-plugin-react-compiler@19.0.0-beta-df7b47d-20241124: + resolution: {integrity: sha512-82PfnllC8jP/68KdLAbpWuYTcfmtGLzkqy2IW85WopKMTr+4rdQpp+lfliQ/QE79wWrv/dRoADrk3Pdhq25nTw==} engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} peerDependencies: eslint: '>=7' - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + eslint-plugin-react-hooks@5.1.0: + resolution: {integrity: sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 eslint-plugin-react@7.37.2: resolution: {integrity: sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==} @@ -4382,9 +4490,9 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} @@ -4394,19 +4502,23 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - 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. + eslint@9.17.0: + resolution: {integrity: sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true esniff@2.0.1: resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} engines: {node: '>=0.10'} - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} @@ -4506,9 +4618,9 @@ packages: engines: {node: '>= 0.4.0'} hasBin: true - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} file-entry-cache@9.1.0: resolution: {integrity: sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==} @@ -4533,9 +4645,9 @@ packages: resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} engines: {node: '>=18'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flat-cache@5.0.0: resolution: {integrity: sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==} @@ -4689,12 +4801,8 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globals@15.11.0: - resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} globals@15.13.0: @@ -4780,11 +4888,11 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - hermes-estree@0.20.1: - resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - hermes-parser@0.20.1: - resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} highlight-words@2.0.0: resolution: {integrity: sha512-If5n+IhSBRXTScE7wl16VPmd+44Vy7kof24EdqhjsZsDuHikpv1OCagVcJFpB4fS4UPUniedlWqrjIO8vWOsIQ==} @@ -4876,9 +4984,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - immutable@4.3.5: - resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} - immutable@5.0.2: resolution: {integrity: sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==} @@ -4991,6 +5096,9 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} + is-bun-module@1.3.0: + resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -5097,10 +5205,6 @@ packages: resolution: {integrity: sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==} engines: {node: '>=0.10.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -5751,6 +5855,13 @@ packages: engines: {node: '>= 4.4.x'} hasBin: true + neostandard@0.12.0: + resolution: {integrity: sha512-MvtiRhevDzE+oqQUxFvDsEmipzy3erNmnz5q5TG9M8xZ30n86rt4PxGP9jgocGIZr1105OgPZNlK2FQEtb2Vng==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + eslint: ^9.0.0 + next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} @@ -6019,6 +6130,10 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + peowly@1.3.2: + resolution: {integrity: sha512-BYIrwr8JCXY49jUZscgw311w9oGEKo7ux/s+BxrhKTQbiQ0iYNdZNJ5LgagaeercQdFHwnR7Z5IxxFWVQ+BasQ==} + engines: {node: '>=18.6.0'} + picocolors@0.2.1: resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} @@ -6570,11 +6685,6 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@5.0.9: resolution: {integrity: sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==} engines: {node: 14 >=14.20 || 16 >=16.20 || >=18} @@ -6628,128 +6738,128 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass-embedded-android-arm64@1.78.0: - resolution: {integrity: sha512-2sAr11EgwPudAuyk4Ite+fWGYJspiFSiZDU2D8/vjjI7BaB9FG6ksYqww3svoMMnjPUWBCjKPDELpZTxViLJbw==} + sass-embedded-android-arm64@1.83.0: + resolution: {integrity: sha512-GBiCvM4a2rkWBLdYDxI6XYnprfk5U5c81g69RC2X6kqPuzxzx8qTArQ9M6keFK4+iDQ5N9QTwFCr0KbZTn+ZNQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [android] - sass-embedded-android-arm@1.78.0: - resolution: {integrity: sha512-YM6nrmKsj+ImaSTd96F+jzbWSbhPkRN4kedbLgIJ5FsILNa9NAqhmrCQz9pdcjuAhyfxWImdUACsT23CPGENZQ==} + sass-embedded-android-arm@1.83.0: + resolution: {integrity: sha512-uwFSXzJlfbd4Px189xE5l+cxN8+TQpXdQgJec7TIrb4HEY7imabtpYufpVdqUVwT1/uiis5V4+qIEC4Vl5XObQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [android] - sass-embedded-android-ia32@1.78.0: - resolution: {integrity: sha512-TyJOo4TgnHpOfC/PfqCBqd+jGRanWoRd4Br/0KAfIvaIFjTGIPdk26vUyDVugV1J8QUEY4INGE8EXAuDeRldUQ==} + sass-embedded-android-ia32@1.83.0: + resolution: {integrity: sha512-5ATPdGo2SICqAhiJl/Z8KQ23zH4sGgobGgux0TnrNtt83uHZ+r+To/ubVJ7xTkZxed+KJZnIpolGD8dQyQqoTg==} engines: {node: '>=14.0.0'} cpu: [ia32] os: [android] - sass-embedded-android-riscv64@1.78.0: - resolution: {integrity: sha512-wwajpsVRuhb7ixrkA3Yu60V2LtROYn45PIYeda30/MrMJi9k3xEqHLhodTexFm6wZoKclGSDZ6L9U5q0XyRKiQ==} + sass-embedded-android-riscv64@1.83.0: + resolution: {integrity: sha512-aveknUOB8GZewOzVn2Uwk+DKcncTR50Q6vtzslNMGbYnxtgQNHzy8A1qVEviNUruex+pHofppeMK4iMPFAbiEQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [android] - sass-embedded-android-x64@1.78.0: - resolution: {integrity: sha512-k5l66PO0LgSHMDbDzAQ/vqrXMlJ3r42ZHJA8MJvUbA6sQxTzDS381V7L+EhOATwyI225j2FhEeTHW6rr4WBQzA==} + sass-embedded-android-x64@1.83.0: + resolution: {integrity: sha512-WqIay/72ncyf9Ph4vS742J3a73wZihWmzFUwpn1OD6lme1Aj4eWzWIve5IVnlTEJgcZcDHu6ECID9IZgehJKoA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [android] - sass-embedded-darwin-arm64@1.78.0: - resolution: {integrity: sha512-3JaxceFSR6N+a22hPYYkj1p45eBaWTt/M8MPTbfzU3TGZrU9bmRX7WlUVtXTo1yYI2iMf22nCv0PQ5ExFF3FMQ==} + sass-embedded-darwin-arm64@1.83.0: + resolution: {integrity: sha512-XQl9QqgxFFIPm/CzHhmppse5o9ocxrbaAdC2/DAnlAqvYWBBtgFqPjGoYlej13h9SzfvNoogx+y9r+Ap+e+hYg==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [darwin] - sass-embedded-darwin-x64@1.78.0: - resolution: {integrity: sha512-UMTijqE3fJ8vEaaD7GPG7G3GsHuPKOdpS8vuA2v2uwO3BPFp/rEKah66atvGqvGO+0JYApkSv0YTnnexSrkHIQ==} + sass-embedded-darwin-x64@1.83.0: + resolution: {integrity: sha512-ERQ7Tvp1kFOW3ux4VDFIxb7tkYXHYc+zJpcrbs0hzcIO5ilIRU2tIOK1OrNwrFO6Qxyf7AUuBwYKLAtIU/Nz7g==} engines: {node: '>=14.0.0'} cpu: [x64] os: [darwin] - sass-embedded-linux-arm64@1.78.0: - resolution: {integrity: sha512-juMIMpp3DIAiQ842y+boqh0u2SjN4m3mDKrDfMuBznj8DSQoy9J/3e4hLh3g+p0/j83WuROu5nNoYxm2Xz8rww==} + sass-embedded-linux-arm64@1.83.0: + resolution: {integrity: sha512-syEAVTJt4qhaMLxrSwOWa46zdqHJdnqJkLUK+t9aCr8xqBZLPxSUeIGji76uOehQZ1C+KGFj6n9xstHN6wzOJw==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-arm@1.78.0: - resolution: {integrity: sha512-JafT+Co0RK8oO3g9TfVRuG7tkYeh35yDGTgqCFxLrktnkiw5pmIagCfpjxk5GBcSfJMOzhCgclTCDJWAuHGuMQ==} + sass-embedded-linux-arm@1.83.0: + resolution: {integrity: sha512-baG9RYBJxUFmqwDNC9h9ZFElgJoyO3jgHGjzEZ1wHhIS9anpG+zZQvO8bHx3dBpKEImX+DBeLX+CxsFR9n81gQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-ia32@1.78.0: - resolution: {integrity: sha512-Gy8GW5g6WX9t8CT2Dto5AL6ikB+pG7aAXWXvfu3RFHktixSwSbyy6CeGqSk1t0xyJCFkQQA/V8HU9bNdeHiBxg==} + sass-embedded-linux-ia32@1.83.0: + resolution: {integrity: sha512-RRBxQxMpoxu5+XcSSc6QR/o9asEwUzR8AbCS83RaXcdTIHTa/CccQsiAoDDoPlRsMTLqnzs0LKL4CfOsf7zBbA==} engines: {node: '>=14.0.0'} cpu: [ia32] os: [linux] - sass-embedded-linux-musl-arm64@1.78.0: - resolution: {integrity: sha512-Lu/TlRHbe9aJY7B7PwWCJz7pTT5Rc50VkApWEmPiU/nu0mGbSpg0Xwar6pNeG8+98ubgKKdRb01N3bvclf5a4A==} + sass-embedded-linux-musl-arm64@1.83.0: + resolution: {integrity: sha512-Y7juhPHClUO2H5O+u+StRy6SEAcwZ+hTEk5WJdEmo1Bb1gDtfHvJaWB/iFZJ2tW0W1e865AZeUrC4OcOFjyAQA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-musl-arm@1.78.0: - resolution: {integrity: sha512-DUVXtcsfsiOJ2Zwp4Y3T6KZWX8h0gWpzmFUrx+gSIbg67vV8Ww2DWMjWRwqLe7HOLTYBegMBYpMgMgZiPtXhIA==} + sass-embedded-linux-musl-arm@1.83.0: + resolution: {integrity: sha512-Yc7u2TelCfBab+PRob9/MNJFh3EooMiz4urvhejXkihTiKSHGCv5YqDdtWzvyb9tY2Jb7YtYREVuHwfdVn3dTQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-musl-ia32@1.78.0: - resolution: {integrity: sha512-1E5ywUnq6MRPAecr2r/vDOBr93wXyculEmfyF5JRG8mUufMaxGIhfx64OQE6Drjs+EDURcYZ+Qcg6/ubJWqhcw==} + sass-embedded-linux-musl-ia32@1.83.0: + resolution: {integrity: sha512-arQeYwGmwXV8byx5G1PtSzZWW1jbkfR5qrIHMEbTFSAvAxpqjgSvCvrHMOFd73FcMxVaYh4BX9LQNbKinkbEdg==} engines: {node: '>=14.0.0'} cpu: [ia32] os: [linux] - sass-embedded-linux-musl-riscv64@1.78.0: - resolution: {integrity: sha512-YvQEvX7ctn5BwC79+HBagDYIciEkwcl2NLgoydmEsBO/0+ncMKSGnjsn/iRzErbq1KJNyjGEni8eSHlrtQI1vQ==} + sass-embedded-linux-musl-riscv64@1.83.0: + resolution: {integrity: sha512-E6uzlIWz59rut+Z3XR6mLG915zNzv07ISvj3GUNZENdHM7dF8GQ//ANoIpl5PljMQKp89GnYdvo6kj2gnaBf/g==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-musl-x64@1.78.0: - resolution: {integrity: sha512-azdUcZZvZmtUBslIKr2/l4aQrTX7BvO96TD0GLdWz9vuXZrokYm09AJZEnb5j6Pk5I4Xr0yM6BG1Vgcbzqi5Zg==} + sass-embedded-linux-musl-x64@1.83.0: + resolution: {integrity: sha512-eAMK6tyGqvqr21r9g8BnR3fQc1rYFj85RGduSQ3xkITZ6jOAnOhuU94N5fwRS852Hpws0lXhET+7JHXgg3U18w==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-linux-riscv64@1.78.0: - resolution: {integrity: sha512-g8M6vqHMjZUoH9C1WJsgwu+qmwdJAAMDaJTM1emeAScUZMTaQGzm+Q6C5oSGnAGR3XLT/drgbHhbmruXDgkdeQ==} + sass-embedded-linux-riscv64@1.83.0: + resolution: {integrity: sha512-Ojpi78pTv02sy2fUYirRGXHLY3fPnV/bvwuC2i5LwPQw2LpCcFyFTtN0c5h4LJDk9P6wr+/ZB/JXU8tHIOlK+Q==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-x64@1.78.0: - resolution: {integrity: sha512-m997ThzpMwql4u6LzZCoHPIQkgK6bbLPLc7ydemo2Wusqzh6j8XAGxVT5oANp6s2Dmj+yh49pKDozal+tzEX9w==} + sass-embedded-linux-x64@1.83.0: + resolution: {integrity: sha512-3iLjlXdoPfgZRtX4odhRvka1BQs5mAXqfCtDIQBgh/o0JnGPzJIWWl9bYLpHxK8qb+uyVBxXYgXpI0sCzArBOw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-win32-arm64@1.78.0: - resolution: {integrity: sha512-qTLIIC5URYRmeuYYllfoL0K1cHSUd+f3sFHAA6fjtdgf288usd6ToCbWpuFb0BtVceEfGQX8lEp+teOG7n7Quw==} + sass-embedded-win32-arm64@1.83.0: + resolution: {integrity: sha512-iOHw/8/t2dlTW3lOFwG5eUbiwhEyGWawivlKWJ8lkXH7fjMpVx2VO9zCFAm8RvY9xOHJ9sf1L7g5bx3EnNP9BQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [win32] - sass-embedded-win32-ia32@1.78.0: - resolution: {integrity: sha512-BrOWh18T6Y9xgCokGXElEnd8j03fO4W83bwJ9wHRRkrQWaeHtHs3XWW0fX1j2brngWUTjU+jcYUijWF1Z60krw==} + sass-embedded-win32-ia32@1.83.0: + resolution: {integrity: sha512-2PxNXJ8Pad4geVcTXY4rkyTr5AwbF8nfrCTDv0ulbTvPhzX2mMKEGcBZUXWn5BeHZTBc6whNMfS7d5fQXR9dDQ==} engines: {node: '>=14.0.0'} cpu: [ia32] os: [win32] - sass-embedded-win32-x64@1.78.0: - resolution: {integrity: sha512-C14iFDJd7oGhmQehRiEL7GtzMmLwubcDqsBarQ+u9LbHoDlUQfIPd7y8mVtNgtxJCdrAO/jc5qR4C+85yE3xPQ==} + sass-embedded-win32-x64@1.83.0: + resolution: {integrity: sha512-muBXkFngM6eLTNqOV0FQi7Dv9s+YRQ42Yem26mosdan/GmJQc81deto6uDTgrYn+bzFNmiXcOdfm+0MkTWK3OQ==} engines: {node: '>=14.0.0'} cpu: [x64] os: [win32] - sass-embedded@1.78.0: - resolution: {integrity: sha512-NR2kvhWVFABmBm0AqgFw9OweQycs0Qs+/teJ9Su+BUY7up+f8S5F/Zi+7QtAqJlewsQyUNfzm1vRuM+20lBwRQ==} + sass-embedded@1.83.0: + resolution: {integrity: sha512-/8cYZeL39evUqe0o//193na51Q1VWZ61qhxioQvLJwOtWIrX+PgNhCyD8RSuTtmzc4+6+waFZf899bfp/MCUwA==} engines: {node: '>=16.0.0'} hasBin: true @@ -6921,6 +7031,9 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stable-hash@0.0.4: + resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + stack-generator@2.0.10: resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} @@ -7129,6 +7242,14 @@ packages: peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + synckit@0.9.1: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7180,9 +7301,6 @@ packages: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -7284,10 +7402,6 @@ packages: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - type@2.7.2: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} @@ -7310,6 +7424,13 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typescript-eslint@8.18.0: + resolution: {integrity: sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + typescript-plugin-css-modules@5.1.0: resolution: {integrity: sha512-6h+sLBa4l+XYSTn/31vZHd/1c3SvAbLpobY6FxDiUOHJQG1eD9Gh3eCs12+Eqc+TCOAdxcO+zAPvUq0jBfdciw==} peerDependencies: @@ -7338,8 +7459,8 @@ packages: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - undici@7.1.0: - resolution: {integrity: sha512-3+mdX2R31khuLCm2mKExSlMdJsfol7bJkIMH80tdXA74W34rT1jKemUTlYR7WY3TqsV4wfOgpatWmmB2Jl1+5g==} + undici@7.1.1: + resolution: {integrity: sha512-WZkQ6eH9f5ZT93gaIffsbUaDpBwjbpvmMbfaEhOnbdUneurTESeRxwPGwjI28mRFESH3W3e8Togijh37ptOQqA==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -8036,10 +8157,6 @@ snapshots: '@babel/template': 7.25.9 '@babel/types': 7.26.3 - '@babel/parser@7.26.1': - dependencies: - '@babel/types': 7.26.3 - '@babel/parser@7.26.2': dependencies: '@babel/types': 7.26.3 @@ -8083,14 +8200,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -8573,7 +8682,7 @@ snapshots: '@babel/parser': 7.26.3 '@babel/template': 7.25.9 '@babel/types': 7.26.3 - debug: 4.4.0 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -8606,7 +8715,7 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@bufbuild/protobuf@1.10.0': {} + '@bufbuild/protobuf@2.2.3': {} '@commitlint/cli@19.6.1(@types/node@22.10.2)(typescript@5.7.2)': dependencies: @@ -9015,24 +9124,37 @@ snapshots: '@esbuild/win32-x64@0.24.0': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0(jiti@2.4.1))': dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.11.0': {} - '@eslint/eslintrc@2.1.4': + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/compat@1.2.4(eslint@9.17.0(jiti@2.4.1))': + optionalDependencies: + eslint: 9.17.0(jiti@2.4.1) + + '@eslint/config-array@0.19.1': + dependencies: + '@eslint/object-schema': 2.1.5 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.9.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 debug: 4.4.0 - espree: 9.6.1 - globals: 13.24.0 + espree: 10.3.0 + globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -9041,7 +9163,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/js@9.17.0': {} + + '@eslint/object-schema@2.1.5': {} + + '@eslint/plugin-kit@0.2.4': + dependencies: + levn: 0.4.1 '@fastify/busboy@2.1.1': {} @@ -9067,17 +9195,20 @@ snapshots: postcss: 7.0.32 purgecss: 2.3.0 - '@humanwhocodes/config-array@0.13.0': + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/gitignore-to-minimatch@1.0.2': {} '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.1': {} '@ianvs/prettier-plugin-sort-imports@4.4.0(prettier@3.4.2)': dependencies: @@ -9090,14 +9221,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.283': + '@iconify/json@2.2.285': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 '@iconify/types@2.0.0': {} - '@iconify/utils@2.2.0': + '@iconify/utils@2.2.1': dependencies: '@antfu/install-pkg': 0.4.1 '@antfu/utils': 0.7.10 @@ -9392,6 +9523,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@nolyfill/is-core-module@1.0.39': {} + '@octokit/app@15.1.0': dependencies: '@octokit/auth-app': 7.1.0 @@ -9744,7 +9877,7 @@ snapshots: '@rollup/pluginutils@5.1.0(rollup@4.27.4)': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: @@ -9883,6 +10016,18 @@ snapshots: ignore: 5.3.2 p-map: 4.0.0 + '@stylistic/eslint-plugin@2.11.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + eslint: 9.17.0(jiti@2.4.1) + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + estraverse: 5.3.0 + picomatch: 4.0.2 + transitivePeerDependencies: + - supports-color + - typescript + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -10063,7 +10208,7 @@ snapshots: tsx: 4.19.2 zod: 3.24.1 - '@tanstack/router-plugin@1.87.13(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': + '@tanstack/router-plugin@1.87.13(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.3 @@ -10084,7 +10229,7 @@ snapshots: unplugin: 1.16.0 zod: 3.24.1 optionalDependencies: - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - supports-color @@ -10364,8 +10509,6 @@ snapshots: dependencies: '@types/estree': 1.0.6 - '@types/estree@1.0.5': {} - '@types/estree@1.0.6': {} '@types/figlet@1.7.0': {} @@ -10460,15 +10603,15 @@ snapshots: '@types/node': 22.10.2 optional: true - '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': dependencies: - '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/type-utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/type-utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.18.0 - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -10477,14 +10620,43 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/type-utils': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.1 + eslint: 9.17.0(jiti@2.4.1) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': dependencies: '@typescript-eslint/scope-manager': 8.18.0 '@typescript-eslint/types': 8.18.0 '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.18.0 - debug: 4.3.7 - eslint: 8.57.1 + debug: 4.4.0 + eslint: 9.17.0(jiti@2.4.1) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.1 + debug: 4.4.0 + eslint: 9.17.0(jiti@2.4.1) typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -10494,12 +10666,28 @@ snapshots: '@typescript-eslint/types': 8.18.0 '@typescript-eslint/visitor-keys': 8.18.0 - '@typescript-eslint/type-utils@8.18.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/scope-manager@8.18.1': + dependencies: + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/visitor-keys': 8.18.1 + + '@typescript-eslint/type-utils@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': dependencies: '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) debug: 4.4.0 - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/type-utils@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + debug: 4.4.0 + eslint: 9.17.0(jiti@2.4.1) ts-api-utils: 1.3.0(typescript@5.7.2) typescript: 5.7.2 transitivePeerDependencies: @@ -10507,6 +10695,8 @@ snapshots: '@typescript-eslint/types@8.18.0': {} + '@typescript-eslint/types@8.18.1': {} + '@typescript-eslint/typescript-estree@8.18.0(typescript@5.7.2)': dependencies: '@typescript-eslint/types': 8.18.0 @@ -10521,13 +10711,38 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.18.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@8.18.1(typescript@5.7.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/visitor-keys': 8.18.1 + debug: 4.4.0 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) '@typescript-eslint/scope-manager': 8.18.0 '@typescript-eslint/types': 8.18.0 '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) + '@typescript-eslint/scope-manager': 8.18.1 + '@typescript-eslint/types': 8.18.1 + '@typescript-eslint/typescript-estree': 8.18.1(typescript@5.7.2) + eslint: 9.17.0(jiti@2.4.1) typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -10537,9 +10752,14 @@ snapshots: '@typescript-eslint/types': 8.18.0 eslint-visitor-keys: 4.2.0 + '@typescript-eslint/visitor-keys@8.18.1': + dependencies: + '@typescript-eslint/types': 8.18.1 + eslint-visitor-keys: 4.2.0 + '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-legacy@6.0.0(terser@5.36.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': + '@vitejs/plugin-legacy@6.0.0(terser@5.36.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@babel/preset-env': 7.26.0(@babel/core@7.26.0) @@ -10550,25 +10770,25 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.36.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react-swc@3.7.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': + '@vitejs/plugin-react-swc@3.7.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': dependencies: '@swc/core': 1.7.26 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': + '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - supports-color @@ -10624,9 +10844,9 @@ snapshots: jsonparse: 1.3.1 through: 2.3.8 - acorn-jsx@5.3.2(acorn@8.12.1): + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 acorn-node@1.8.2: dependencies: @@ -10638,8 +10858,6 @@ snapshots: acorn@7.4.1: {} - acorn@8.12.1: {} - acorn@8.14.0: {} adm-zip@0.5.16: {} @@ -11129,6 +11347,8 @@ snapshots: colorize-template@1.0.0: {} + colorjs.io@0.5.2: {} + comma-separated-tokens@2.0.3: {} commander@12.1.0: {} @@ -11257,6 +11477,12 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + crypto-random-string@1.0.0: {} css-functions-list@3.2.3: {} @@ -11858,25 +12084,25 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.5.1(eslint@8.57.1): + eslint-compat-utils@0.5.1(eslint@9.17.0(jiti@2.4.1)): dependencies: - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) semver: 7.6.3 - eslint-config-prettier@9.1.0(eslint@8.57.1): + eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@2.4.1)): dependencies: - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) - eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1))(eslint-plugin-n@17.15.0(eslint@8.57.1))(eslint-plugin-promise@7.2.1(eslint@8.57.1))(eslint@8.57.1): + eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint-plugin-n@17.15.0(eslint@9.17.0(jiti@2.4.1)))(eslint-plugin-promise@7.2.1(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1)): dependencies: - eslint: 8.57.1 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1) - eslint-plugin-n: 17.15.0(eslint@8.57.1) - eslint-plugin-promise: 7.2.1(eslint@8.57.1) + eslint: 9.17.0(jiti@2.4.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-n: 17.15.0(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-promise: 7.2.1(eslint@9.17.0(jiti@2.4.1)) - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))): dependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)) eslint-import-resolver-node@0.3.9: dependencies: @@ -11886,28 +12112,63 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.0 + enhanced-resolve: 5.17.1 + eslint: 9.17.0(jiti@2.4.1) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.3.0 + is-glob: 4.0.3 + stable-hash: 0.0.4 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-import-x: 4.5.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@9.17.0(jiti@2.4.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) - eslint: 8.57.1 + '@typescript-eslint/parser': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + eslint: 9.17.0(jiti@2.4.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.8.0(eslint@8.57.1): + eslint-plugin-es-x@7.8.0(eslint@9.17.0(jiti@2.4.1)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) '@eslint-community/regexpp': 4.11.0 - eslint: 8.57.1 - eslint-compat-utils: 0.5.1(eslint@8.57.1) + eslint: 9.17.0(jiti@2.4.1) + eslint-compat-utils: 0.5.1(eslint@9.17.0(jiti@2.4.1)) eslint-plugin-html@8.1.2: dependencies: htmlparser2: 9.1.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1): + eslint-plugin-import-x@4.5.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2): + dependencies: + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + debug: 4.4.0 + doctrine: 3.0.0 + eslint: 9.17.0(jiti@2.4.1) + eslint-import-resolver-node: 0.3.9 + get-tsconfig: 4.8.1 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + stable-hash: 0.0.4 + tslib: 2.7.0 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -11916,9 +12177,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@9.17.0(jiti@2.4.1)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -11930,55 +12191,55 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.18.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@17.15.0(eslint@8.57.1): + eslint-plugin-n@17.15.0(eslint@9.17.0(jiti@2.4.1)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) enhanced-resolve: 5.17.1 - eslint: 8.57.1 - eslint-plugin-es-x: 7.8.0(eslint@8.57.1) + eslint: 9.17.0(jiti@2.4.1) + eslint-plugin-es-x: 7.8.0(eslint@9.17.0(jiti@2.4.1)) get-tsconfig: 4.8.1 - globals: 15.11.0 + globals: 15.13.0 ignore: 5.3.2 minimatch: 9.0.5 semver: 7.6.3 - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1))(prettier@3.4.2): dependencies: - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) prettier: 3.4.2 prettier-linter-helpers: 1.0.0 synckit: 0.9.1 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@8.57.1) + eslint-config-prettier: 9.1.0(eslint@9.17.0(jiti@2.4.1)) - eslint-plugin-promise@7.2.1(eslint@8.57.1): + eslint-plugin-promise@7.2.1(eslint@9.17.0(jiti@2.4.1)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - eslint: 8.57.1 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) + eslint: 9.17.0(jiti@2.4.1) - eslint-plugin-react-compiler@0.0.0-experimental-fcabbc1-20241106(eslint@8.57.1): + eslint-plugin-react-compiler@19.0.0-beta-df7b47d-20241124(eslint@9.17.0(jiti@2.4.1)): dependencies: '@babel/core': 7.26.0 - '@babel/parser': 7.26.1 - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.0) - eslint: 8.57.1 - hermes-parser: 0.20.1 + '@babel/parser': 7.26.3 + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + eslint: 9.17.0(jiti@2.4.1) + hermes-parser: 0.25.1 zod: 3.24.1 zod-validation-error: 3.3.1(zod@3.24.1) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): + eslint-plugin-react-hooks@5.1.0(eslint@9.17.0(jiti@2.4.1)): dependencies: - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) - eslint-plugin-react@7.37.2(eslint@8.57.1): + eslint-plugin-react@7.37.2(eslint@9.17.0(jiti@2.4.1)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -11986,7 +12247,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.1.0 - eslint: 8.57.1 + eslint: 9.17.0(jiti@2.4.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -12000,7 +12261,7 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-scope@7.2.2: + eslint-scope@8.2.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 @@ -12009,46 +12270,44 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@8.57.1: + eslint@9.17.0(jiti@2.4.1): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.11.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.1)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.1 + '@eslint/core': 0.9.1 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.17.0 + '@eslint/plugin-kit': 0.2.4 + '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.7 - doctrine: 3.0.0 + cross-spawn: 7.0.6 + debug: 4.4.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 + optionalDependencies: + jiti: 2.4.1 transitivePeerDependencies: - supports-color @@ -12059,11 +12318,11 @@ snapshots: event-emitter: 0.3.5 type: 2.7.2 - espree@9.6.1: + espree@10.3.0: dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 3.4.3 + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 esquery@1.6.0: dependencies: @@ -12181,9 +12440,9 @@ snapshots: figlet@1.8.0: {} - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 file-entry-cache@9.1.0: dependencies: @@ -12208,11 +12467,10 @@ snapshots: path-exists: 5.0.0 unicorn-magic: 0.1.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: flatted: 3.3.1 keyv: 4.5.4 - rimraf: 3.0.2 flat-cache@5.0.0: dependencies: @@ -12378,11 +12636,7 @@ snapshots: globals@11.12.0: {} - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globals@15.11.0: {} + globals@14.0.0: {} globals@15.13.0: {} @@ -12484,7 +12738,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/hast': 3.0.4 '@types/unist': 3.0.2 comma-separated-tokens: 2.0.3 @@ -12508,11 +12762,11 @@ snapshots: he@1.2.0: {} - hermes-estree@0.20.1: {} + hermes-estree@0.25.1: {} - hermes-parser@0.20.1: + hermes-parser@0.25.1: dependencies: - hermes-estree: 0.20.1 + hermes-estree: 0.25.1 highlight-words@2.0.0: {} @@ -12596,8 +12850,6 @@ snapshots: image-size@0.5.5: optional: true - immutable@4.3.5: {} - immutable@5.0.2: {} import-fresh@3.3.0: @@ -12700,6 +12952,10 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 + is-bun-module@1.3.0: + dependencies: + semver: 7.6.3 + is-callable@1.2.7: {} is-ci@1.2.1: @@ -12779,8 +13035,6 @@ snapshots: dependencies: path-is-inside: 1.0.2 - is-path-inside@3.0.3: {} - is-plain-obj@4.1.0: {} is-plain-object@5.0.0: {} @@ -13527,6 +13781,25 @@ snapshots: sax: 1.3.0 optional: true + neostandard@0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2): + dependencies: + '@humanwhocodes/gitignore-to-minimatch': 1.0.2 + '@stylistic/eslint-plugin': 2.11.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + eslint: 9.17.0(jiti@2.4.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-import-x: 4.5.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + eslint-plugin-n: 17.15.0(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-promise: 7.2.1(eslint@9.17.0(jiti@2.4.1)) + eslint-plugin-react: 7.37.2(eslint@9.17.0(jiti@2.4.1)) + find-up: 5.0.0 + globals: 15.13.0 + peowly: 1.3.2 + typescript-eslint: 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + transitivePeerDependencies: + - eslint-plugin-import + - supports-color + - typescript + next-tick@1.1.0: {} no-case@3.0.4: @@ -13800,6 +14073,8 @@ snapshots: pend@1.2.0: {} + peowly@1.3.2: {} + picocolors@0.2.1: {} picocolors@1.1.1: {} @@ -14311,10 +14586,6 @@ snapshots: rfdc@1.4.1: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rimraf@5.0.9: dependencies: glob: 10.4.5 @@ -14395,95 +14666,97 @@ snapshots: safer-buffer@2.1.2: {} - sass-embedded-android-arm64@1.78.0: + sass-embedded-android-arm64@1.83.0: optional: true - sass-embedded-android-arm@1.78.0: + sass-embedded-android-arm@1.83.0: optional: true - sass-embedded-android-ia32@1.78.0: + sass-embedded-android-ia32@1.83.0: optional: true - sass-embedded-android-riscv64@1.78.0: + sass-embedded-android-riscv64@1.83.0: optional: true - sass-embedded-android-x64@1.78.0: + sass-embedded-android-x64@1.83.0: optional: true - sass-embedded-darwin-arm64@1.78.0: + sass-embedded-darwin-arm64@1.83.0: optional: true - sass-embedded-darwin-x64@1.78.0: + sass-embedded-darwin-x64@1.83.0: optional: true - sass-embedded-linux-arm64@1.78.0: + sass-embedded-linux-arm64@1.83.0: optional: true - sass-embedded-linux-arm@1.78.0: + sass-embedded-linux-arm@1.83.0: optional: true - sass-embedded-linux-ia32@1.78.0: + sass-embedded-linux-ia32@1.83.0: optional: true - sass-embedded-linux-musl-arm64@1.78.0: + sass-embedded-linux-musl-arm64@1.83.0: optional: true - sass-embedded-linux-musl-arm@1.78.0: + sass-embedded-linux-musl-arm@1.83.0: optional: true - sass-embedded-linux-musl-ia32@1.78.0: + sass-embedded-linux-musl-ia32@1.83.0: optional: true - sass-embedded-linux-musl-riscv64@1.78.0: + sass-embedded-linux-musl-riscv64@1.83.0: optional: true - sass-embedded-linux-musl-x64@1.78.0: + sass-embedded-linux-musl-x64@1.83.0: optional: true - sass-embedded-linux-riscv64@1.78.0: + sass-embedded-linux-riscv64@1.83.0: optional: true - sass-embedded-linux-x64@1.78.0: + sass-embedded-linux-x64@1.83.0: optional: true - sass-embedded-win32-arm64@1.78.0: + sass-embedded-win32-arm64@1.83.0: optional: true - sass-embedded-win32-ia32@1.78.0: + sass-embedded-win32-ia32@1.83.0: optional: true - sass-embedded-win32-x64@1.78.0: + sass-embedded-win32-x64@1.83.0: optional: true - sass-embedded@1.78.0: + sass-embedded@1.83.0: dependencies: - '@bufbuild/protobuf': 1.10.0 + '@bufbuild/protobuf': 2.2.3 buffer-builder: 0.2.0 - immutable: 4.3.5 + colorjs.io: 0.5.2 + immutable: 5.0.2 rxjs: 7.8.1 supports-color: 8.1.1 + sync-child-process: 1.0.2 varint: 6.0.0 optionalDependencies: - sass-embedded-android-arm: 1.78.0 - sass-embedded-android-arm64: 1.78.0 - sass-embedded-android-ia32: 1.78.0 - sass-embedded-android-riscv64: 1.78.0 - sass-embedded-android-x64: 1.78.0 - sass-embedded-darwin-arm64: 1.78.0 - sass-embedded-darwin-x64: 1.78.0 - sass-embedded-linux-arm: 1.78.0 - sass-embedded-linux-arm64: 1.78.0 - sass-embedded-linux-ia32: 1.78.0 - sass-embedded-linux-musl-arm: 1.78.0 - sass-embedded-linux-musl-arm64: 1.78.0 - sass-embedded-linux-musl-ia32: 1.78.0 - sass-embedded-linux-musl-riscv64: 1.78.0 - sass-embedded-linux-musl-x64: 1.78.0 - sass-embedded-linux-riscv64: 1.78.0 - sass-embedded-linux-x64: 1.78.0 - sass-embedded-win32-arm64: 1.78.0 - sass-embedded-win32-ia32: 1.78.0 - sass-embedded-win32-x64: 1.78.0 + sass-embedded-android-arm: 1.83.0 + sass-embedded-android-arm64: 1.83.0 + sass-embedded-android-ia32: 1.83.0 + sass-embedded-android-riscv64: 1.83.0 + sass-embedded-android-x64: 1.83.0 + sass-embedded-darwin-arm64: 1.83.0 + sass-embedded-darwin-x64: 1.83.0 + sass-embedded-linux-arm: 1.83.0 + sass-embedded-linux-arm64: 1.83.0 + sass-embedded-linux-ia32: 1.83.0 + sass-embedded-linux-musl-arm: 1.83.0 + sass-embedded-linux-musl-arm64: 1.83.0 + sass-embedded-linux-musl-ia32: 1.83.0 + sass-embedded-linux-musl-riscv64: 1.83.0 + sass-embedded-linux-musl-x64: 1.83.0 + sass-embedded-linux-riscv64: 1.83.0 + sass-embedded-linux-x64: 1.83.0 + sass-embedded-win32-arm64: 1.83.0 + sass-embedded-win32-ia32: 1.83.0 + sass-embedded-win32-x64: 1.83.0 sass@1.83.0: dependencies: @@ -14638,6 +14911,8 @@ snapshots: sprintf-js@1.1.3: {} + stable-hash@0.0.4: {} + stack-generator@2.0.10: dependencies: stackframe: 1.3.4 @@ -14912,6 +15187,12 @@ snapshots: react: 19.0.0 use-sync-external-store: 1.2.2(react@19.0.0) + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.1.3 + + sync-message-port@1.1.3: {} + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 @@ -15031,8 +15312,6 @@ snapshots: text-extensions@2.4.0: {} - text-table@0.2.0: {} - thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -15113,8 +15392,6 @@ snapshots: type-fest@0.13.1: optional: true - type-fest@0.20.2: {} - type@2.7.2: {} typed-array-buffer@1.0.2: @@ -15153,6 +15430,16 @@ snapshots: dependencies: is-typedarray: 1.0.0 + typescript-eslint@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2) + eslint: 9.17.0(jiti@2.4.1) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + typescript-plugin-css-modules@5.1.0(typescript@5.7.2): dependencies: '@types/postcss-modules-local-by-default': 4.0.2 @@ -15195,7 +15482,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.1.0: {} + undici@7.1.1: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -15297,7 +15584,7 @@ snapshots: dependencies: '@antfu/install-pkg': 0.5.0 '@antfu/utils': 0.7.10 - '@iconify/utils': 2.2.0 + '@iconify/utils': 2.2.1 debug: 4.4.0 kolorist: 1.8.0 local-pkg: 0.5.1 @@ -15404,7 +15691,7 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.3.0(@types/node@22.10.2)(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): + vite-plugin-dts@4.3.0(@types/node@22.10.2)(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): dependencies: '@microsoft/api-extractor': 7.47.11(@types/node@22.10.2) '@rollup/pluginutils': 5.1.0(rollup@4.27.4) @@ -15417,43 +15704,43 @@ snapshots: magic-string: 0.30.11 typescript: 5.7.2 optionalDependencies: - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-sass-dts@1.3.29(postcss@8.4.49)(prettier@3.4.2)(sass-embedded@1.78.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): + vite-plugin-sass-dts@1.3.29(postcss@8.4.49)(prettier@3.4.2)(sass-embedded@1.83.0)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): dependencies: postcss: 8.4.49 postcss-js: 4.0.1(postcss@8.4.49) prettier: 3.4.2 - sass-embedded: 1.78.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + sass-embedded: 1.83.0 + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) - vite-plugin-svgr@4.3.0(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): + vite-plugin-svgr@4.3.0(rollup@4.27.4)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): dependencies: '@rollup/pluginutils': 5.1.3(rollup@4.27.4) '@svgr/core': 8.1.0(typescript@5.7.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.7.2)) - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): + vite-tsconfig-paths@5.1.4(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1)): dependencies: debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.7.2) optionalDependencies: - vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) + vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) transitivePeerDependencies: - supports-color - typescript - vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1): + vite@6.0.3(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.0)(sass-embedded@1.83.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1): dependencies: esbuild: 0.24.0 postcss: 8.4.49 @@ -15464,7 +15751,7 @@ snapshots: jiti: 2.4.1 less: 4.2.0 sass: 1.83.0 - sass-embedded: 1.78.0 + sass-embedded: 1.83.0 stylus: 0.62.0 terser: 5.36.0 tsx: 4.19.2 diff --git a/clash-nyanpasu/pnpm-workspace.yaml b/clash-nyanpasu/pnpm-workspace.yaml index 5b81f0cef0..822faa969f 100644 --- a/clash-nyanpasu/pnpm-workspace.yaml +++ b/clash-nyanpasu/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - - "frontend/*" - - "scripts" + - 'frontend/*' + - 'scripts' diff --git a/clash-nyanpasu/scripts/check.ts b/clash-nyanpasu/scripts/check.ts index a35c108481..3678746e72 100644 --- a/clash-nyanpasu/scripts/check.ts +++ b/clash-nyanpasu/scripts/check.ts @@ -1,112 +1,112 @@ -import os from "node:os"; -import { printNyanpasu } from "./utils"; -import { archCheck } from "./utils/arch-check"; -import { SIDECAR_HOST } from "./utils/consts"; -import { colorize, consola } from "./utils/logger"; -import { Resolve } from "./utils/resolve"; +import os from 'node:os' +import { printNyanpasu } from './utils' +import { archCheck } from './utils/arch-check' +import { SIDECAR_HOST } from './utils/consts' +import { colorize, consola } from './utils/logger' +import { Resolve } from './utils/resolve' // force download -const FORCE = process.argv.includes("--force"); +const FORCE = process.argv.includes('--force') // cross platform build using -const ARCH = process.argv.includes("--arch") - ? process.argv[process.argv.indexOf("--arch") + 1] - : undefined; +const ARCH = process.argv.includes('--arch') + ? process.argv[process.argv.indexOf('--arch') + 1] + : undefined // cross platform build support if (!SIDECAR_HOST) { - consola.fatal(colorize`{red.bold SIDECAR_HOST} not found`); - process.exit(1); + consola.fatal(colorize`{red.bold SIDECAR_HOST} not found`) + process.exit(1) } else { - consola.debug(colorize`sidecar-host {yellow ${SIDECAR_HOST}}`); + consola.debug(colorize`sidecar-host {yellow ${SIDECAR_HOST}}`) } -const platform = process.platform; +const platform = process.platform -const arch = (ARCH ? ARCH : process.arch) as NodeJS.Architecture | "armel"; +const arch = (ARCH || process.arch) as NodeJS.Architecture | 'armel' -archCheck(platform, arch); +archCheck(platform, arch) const resolve = new Resolve({ platform, arch, sidecarHost: SIDECAR_HOST!, force: FORCE, -}); +}) const tasks: { - name: string; - func: () => Promise; - retry: number; - winOnly?: boolean; + name: string + func: () => Promise + retry: number + winOnly?: boolean }[] = [ - { name: "clash", func: () => resolve.clash(), retry: 5 }, - { name: "mihomo", func: () => resolve.clashMeta(), retry: 5 }, - { name: "mihomo-alpha", func: () => resolve.clashMetaAlpha(), retry: 5 }, - { name: "clash-rs", func: () => resolve.clashRust(), retry: 5 }, - { name: "clash-rs-alpha", func: () => resolve.clashRustAlpha(), retry: 5 }, - { name: "wintun", func: () => resolve.wintun(), retry: 5, winOnly: true }, + { name: 'clash', func: () => resolve.clash(), retry: 5 }, + { name: 'mihomo', func: () => resolve.clashMeta(), retry: 5 }, + { name: 'mihomo-alpha', func: () => resolve.clashMetaAlpha(), retry: 5 }, + { name: 'clash-rs', func: () => resolve.clashRust(), retry: 5 }, + { name: 'clash-rs-alpha', func: () => resolve.clashRustAlpha(), retry: 5 }, + { name: 'wintun', func: () => resolve.wintun(), retry: 5, winOnly: true }, { - name: "nyanpasu-service", + name: 'nyanpasu-service', func: () => resolve.service(), retry: 5, }, - { name: "mmdb", func: () => resolve.mmdb(), retry: 5 }, - { name: "geoip", func: () => resolve.geoip(), retry: 5 }, - { name: "geosite", func: () => resolve.geosite(), retry: 5 }, + { name: 'mmdb', func: () => resolve.mmdb(), retry: 5 }, + { name: 'geoip', func: () => resolve.geoip(), retry: 5 }, + { name: 'geosite', func: () => resolve.geosite(), retry: 5 }, { - name: "enableLoopback", + name: 'enableLoopback', func: () => resolve.enableLoopback(), retry: 5, winOnly: true, }, -]; +] async function runTask() { - const task = tasks.shift(); + const task = tasks.shift() - if (!task) return; + if (!task) return - if (task.winOnly && process.platform !== "win32") return runTask(); + if (task.winOnly && process.platform !== 'win32') return runTask() for (let i = 0; i < task.retry; i++) { try { - await task.func(); + await task.func() - break; + break } catch (err) { - consola.warn(`task::${task.name} try ${i} ==`, err); + consola.warn(`task::${task.name} try ${i} ==`, err) if (i === task.retry - 1) { - consola.fatal(`task::${task.name} failed`, err); - process.exit(1); + consola.fatal(`task::${task.name} failed`, err) + process.exit(1) } } } - return runTask(); + return runTask() } -consola.start("start check and download resources..."); +consola.start('start check and download resources...') const jobs = new Array(Math.ceil(os.cpus.length / 2) || 2) .fill(0) - .map(() => runTask()); + .map(() => runTask()) Promise.all(jobs).then(() => { - printNyanpasu(); + printNyanpasu() - consola.success("all resources download finished\n"); + consola.success('all resources download finished\n') const commands = [ - "pnpm dev - development with react dev tools", - "pnpm dev:diff - deadlock development with react dev tools (recommend)", - "pnpm tauri:diff - deadlock development", - ]; + 'pnpm dev - development with react dev tools', + 'pnpm dev:diff - deadlock development with react dev tools (recommend)', + 'pnpm tauri:diff - deadlock development', + ] - consola.log(" next command:\n"); + consola.log(' next command:\n') commands.forEach((text) => { - consola.log(` ${text}`); - }); -}); + consola.log(` ${text}`) + }) +}) diff --git a/clash-nyanpasu/scripts/generate-git-info.ts b/clash-nyanpasu/scripts/generate-git-info.ts index 710a29d673..53b54b780c 100644 --- a/clash-nyanpasu/scripts/generate-git-info.ts +++ b/clash-nyanpasu/scripts/generate-git-info.ts @@ -1,7 +1,7 @@ -import { execSync } from "node:child_process"; -import fs from "fs-extra"; -import { GIT_SUMMARY_INFO_PATH, TAURI_APP_TEMP_DIR } from "./utils/env"; -import { consola } from "./utils/logger"; +import { execSync } from 'node:child_process' +import fs from 'fs-extra' +import { GIT_SUMMARY_INFO_PATH, TAURI_APP_TEMP_DIR } from './utils/env' +import { consola } from './utils/logger' async function main() { const [hash, author, time] = execSync( @@ -11,21 +11,21 @@ async function main() { }, ) .toString() - .replace(/'/g, "") - .split(","); + .replace(/'/g, '') + .split(',') const summary = { hash, author, time, - }; - consola.info(summary); + } + consola.info(summary) if (!(await fs.exists(TAURI_APP_TEMP_DIR))) { - await fs.mkdir(TAURI_APP_TEMP_DIR); + await fs.mkdir(TAURI_APP_TEMP_DIR) } - await fs.writeJSON(GIT_SUMMARY_INFO_PATH, summary, { spaces: 2 }); - consola.success("Git summary info generated"); + await fs.writeJSON(GIT_SUMMARY_INFO_PATH, summary, { spaces: 2 }) + consola.success('Git summary info generated') } -main().catch(consola.error); +main().catch(consola.error) diff --git a/clash-nyanpasu/scripts/generate-latest-version.ts b/clash-nyanpasu/scripts/generate-latest-version.ts index 9a370338ba..6ad5a53585 100644 --- a/clash-nyanpasu/scripts/generate-latest-version.ts +++ b/clash-nyanpasu/scripts/generate-latest-version.ts @@ -1,16 +1,16 @@ -import fs from "fs-extra"; -import { ManifestVersion, SupportedCore } from "./types/index"; -import { MANIFEST_DIR, MANIFEST_VERSION_PATH } from "./utils/env"; -import { consola } from "./utils/logger"; +import fs from 'fs-extra' +import { ManifestVersion, SupportedCore } from './types/index' +import { MANIFEST_DIR, MANIFEST_VERSION_PATH } from './utils/env' +import { consola } from './utils/logger' import { resolveClashPremium, resolveClashRs, resolveClashRsAlpha, resolveMihomo, resolveMihomoAlpha, -} from "./utils/manifest"; +} from './utils/manifest' -const MANIFEST_VERSION = 1; +const MANIFEST_VERSION = 1 export async function generateLatestVersion() { const resolvers = [ @@ -19,45 +19,45 @@ export async function generateLatestVersion() { resolveClashRs, resolveClashPremium, resolveClashRsAlpha, - ]; + ] - consola.start("Resolving latest versions"); + consola.start('Resolving latest versions') - const results = await Promise.all(resolvers.map((r) => r())); + const results = await Promise.all(resolvers.map((r) => r())) - consola.success("Resolved latest versions"); + consola.success('Resolved latest versions') - consola.start("Generating manifest"); + consola.start('Generating manifest') const manifest: ManifestVersion = { manifest_version: MANIFEST_VERSION, latest: {}, arch_template: {}, - } as ManifestVersion; + } as ManifestVersion for (const result of results) { - manifest.latest[result.name as SupportedCore] = result.version; - manifest.arch_template[result.name as SupportedCore] = result.archMapping; + manifest.latest[result.name as SupportedCore] = result.version + manifest.arch_template[result.name as SupportedCore] = result.archMapping } - await fs.ensureDir(MANIFEST_DIR); + await fs.ensureDir(MANIFEST_DIR) // If no changes, skip writing manifest - const previousManifest = (await fs.readJSON(MANIFEST_VERSION_PATH)) || {}; + const previousManifest = (await fs.readJSON(MANIFEST_VERSION_PATH)) || {} - delete previousManifest.updated_at; + delete previousManifest.updated_at if (JSON.stringify(previousManifest) === JSON.stringify(manifest)) { - consola.success("No changes, skip writing manifest"); - return; + consola.success('No changes, skip writing manifest') + return } - manifest.updated_at = new Date().toISOString(); + manifest.updated_at = new Date().toISOString() - consola.success("Generated manifest"); + consola.success('Generated manifest') - await fs.writeJSON(MANIFEST_VERSION_PATH, manifest, { spaces: 2 }); + await fs.writeJSON(MANIFEST_VERSION_PATH, manifest, { spaces: 2 }) - consola.success("Manifest written"); + consola.success('Manifest written') } -generateLatestVersion(); +generateLatestVersion() diff --git a/clash-nyanpasu/scripts/manifest/clash-meta.ts b/clash-nyanpasu/scripts/manifest/clash-meta.ts index 713bf6e5b0..b977c9d6b7 100644 --- a/clash-nyanpasu/scripts/manifest/clash-meta.ts +++ b/clash-nyanpasu/scripts/manifest/clash-meta.ts @@ -1,17 +1,17 @@ -import { ClashManifest } from "types"; -import versionManifest from "../../manifest/version.json"; +import { ClashManifest } from 'types' +import versionManifest from '../../manifest/version.json' export const CLASH_META_MANIFEST: ClashManifest = { URL_PREFIX: `https://github.com/MetaCubeX/mihomo/releases/download/${versionManifest.latest.mihomo}`, VERSION: versionManifest.latest.mihomo, ARCH_MAPPING: versionManifest.arch_template.mihomo, -}; +} export const CLASH_META_ALPHA_MANIFEST: ClashManifest = { VERSION_URL: - "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt", + 'https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt', URL_PREFIX: - "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha", + 'https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha', VERSION: versionManifest.latest.mihomo_alpha, ARCH_MAPPING: versionManifest.arch_template.mihomo_alpha, -}; +} diff --git a/clash-nyanpasu/scripts/manifest/clash-premium.ts b/clash-nyanpasu/scripts/manifest/clash-premium.ts index 3f40a5ee59..82c9e13d4a 100644 --- a/clash-nyanpasu/scripts/manifest/clash-premium.ts +++ b/clash-nyanpasu/scripts/manifest/clash-premium.ts @@ -1,13 +1,13 @@ -import { ClashManifest } from "types"; -import versionManifest from "../../manifest/version.json"; +import { ClashManifest } from 'types' +import versionManifest from '../../manifest/version.json' export const CLASH_MANIFEST: ClashManifest = { - URL_PREFIX: "https://github.com/Dreamacro/clash/releases/download/premium/", - LATEST_DATE: "2023.08.17", - STORAGE_PREFIX: "https://release.dreamacro.workers.dev/", + URL_PREFIX: 'https://github.com/Dreamacro/clash/releases/download/premium/', + LATEST_DATE: '2023.08.17', + STORAGE_PREFIX: 'https://release.dreamacro.workers.dev/', BACKUP_URL_PREFIX: - "https://github.com/zhongfly/Clash-premium-backup/releases/download/", + 'https://github.com/zhongfly/Clash-premium-backup/releases/download/', BACKUP_LATEST_DATE: versionManifest.latest.clash_premium, VERSION: versionManifest.latest.clash_premium, ARCH_MAPPING: versionManifest.arch_template.clash_premium, -}; +} diff --git a/clash-nyanpasu/scripts/manifest/clash-rs.ts b/clash-nyanpasu/scripts/manifest/clash-rs.ts index 954d8206c3..7704e5bbb4 100644 --- a/clash-nyanpasu/scripts/manifest/clash-rs.ts +++ b/clash-nyanpasu/scripts/manifest/clash-rs.ts @@ -1,16 +1,16 @@ -import { ClashManifest } from "types"; -import versionManifest from "../../manifest/version.json"; +import { ClashManifest } from 'types' +import versionManifest from '../../manifest/version.json' export const CLASH_RS_MANIFEST: ClashManifest = { - URL_PREFIX: "https://github.com/Watfaq/clash-rs/releases/download/", + URL_PREFIX: 'https://github.com/Watfaq/clash-rs/releases/download/', VERSION: versionManifest.latest.clash_rs, ARCH_MAPPING: versionManifest.arch_template.clash_rs, -}; +} export const CLASH_RS_ALPHA_MANIFEST: ClashManifest = { VERSION_URL: - "https://github.com/Watfaq/clash-rs/releases/download/latest/version.txt", - URL_PREFIX: "https://github.com/Watfaq/clash-rs/releases/download/latest", + 'https://github.com/Watfaq/clash-rs/releases/download/latest/version.txt', + URL_PREFIX: 'https://github.com/Watfaq/clash-rs/releases/download/latest', VERSION: versionManifest.latest.clash_rs_alpha, ARCH_MAPPING: versionManifest.arch_template.clash_rs_alpha, -}; +} diff --git a/clash-nyanpasu/scripts/manifest/index.ts b/clash-nyanpasu/scripts/manifest/index.ts index 7f0500a32c..ad902de9ab 100644 --- a/clash-nyanpasu/scripts/manifest/index.ts +++ b/clash-nyanpasu/scripts/manifest/index.ts @@ -1,10 +1,10 @@ -import { CLASH_META_ALPHA_MANIFEST, CLASH_META_MANIFEST } from "./clash-meta"; -import { CLASH_MANIFEST } from "./clash-premium"; -import { CLASH_RS_MANIFEST } from "./clash-rs"; +import { CLASH_META_ALPHA_MANIFEST, CLASH_META_MANIFEST } from './clash-meta' +import { CLASH_MANIFEST } from './clash-premium' +import { CLASH_RS_MANIFEST } from './clash-rs' export const clashManifest = { premium: CLASH_MANIFEST, meta: CLASH_META_MANIFEST, metaAlpha: CLASH_META_ALPHA_MANIFEST, rs: CLASH_RS_MANIFEST, -}; +} diff --git a/clash-nyanpasu/scripts/osx-aarch64-upload.ts b/clash-nyanpasu/scripts/osx-aarch64-upload.ts index ff1d8798b0..0497bac8aa 100644 --- a/clash-nyanpasu/scripts/osx-aarch64-upload.ts +++ b/clash-nyanpasu/scripts/osx-aarch64-upload.ts @@ -2,90 +2,90 @@ * Build and upload assets * for macOS(aarch) */ -import path from "node:path"; -import fs from "fs-extra"; -import { context, getOctokit } from "@actions/github"; -import pkgJson from "../package.json"; -import { consola } from "./utils/logger"; +import path from 'node:path' +import fs from 'fs-extra' +import { context, getOctokit } from '@actions/github' +import pkgJson from '../package.json' +import { consola } from './utils/logger' async function resolve() { if (!process.env.GITHUB_TOKEN) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } if (!process.env.TAURI_SIGNING_PRIVATE_KEY) { - throw new Error("TAURI_SIGNING_PRIVATE_KEY is required"); + throw new Error('TAURI_SIGNING_PRIVATE_KEY is required') } if (!process.env.TAURI_SIGNING_PRIVATE_KEY_PASSWORD) { - throw new Error("TAURI_SIGNING_PRIVATE_KEY_PASSWORD is required"); + throw new Error('TAURI_SIGNING_PRIVATE_KEY_PASSWORD is required') } - const { version } = pkgJson; + const { version } = pkgJson - const tag = process.env.TAG_NAME || `v${version}`; + const tag = process.env.TAG_NAME || `v${version}` - consola.info(`Upload to tag ${tag}`); + consola.info(`Upload to tag ${tag}`) - const cwd = process.cwd(); + const cwd = process.cwd() const bundlePath = path.join( - "backend/target/aarch64-apple-darwin/release/bundle", - ); - const join = (p: string) => path.join(bundlePath, p); + 'backend/target/aarch64-apple-darwin/release/bundle', + ) + const join = (p: string) => path.join(bundlePath, p) const appPathList = [ - join("macos/Clash Nyanpasu.aarch64.app.tar.gz"), - join("macos/Clash Nyanpasu.aarch64.app.tar.gz.sig"), - ]; + join('macos/Clash Nyanpasu.aarch64.app.tar.gz'), + join('macos/Clash Nyanpasu.aarch64.app.tar.gz.sig'), + ] for (const appPath of appPathList) { if (fs.pathExistsSync(appPath)) { - fs.removeSync(appPath); + fs.removeSync(appPath) } } - fs.copyFileSync(join("macos/Clash Nyanpasu.app.tar.gz"), appPathList[0]); - fs.copyFileSync(join("macos/Clash Nyanpasu.app.tar.gz.sig"), appPathList[1]); + fs.copyFileSync(join('macos/Clash Nyanpasu.app.tar.gz'), appPathList[0]) + fs.copyFileSync(join('macos/Clash Nyanpasu.app.tar.gz.sig'), appPathList[1]) - const options = { owner: context.repo.owner, repo: context.repo.repo }; - const github = getOctokit(process.env.GITHUB_TOKEN); + const options = { owner: context.repo.owner, repo: context.repo.repo } + const github = getOctokit(process.env.GITHUB_TOKEN) const { data: release } = await github.rest.repos.getReleaseByTag({ ...options, tag, - }); + }) - if (!release.id) throw new Error("failed to find the release"); + if (!release.id) throw new Error('failed to find the release') await uploadAssets(release.id, [ join(`dmg/Clash Nyanpasu_${version}_aarch64.dmg`), ...appPathList, - ]); + ]) } // From tauri-apps/tauri-action // https://github.com/tauri-apps/tauri-action/blob/dev/packages/action/src/upload-release-assets.ts async function uploadAssets(releaseId: number, assets: string[]) { - const GITHUB_TOKEN = process.env.GITHUB_TOKEN; + const GITHUB_TOKEN = process.env.GITHUB_TOKEN if (!GITHUB_TOKEN) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } - const github = getOctokit(GITHUB_TOKEN); + const github = getOctokit(GITHUB_TOKEN) // Determine content-length for header to upload asset - const contentLength = (filePath: string) => fs.statSync(filePath).size; + const contentLength = (filePath: string) => fs.statSync(filePath).size for (const assetPath of assets) { const headers = { - "content-type": "application/zip", - "content-length": contentLength(assetPath), - }; + 'content-type': 'application/zip', + 'content-length': contentLength(assetPath), + } - const ext = path.extname(assetPath); - const filename = path.basename(assetPath).replace(ext, ""); + const ext = path.extname(assetPath) + const filename = path.basename(assetPath).replace(ext, '') const assetName = path.dirname(assetPath).includes(`target${path.sep}debug`) ? `${filename}-debug${ext}` - : `${filename}${ext}`; + : `${filename}${ext}` - consola.start(`Uploading ${assetName}...`); + consola.start(`Uploading ${assetName}...`) try { await github.rest.repos.uploadReleaseAsset({ @@ -97,15 +97,15 @@ async function uploadAssets(releaseId: number, assets: string[]) { owner: context.repo.owner, repo: context.repo.repo, release_id: releaseId, - }); - consola.success(`Uploaded ${assetName}`); + }) + consola.success(`Uploaded ${assetName}`) } catch (error) { consola.error( - "Failed to upload release asset", + 'Failed to upload release asset', error instanceof Error ? error.message : error, - ); + ) } } } -resolve(); +resolve() diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index 5576c23d7d..b0aa44e015 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -22,6 +22,6 @@ "picocolors": "1.1.1", "tar": "7.4.3", "telegram": "2.26.8", - "undici": "7.1.0" + "undici": "7.1.1" } } diff --git a/clash-nyanpasu/scripts/portable.ts b/clash-nyanpasu/scripts/portable.ts index 26af8466b8..dab749da42 100644 --- a/clash-nyanpasu/scripts/portable.ts +++ b/clash-nyanpasu/scripts/portable.ts @@ -1,86 +1,86 @@ -import path from "node:path"; -import AdmZip from "adm-zip"; -import fs from "fs-extra"; -import { context, getOctokit } from "@actions/github"; -import packageJson from "../package.json"; -import { TAURI_APP_DIR } from "./utils/env"; -import { colorize, consola } from "./utils/logger"; +import path from 'node:path' +import AdmZip from 'adm-zip' +import fs from 'fs-extra' +import { context, getOctokit } from '@actions/github' +import packageJson from '../package.json' +import { TAURI_APP_DIR } from './utils/env' +import { colorize, consola } from './utils/logger' -const RUST_ARCH = process.env.RUST_ARCH || "x86_64"; -const fixedWebview = process.argv.includes("--fixed-webview"); +const RUST_ARCH = process.env.RUST_ARCH || 'x86_64' +const fixedWebview = process.argv.includes('--fixed-webview') /// Script for ci /// 打包绿色版/便携版 (only Windows) async function resolvePortable() { - if (process.platform !== "win32") return; + if (process.platform !== 'win32') return const buildDir = path.join( - RUST_ARCH === "x86_64" - ? "backend/target/release" + RUST_ARCH === 'x86_64' + ? 'backend/target/release' : `backend/target/${RUST_ARCH}-pc-windows-msvc/release`, - ); + ) - const configDir = path.join(buildDir, ".config"); + const configDir = path.join(buildDir, '.config') if (!(await fs.pathExists(buildDir))) { - throw new Error("could not found the release dir"); + throw new Error('could not found the release dir') } - await fs.ensureDir(configDir); - await fs.createFile(path.join(configDir, "PORTABLE")); + await fs.ensureDir(configDir) + await fs.createFile(path.join(configDir, 'PORTABLE')) - const zip = new AdmZip(); - let mainEntryPath = path.join(buildDir, "Clash Nyanpasu.exe"); + const zip = new AdmZip() + let mainEntryPath = path.join(buildDir, 'Clash Nyanpasu.exe') if (!(await fs.pathExists(mainEntryPath))) { - mainEntryPath = path.join(buildDir, "clash-nyanpasu.exe"); + mainEntryPath = path.join(buildDir, 'clash-nyanpasu.exe') } - zip.addLocalFile(mainEntryPath); - zip.addLocalFile(path.join(buildDir, "clash.exe")); - zip.addLocalFile(path.join(buildDir, "mihomo.exe")); - zip.addLocalFile(path.join(buildDir, "mihomo-alpha.exe")); - zip.addLocalFile(path.join(buildDir, "nyanpasu-service.exe")); - zip.addLocalFile(path.join(buildDir, "clash-rs.exe")); - zip.addLocalFile(path.join(buildDir, "clash-rs-alpha.exe")); - zip.addLocalFolder(path.join(buildDir, "resources"), "resources"); + zip.addLocalFile(mainEntryPath) + zip.addLocalFile(path.join(buildDir, 'clash.exe')) + zip.addLocalFile(path.join(buildDir, 'mihomo.exe')) + zip.addLocalFile(path.join(buildDir, 'mihomo-alpha.exe')) + zip.addLocalFile(path.join(buildDir, 'nyanpasu-service.exe')) + zip.addLocalFile(path.join(buildDir, 'clash-rs.exe')) + zip.addLocalFile(path.join(buildDir, 'clash-rs-alpha.exe')) + zip.addLocalFolder(path.join(buildDir, 'resources'), 'resources') if (fixedWebview) { const webviewPath = (await fs.readdir(TAURI_APP_DIR)).find((file) => - file.includes("WebView2"), - ); + file.includes('WebView2'), + ) if (!webviewPath) { - throw new Error("WebView2 runtime not found"); + throw new Error('WebView2 runtime not found') } zip.addLocalFolder( path.join(TAURI_APP_DIR, webviewPath), path.basename(webviewPath), - ); + ) } - zip.addLocalFolder(configDir, ".config"); + zip.addLocalFolder(configDir, '.config') - const { version } = packageJson; + const { version } = packageJson - const zipFile = `Clash.Nyanpasu_${version}_${RUST_ARCH}${fixedWebview ? "_fixed-webview" : ""}_portable.zip`; - zip.writeZip(zipFile); + const zipFile = `Clash.Nyanpasu_${version}_${RUST_ARCH}${fixedWebview ? '_fixed-webview' : ''}_portable.zip` + zip.writeZip(zipFile) - consola.success("create portable zip successfully"); + consola.success('create portable zip successfully') // push release assets if (process.env.GITHUB_TOKEN === undefined) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } - const options = { owner: context.repo.owner, repo: context.repo.repo }; - const github = getOctokit(process.env.GITHUB_TOKEN); + const options = { owner: context.repo.owner, repo: context.repo.repo } + const github = getOctokit(process.env.GITHUB_TOKEN) - consola.info("upload to ", process.env.TAG_NAME || `v${version}`); + consola.info('upload to ', process.env.TAG_NAME || `v${version}`) const { data: release } = await github.rest.repos.getReleaseByTag({ ...options, tag: process.env.TAG_NAME || `v${version}`, - }); + }) - consola.debug(colorize`releaseName: {green ${release.name}}`); + consola.debug(colorize`releaseName: {green ${release.name}}`) await github.rest.repos.uploadReleaseAsset({ ...options, @@ -88,10 +88,10 @@ async function resolvePortable() { name: zipFile, // @ts-expect-error data is Buffer should work fine data: zip.toBuffer(), - }); + }) } resolvePortable().catch((err) => { - consola.error(err); - process.exit(1); -}); + consola.error(err) + process.exit(1) +}) diff --git a/clash-nyanpasu/scripts/prepare-nightly.ts b/clash-nyanpasu/scripts/prepare-nightly.ts index 4bfae73746..72ad675c8f 100644 --- a/clash-nyanpasu/scripts/prepare-nightly.ts +++ b/clash-nyanpasu/scripts/prepare-nightly.ts @@ -1,73 +1,73 @@ -import { execSync } from "child_process"; -import path from "node:path"; -import fs from "fs-extra"; -import { merge } from "lodash-es"; +import { execSync } from 'child_process' +import path from 'node:path' +import fs from 'fs-extra' +import { merge } from 'lodash-es' import { cwd, TAURI_APP_DIR, TAURI_FIXED_WEBVIEW2_CONFIG_OVERRIDE_PATH, -} from "./utils/env"; -import { consola } from "./utils/logger"; +} from './utils/env' +import { consola } from './utils/logger' const TAURI_DEV_APP_CONF_PATH = path.join( TAURI_APP_DIR, - "tauri.nightly.conf.json", -); -const TAURI_APP_CONF = path.join(TAURI_APP_DIR, "tauri.conf.json"); + 'tauri.nightly.conf.json', +) +const TAURI_APP_CONF = path.join(TAURI_APP_DIR, 'tauri.conf.json') const TAURI_DEV_APP_OVERRIDES_PATH = path.join( TAURI_APP_DIR, - "overrides/nightly.conf.json", -); -const ROOT_PACKAGE_JSON_PATH = path.join(cwd, "package.json"); + 'overrides/nightly.conf.json', +) +const ROOT_PACKAGE_JSON_PATH = path.join(cwd, 'package.json') const NYANPASU_PACKAGE_JSON_PATH = path.join( cwd, - "frontend/nyanpasu/package.json", -); + 'frontend/nyanpasu/package.json', +) // blocked by https://github.com/tauri-apps/tauri/issues/8447 // const WXS_PATH = path.join(TAURI_APP_DIR, "templates", "nightly.wxs"); -const isNSIS = process.argv.includes("--nsis"); // only build nsis -const isMSI = process.argv.includes("--msi"); // only build msi -const fixedWebview = process.argv.includes("--fixed-webview"); +const isNSIS = process.argv.includes('--nsis') // only build nsis +const isMSI = process.argv.includes('--msi') // only build msi +const fixedWebview = process.argv.includes('--fixed-webview') async function main() { - consola.debug("Read config..."); - const tauriAppConf = await fs.readJSON(TAURI_APP_CONF); - const tauriAppOverrides = await fs.readJSON(TAURI_DEV_APP_OVERRIDES_PATH); - let tauriConf = merge(tauriAppConf, tauriAppOverrides); - const packageJson = await fs.readJSON(NYANPASU_PACKAGE_JSON_PATH); - const rootPackageJson = await fs.readJSON(ROOT_PACKAGE_JSON_PATH); + consola.debug('Read config...') + const tauriAppConf = await fs.readJSON(TAURI_APP_CONF) + const tauriAppOverrides = await fs.readJSON(TAURI_DEV_APP_OVERRIDES_PATH) + let tauriConf = merge(tauriAppConf, tauriAppOverrides) + const packageJson = await fs.readJSON(NYANPASU_PACKAGE_JSON_PATH) + const rootPackageJson = await fs.readJSON(ROOT_PACKAGE_JSON_PATH) // const wxsFile = await fs.readFile(WXS_PATH, "utf-8"); if (fixedWebview) { const fixedWebview2Config = await fs.readJSON( TAURI_FIXED_WEBVIEW2_CONFIG_OVERRIDE_PATH, - ); + ) const webviewPath = (await fs.readdir(TAURI_APP_DIR)).find((file) => - file.includes("WebView2"), - ); + file.includes('WebView2'), + ) if (!webviewPath) { - throw new Error("WebView2 runtime not found"); + throw new Error('WebView2 runtime not found') } - tauriConf = merge(tauriConf, fixedWebview2Config); - delete tauriConf.bundle.windows.webviewInstallMode.silent; - tauriConf.bundle.windows.webviewInstallMode.path = `./${path.basename(webviewPath)}`; + tauriConf = merge(tauriConf, fixedWebview2Config) + delete tauriConf.bundle.windows.webviewInstallMode.silent + tauriConf.bundle.windows.webviewInstallMode.path = `./${path.basename(webviewPath)}` tauriConf.plugins.updater.endpoints = tauriConf.plugins.updater.endpoints.map((o: string) => - o.replace("update-", "update-nightly-"), - ); + o.replace('update-', 'update-nightly-'), + ) } if (isNSIS) { - tauriConf.bundle.targets = ["nsis"]; + tauriConf.bundle.targets = ['nsis'] } - consola.debug("Get current git short hash"); - const GIT_SHORT_HASH = execSync("git rev-parse --short HEAD") + consola.debug('Get current git short hash') + const GIT_SHORT_HASH = execSync('git rev-parse --short HEAD') .toString() - .trim(); - consola.debug(`Current git short hash: ${GIT_SHORT_HASH}`); + .trim() + consola.debug(`Current git short hash: ${GIT_SHORT_HASH}`) - const version = `${tauriConf.version}-alpha+${GIT_SHORT_HASH}`; + const version = `${tauriConf.version}-alpha+${GIT_SHORT_HASH}` // blocked by https://github.com/tauri-apps/tauri/issues/8447 // 1. update wxs version // consola.debug("Write raw version to wxs"); @@ -78,17 +78,17 @@ async function main() { // await fs.writeFile(WXS_PATH, modifiedWxsFile); // consola.debug("wxs updated"); // 2. update tauri version - consola.debug("Write tauri version to tauri.nightly.conf.json"); - if (!isNSIS && !isMSI) tauriConf.version = version; - await fs.writeJSON(TAURI_DEV_APP_CONF_PATH, tauriConf, { spaces: 2 }); - consola.debug("tauri.nightly.conf.json updated"); + consola.debug('Write tauri version to tauri.nightly.conf.json') + if (!isNSIS && !isMSI) tauriConf.version = version + await fs.writeJSON(TAURI_DEV_APP_CONF_PATH, tauriConf, { spaces: 2 }) + consola.debug('tauri.nightly.conf.json updated') // 3. update package version - consola.debug("Write tauri version to package.json"); - packageJson.version = version; - await fs.writeJSON(NYANPASU_PACKAGE_JSON_PATH, packageJson, { spaces: 2 }); - rootPackageJson.version = version; - await fs.writeJSON(ROOT_PACKAGE_JSON_PATH, rootPackageJson, { spaces: 2 }); - consola.debug("package.json updated"); + consola.debug('Write tauri version to package.json') + packageJson.version = version + await fs.writeJSON(NYANPASU_PACKAGE_JSON_PATH, packageJson, { spaces: 2 }) + rootPackageJson.version = version + await fs.writeJSON(ROOT_PACKAGE_JSON_PATH, rootPackageJson, { spaces: 2 }) + consola.debug('package.json updated') } -main(); +main() diff --git a/clash-nyanpasu/scripts/prepare-preview.ts b/clash-nyanpasu/scripts/prepare-preview.ts index b547d2a4a8..937ffe323f 100644 --- a/clash-nyanpasu/scripts/prepare-preview.ts +++ b/clash-nyanpasu/scripts/prepare-preview.ts @@ -1,28 +1,28 @@ -import path from "path"; -import fs from "fs-extra"; -import { TAURI_APP_DIR } from "./utils/env"; -import { consola } from "./utils/logger"; +import path from 'path' +import fs from 'fs-extra' +import { TAURI_APP_DIR } from './utils/env' +import { consola } from './utils/logger' -const TAURI_APP_CONF = path.join(TAURI_APP_DIR, "tauri.conf.json"); +const TAURI_APP_CONF = path.join(TAURI_APP_DIR, 'tauri.conf.json') const TAURI_PREVIEW_APP_CONF_PATH = path.join( TAURI_APP_DIR, - "tauri.preview.conf.json", -); + 'tauri.preview.conf.json', +) const main = async () => { - consola.debug("Read config..."); + consola.debug('Read config...') - const tauriAppConf = await fs.readJSON(TAURI_APP_CONF); + const tauriAppConf = await fs.readJSON(TAURI_APP_CONF) - tauriAppConf.build.devPath = tauriAppConf.build.distDir; - tauriAppConf.build.beforeDevCommand = tauriAppConf.build.beforeBuildCommand; + tauriAppConf.build.devPath = tauriAppConf.build.distDir + tauriAppConf.build.beforeDevCommand = tauriAppConf.build.beforeBuildCommand - consola.debug("Write config..."); + consola.debug('Write config...') await fs.writeJSON(TAURI_PREVIEW_APP_CONF_PATH, tauriAppConf, { spaces: 2, - }); -}; + }) +} -main(); +main() diff --git a/clash-nyanpasu/scripts/prepare-release.ts b/clash-nyanpasu/scripts/prepare-release.ts index d09e870cea..29b4e6da6f 100644 --- a/clash-nyanpasu/scripts/prepare-release.ts +++ b/clash-nyanpasu/scripts/prepare-release.ts @@ -1,32 +1,32 @@ -import path from "node:path"; -import fs from "fs-extra"; -import { merge } from "lodash-es"; +import path from 'node:path' +import fs from 'fs-extra' +import { merge } from 'lodash-es' import { cwd, TAURI_APP_DIR, TAURI_FIXED_WEBVIEW2_CONFIG_OVERRIDE_PATH, -} from "./utils/env"; -import { consola } from "./utils/logger"; +} from './utils/env' +import { consola } from './utils/logger' -const TAURI_APP_CONF = path.join(TAURI_APP_DIR, "tauri.conf.json"); +const TAURI_APP_CONF = path.join(TAURI_APP_DIR, 'tauri.conf.json') // TODO: define overrides // const TAURI_DEV_APP_OVERRIDES_PATH = path.join( // TAURI_APP_DIR, // "overrides/nightly.conf.json", // ); -const PACKAGE_JSON_PATH = path.join(cwd, "package.json"); +const PACKAGE_JSON_PATH = path.join(cwd, 'package.json') // blocked by https://github.com/tauri-apps/tauri/issues/8447 // const WXS_PATH = path.join(TAURI_APP_DIR, "templates", "nightly.wxs"); -const isNSIS = process.argv.includes("--nsis"); // only build nsis -const fixedWebview = process.argv.includes("--fixed-webview"); +const isNSIS = process.argv.includes('--nsis') // only build nsis +const fixedWebview = process.argv.includes('--fixed-webview') async function main() { - consola.debug("Read config..."); - const tauriAppConf = await fs.readJSON(TAURI_APP_CONF); + consola.debug('Read config...') + const tauriAppConf = await fs.readJSON(TAURI_APP_CONF) // const tauriAppOverrides = await fs.readJSON(TAURI_DEV_APP_OVERRIDES_PATH); // const tauriConf = merge(tauriAppConf, tauriAppOverrides); - let tauriConf = tauriAppConf; + let tauriConf = tauriAppConf // const wxsFile = await fs.readFile(WXS_PATH, "utf-8"); // if (isNSIS) { @@ -36,23 +36,23 @@ async function main() { if (fixedWebview) { const fixedWebview2Config = await fs.readJSON( TAURI_FIXED_WEBVIEW2_CONFIG_OVERRIDE_PATH, - ); + ) const webviewPath = (await fs.readdir(TAURI_APP_DIR)).find((file) => - file.includes("WebView2"), - ); + file.includes('WebView2'), + ) if (!webviewPath) { - throw new Error("WebView2 runtime not found"); + throw new Error('WebView2 runtime not found') } - tauriConf = merge(tauriConf, fixedWebview2Config); - delete tauriConf.bundle.windows.webviewInstallMode.silent; - tauriConf.bundle.windows.webviewInstallMode.path = `./${path.basename(webviewPath)}`; + tauriConf = merge(tauriConf, fixedWebview2Config) + delete tauriConf.bundle.windows.webviewInstallMode.silent + tauriConf.bundle.windows.webviewInstallMode.path = `./${path.basename(webviewPath)}` } - consola.debug("Write tauri version to tauri.conf.json"); - await fs.writeJSON(TAURI_APP_CONF, tauriConf, { spaces: 2 }); - consola.debug("tauri.conf.json updated"); + consola.debug('Write tauri version to tauri.conf.json') + await fs.writeJSON(TAURI_APP_CONF, tauriConf, { spaces: 2 }) + consola.debug('tauri.conf.json updated') - consola.debug("package.json updated"); + consola.debug('package.json updated') } -main(); +main() diff --git a/clash-nyanpasu/scripts/publish.ts b/clash-nyanpasu/scripts/publish.ts index 7ce6b815c4..e804ec0e8d 100644 --- a/clash-nyanpasu/scripts/publish.ts +++ b/clash-nyanpasu/scripts/publish.ts @@ -1,48 +1,48 @@ -import path from "node:path"; -import fs from "fs-extra"; -import packageJson from "../package.json"; -import { cwd, TAURI_APP_DIR } from "./utils/env"; +import path from 'node:path' +import fs from 'fs-extra' +import packageJson from '../package.json' +import { cwd, TAURI_APP_DIR } from './utils/env' const MONO_REPO_PATHS = [ - path.join(cwd, "frontend/nyanpasu"), - path.join(cwd, "frontend/ui"), - path.join(cwd, "frontend/interface"), - path.join(cwd, "scripts"), -]; + path.join(cwd, 'frontend/nyanpasu'), + path.join(cwd, 'frontend/ui'), + path.join(cwd, 'frontend/interface'), + path.join(cwd, 'scripts'), +] // import { consola } from "./utils/logger"; -const TAURI_APP_CONF_PATH = path.join(TAURI_APP_DIR, "tauri.conf.json"); +const TAURI_APP_CONF_PATH = path.join(TAURI_APP_DIR, 'tauri.conf.json') const TAURI_NIGHTLY_APP_CONF_PATH = path.join( TAURI_APP_DIR, - "overrides/nightly.conf.json", -); -const PACKAGE_JSON_PATH = path.join(cwd, "package.json"); + 'overrides/nightly.conf.json', +) +const PACKAGE_JSON_PATH = path.join(cwd, 'package.json') // publish async function resolvePublish() { - const flag = process.argv[2] ?? "patch"; - const tauriJson = await fs.readJSON(TAURI_APP_CONF_PATH); - const tauriNightlyJson = await fs.readJSON(TAURI_NIGHTLY_APP_CONF_PATH); + const flag = process.argv[2] ?? 'patch' + const tauriJson = await fs.readJSON(TAURI_APP_CONF_PATH) + const tauriNightlyJson = await fs.readJSON(TAURI_NIGHTLY_APP_CONF_PATH) - let [a, b, c] = packageJson.version.split(".").map(Number); + let [a, b, c] = packageJson.version.split('.').map(Number) - if (flag === "major") { - a += 1; - b = 0; - c = 0; - } else if (flag === "minor") { - b += 1; - c = 0; - } else if (flag === "patch") { - c += 1; - } else throw new Error(`invalid flag "${flag}"`); + if (flag === 'major') { + a += 1 + b = 0 + c = 0 + } else if (flag === 'minor') { + b += 1 + c = 0 + } else if (flag === 'patch') { + c += 1 + } else throw new Error(`invalid flag "${flag}"`) - const nextVersion = `${a}.${b}.${c}`; - const nextNightlyVersion = `${a}.${b}.${c + 1}`; - packageJson.version = nextVersion; - tauriJson.package.version = nextVersion; - tauriNightlyJson.package.version = nextNightlyVersion; + const nextVersion = `${a}.${b}.${c}` + const nextNightlyVersion = `${a}.${b}.${c + 1}` + packageJson.version = nextVersion + tauriJson.package.version = nextVersion + tauriNightlyJson.package.version = nextNightlyVersion // 发布更新前先写更新日志 // const nextTag = `v${nextVersion}`; @@ -50,22 +50,22 @@ async function resolvePublish() { await fs.writeJSON(PACKAGE_JSON_PATH, packageJson, { spaces: 2, - }); + }) await fs.writeJSON(TAURI_APP_CONF_PATH, tauriJson, { spaces: 2, - }); + }) await fs.writeJSON(TAURI_NIGHTLY_APP_CONF_PATH, tauriNightlyJson, { spaces: 2, - }); + }) // overrides mono repo package.json for (const monoRepoPath of MONO_REPO_PATHS) { - const monoRepoPackageJsonPath = path.join(monoRepoPath, "package.json"); - const monoRepoPackageJson = await fs.readJSON(monoRepoPackageJsonPath); - monoRepoPackageJson.version = nextVersion; + const monoRepoPackageJsonPath = path.join(monoRepoPath, 'package.json') + const monoRepoPackageJson = await fs.readJSON(monoRepoPackageJsonPath) + monoRepoPackageJson.version = nextVersion await fs.writeJSON(monoRepoPackageJsonPath, monoRepoPackageJson, { spaces: 2, - }); + }) } // execSync("git add ./package.json"); @@ -75,7 +75,7 @@ async function resolvePublish() { // execSync(`git push`); // execSync(`git push origin v${nextVersion}`); // consola.success(`Publish Successfully...`); - console.log(nextVersion); + console.log(nextVersion) } -resolvePublish(); +resolvePublish() diff --git a/clash-nyanpasu/scripts/telegram-notify.ts b/clash-nyanpasu/scripts/telegram-notify.ts index 3e83d34fb3..bead34dd14 100644 --- a/clash-nyanpasu/scripts/telegram-notify.ts +++ b/clash-nyanpasu/scripts/telegram-notify.ts @@ -1,238 +1,235 @@ // import { Telegraf } from "telegraf"; -import { existsSync } from "fs"; -import path from "path"; -import { fstat, mkdirp } from "fs-extra"; -import pRetry from "p-retry"; -import { getOctokit } from "@actions/github"; -import { version } from "../package.json"; -import { array2text, getFileSize } from "./utils"; -import { downloadFile } from "./utils/download"; -import { TEMP_DIR } from "./utils/env"; -import { consola } from "./utils/logger"; -import { GIT_SHORT_HASH } from "./utils/shell"; -import { client } from "./utils/telegram"; +import { existsSync } from 'fs' +import path from 'path' +import { fstat, mkdirp } from 'fs-extra' +import pRetry from 'p-retry' +import { getOctokit } from '@actions/github' +import { version } from '../package.json' +import { array2text, getFileSize } from './utils' +import { downloadFile } from './utils/download' +import { TEMP_DIR } from './utils/env' +import { consola } from './utils/logger' +import { GIT_SHORT_HASH } from './utils/shell' +import { client } from './utils/telegram' -const nightlyBuild = process.argv.includes("--nightly"); +const nightlyBuild = process.argv.includes('--nightly') if (!process.env.TELEGRAM_TOKEN) { - throw new Error("TELEGRAM_TOKEN is required"); + throw new Error('TELEGRAM_TOKEN is required') } -const TELEGRAM_TOKEN = process.env.TELEGRAM_TOKEN; +const TELEGRAM_TOKEN = process.env.TELEGRAM_TOKEN if (!process.env.TELEGRAM_TO) { - throw new Error("TELEGRAM_TO is required"); + throw new Error('TELEGRAM_TO is required') } -const TELEGRAM_TO = process.env.TELEGRAM_TO; +const TELEGRAM_TO = process.env.TELEGRAM_TO if (!process.env.TELEGRAM_TO_NIGHTLY) { - throw new Error("TELEGRAM_TO_NIGHTLY is required"); + throw new Error('TELEGRAM_TO_NIGHTLY is required') } -const TELEGRAM_TO_NIGHTLY = process.env.TELEGRAM_TO_NIGHTLY; +const TELEGRAM_TO_NIGHTLY = process.env.TELEGRAM_TO_NIGHTLY if (!process.env.GITHUB_TOKEN) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } -const GITHUB_TOKEN = process.env.GITHUB_TOKEN; +const GITHUB_TOKEN = process.env.GITHUB_TOKEN -const WORKFLOW_RUN_ID = process.env.WORKFLOW_RUN_ID; +const WORKFLOW_RUN_ID = process.env.WORKFLOW_RUN_ID const resourceFormats = [ - ".exe", - "portable.zip", - ".rpm", - ".deb", - ".dmg", - ".AppImage", -]; + '.exe', + 'portable.zip', + '.rpm', + '.deb', + '.dmg', + '.AppImage', +] const isValidFormat = (fileName: string): boolean => { - return resourceFormats.some((format) => fileName.endsWith(format)); -}; + return resourceFormats.some((format) => fileName.endsWith(format)) +} const repoInfo = { - owner: "libnyanpasu", - repo: "clash-nyanpasu", -}; + owner: 'libnyanpasu', + repo: 'clash-nyanpasu', +} -(async () => { +;(async () => { await client.start({ botAuthToken: TELEGRAM_TOKEN, - }); + }) - const github = getOctokit(GITHUB_TOKEN); + const github = getOctokit(GITHUB_TOKEN) const content = nightlyBuild ? await github.rest.repos.getReleaseByTag({ ...repoInfo, - tag: "pre-release", + tag: 'pre-release', }) - : await github.rest.repos.getLatestRelease(repoInfo); + : await github.rest.repos.getLatestRelease(repoInfo) - const downloadTasks: Promise[] = []; + const downloadTasks: Promise[] = [] - const resourceMapping: string[] = []; + const resourceMapping: string[] = [] content.data.assets.forEach((asset) => { if (isValidFormat(asset.name)) { - const _path = path.join(TEMP_DIR, asset.name); + const _path = path.join(TEMP_DIR, asset.name) - resourceMapping.push(_path); + resourceMapping.push(_path) downloadTasks.push( pRetry(() => downloadFile(asset.browser_download_url, _path), { retries: 5, }), - ); + ) } - }); + }) try { - mkdirp(TEMP_DIR); + mkdirp(TEMP_DIR) - await Promise.all(downloadTasks); + await Promise.all(downloadTasks) } catch (error) { - consola.error(error); - throw new Error("Error during download or upload tasks"); + consola.error(error) + throw new Error('Error during download or upload tasks') } resourceMapping.forEach((item) => { - consola.log( - `founded ${item}, size: ${getFileSize(item)}`, - existsSync(item), - ); - }); + consola.log(`founded ${item}, size: ${getFileSize(item)}`, existsSync(item)) + }) if (!nightlyBuild) { await client.sendMessage(TELEGRAM_TO, { message: array2text([ `Clash Nyanpasu ${version} Released!`, - "", - "Check out on GitHub:", + '', + 'Check out on GitHub:', ` - https://github.com/libnyanpasu/clash-nyanpasu/releases/tag/v${version}`, ]), - }); - consola.success("Send release message to telegram successfully"); + }) + consola.success('Send release message to telegram successfully') } else { await client.sendMessage(TELEGRAM_TO_NIGHTLY, { message: array2text([ `Clash Nyanpasu Nightly Build ${GIT_SHORT_HASH} released!`, - "", - "Could be unstable, use at your own risk. Download at:", + '', + 'Could be unstable, use at your own risk. Download at:', `- https://github.com/libnyanpasu/clash-nyanpasu/actions/runs/${WORKFLOW_RUN_ID}`, - "", - "You could also waiting for the telegram bot to upload the binaries, although it may take a while or even fail.", + '', + 'You could also waiting for the telegram bot to upload the binaries, although it may take a while or even fail.', ]), - }); + }) } - consola.start("Staring upload tasks (nightly)"); + consola.start('Staring upload tasks (nightly)') // upload windows binary - consola.info("starting upload windows related binary: here is the list:"); - let filtered_file = resourceMapping.filter( + consola.info('starting upload windows related binary: here is the list:') + let filteredFile = resourceMapping.filter( (item) => - !item.includes("fixed-webview") && - (item.endsWith(".exe") || item.endsWith("portable.zip")), - ); - filtered_file.forEach((v) => { - consola.debug(`file: ${v}, size:${getFileSize(v)}`); - }); + !item.includes('fixed-webview') && + (item.endsWith('.exe') || item.endsWith('portable.zip')), + ) + filteredFile.forEach((v) => { + consola.debug(`file: ${v}, size:${getFileSize(v)}`) + }) await pRetry( () => client.sendFile(TELEGRAM_TO_NIGHTLY, { - file: filtered_file, + file: filteredFile, forceDocument: true, caption: `Clash Nyanpasu Nightly Build ${GIT_SHORT_HASH} for Windows`, workers: 16, progressCallback: (...args) => { - console.log("progressCallback", args); + console.log('progressCallback', args) }, }), { retries: 5 }, - ); + ) - consola.info("starting upload macos related binary: here is the list:"); - filtered_file = resourceMapping.filter((item) => item.endsWith(".dmg")); - filtered_file.forEach((v) => { - consola.debug(`file: ${v}, size:${getFileSize(v)}`); - }); + consola.info('starting upload macos related binary: here is the list:') + filteredFile = resourceMapping.filter((item) => item.endsWith('.dmg')) + filteredFile.forEach((v) => { + consola.debug(`file: ${v}, size:${getFileSize(v)}`) + }) // upload macOS binary await pRetry( () => client.sendFile(TELEGRAM_TO_NIGHTLY, { - file: filtered_file, + file: filteredFile, forceDocument: true, caption: `Clash Nyanpasu Nightly Build ${GIT_SHORT_HASH} for macOS`, workers: 16, }), { retries: 5 }, - ); + ) consola.info( - "starting upload Linux related binary, part 1: here is the list:", - ); - filtered_file = resourceMapping.filter( + 'starting upload Linux related binary, part 1: here is the list:', + ) + filteredFile = resourceMapping.filter( (item) => - (item.endsWith(".rpm") || - item.endsWith(".deb") || - item.endsWith(".AppImage")) && - !item.includes("armel") && - !item.includes("armhf"), - ); - filtered_file.forEach((v) => { - consola.debug(`file: ${v}, size:${getFileSize(v)}`); - }); + (item.endsWith('.rpm') || + item.endsWith('.deb') || + item.endsWith('.AppImage')) && + !item.includes('armel') && + !item.includes('armhf'), + ) + filteredFile.forEach((v) => { + consola.debug(`file: ${v}, size:${getFileSize(v)}`) + }) // upload linux binary await pRetry( () => client.sendFile(TELEGRAM_TO_NIGHTLY, { - file: filtered_file, + file: filteredFile, forceDocument: true, caption: `Clash Nyanpasu Nightly Build ${GIT_SHORT_HASH} for Linux main target`, workers: 16, }), { retries: 5 }, - ); + ) consola.info( - "starting upload Linux related binary, part 2: here is the list:", - ); - filtered_file = resourceMapping.filter( + 'starting upload Linux related binary, part 2: here is the list:', + ) + filteredFile = resourceMapping.filter( (item) => - ((item.endsWith(".rpm") || - item.endsWith(".deb") || - item.endsWith(".AppImage")) && - item.includes("armel")) || - item.includes("armhf"), - ); - filtered_file.forEach((v) => { - consola.debug(`file: ${v}, size:${getFileSize(v)}`); - }); + ((item.endsWith('.rpm') || + item.endsWith('.deb') || + item.endsWith('.AppImage')) && + item.includes('armel')) || + item.includes('armhf'), + ) + filteredFile.forEach((v) => { + consola.debug(`file: ${v}, size:${getFileSize(v)}`) + }) // upload linux binary await pRetry( () => client.sendFile(TELEGRAM_TO_NIGHTLY, { - file: filtered_file, + file: filteredFile, forceDocument: true, caption: `Clash Nyanpasu Nightly Build ${GIT_SHORT_HASH} for Linux armv7 target`, workers: 16, }), { retries: 5 }, - ); + ) - consola.success("Upload finished (nightly)"); + consola.success('Upload finished (nightly)') - await client.disconnect(); + await client.disconnect() - process.exit(); + process.exit() })().catch((error) => { - consola.fatal(error); - process.exit(1); -}); + consola.fatal(error) + process.exit(1) +}) diff --git a/clash-nyanpasu/scripts/types/index.ts b/clash-nyanpasu/scripts/types/index.ts index 14fdb76291..89fdb3f1cf 100644 --- a/clash-nyanpasu/scripts/types/index.ts +++ b/clash-nyanpasu/scripts/types/index.ts @@ -1,48 +1,48 @@ -import { ArchMapping } from "utils/manifest"; +import { ArchMapping } from 'utils/manifest' export interface ClashManifest { - URL_PREFIX: string; - LATEST_DATE?: string; - STORAGE_PREFIX?: string; - BACKUP_URL_PREFIX?: string; - BACKUP_LATEST_DATE?: string; - VERSION?: string; - VERSION_URL?: string; - ARCH_MAPPING: ArchMapping; + URL_PREFIX: string + LATEST_DATE?: string + STORAGE_PREFIX?: string + BACKUP_URL_PREFIX?: string + BACKUP_LATEST_DATE?: string + VERSION?: string + VERSION_URL?: string + ARCH_MAPPING: ArchMapping } export interface BinInfo { - name: string; - targetFile: string; - exeFile: string; - tmpFile: string; - downloadURL: string; + name: string + targetFile: string + exeFile: string + tmpFile: string + downloadURL: string } export enum SupportedArch { - WindowsX86_32 = "windows-i386", - WindowsX86_64 = "windows-x86_64", - WindowsArm64 = "windows-arm64", - LinuxAarch64 = "linux-aarch64", - LinuxAmd64 = "linux-amd64", - LinuxI386 = "linux-i386", - LinuxArmv7 = "linux-armv7", - LinuxArmv7hf = "linux-armv7hf", - DarwinArm64 = "darwin-arm64", - DarwinX64 = "darwin-x64", + WindowsX86_32 = 'windows-i386', + WindowsX86_64 = 'windows-x86_64', + WindowsArm64 = 'windows-arm64', + LinuxAarch64 = 'linux-aarch64', + LinuxAmd64 = 'linux-amd64', + LinuxI386 = 'linux-i386', + LinuxArmv7 = 'linux-armv7', + LinuxArmv7hf = 'linux-armv7hf', + DarwinArm64 = 'darwin-arm64', + DarwinX64 = 'darwin-x64', } export enum SupportedCore { - Mihomo = "mihomo", - MihomoAlpha = "mihomo_alpha", - ClashRs = "clash_rs", - ClashRsAlpha = "clash_rs_alpha", - ClashPremium = "clash_premium", + Mihomo = 'mihomo', + MihomoAlpha = 'mihomo_alpha', + ClashRs = 'clash_rs', + ClashRsAlpha = 'clash_rs_alpha', + ClashPremium = 'clash_premium', } export interface ManifestVersion { - manifest_version: number; - latest: { [K in SupportedCore]: string }; - arch_template: { [K in SupportedCore]: ArchMapping }; - updated_at: string; // ISO 8601 + manifest_version: number + latest: { [K in SupportedCore]: string } + arch_template: { [K in SupportedCore]: ArchMapping } + updated_at: string // ISO 8601 } diff --git a/clash-nyanpasu/scripts/updatelog.ts b/clash-nyanpasu/scripts/updatelog.ts index a1a6523772..2c56057a55 100644 --- a/clash-nyanpasu/scripts/updatelog.ts +++ b/clash-nyanpasu/scripts/updatelog.ts @@ -1,43 +1,43 @@ -import path from "path"; -import fs from "fs-extra"; -import { cwd } from "./utils/env"; +import path from 'path' +import fs from 'fs-extra' +import { cwd } from './utils/env' -const UPDATE_LOG = "UPDATELOG.md"; +const UPDATE_LOG = 'UPDATELOG.md' // parse the UPDATELOG.md export async function resolveUpdateLog(tag: string) { - const reTitle = /^## v[\d\.]+/; - const reEnd = /^---/; + const reTitle = /^## v[\d.]+/ + const reEnd = /^---/ - const file = path.join(cwd, UPDATE_LOG); + const file = path.join(cwd, UPDATE_LOG) if (!(await fs.pathExists(file))) { - throw new Error("could not found UPDATELOG.md"); + throw new Error('could not found UPDATELOG.md') } - const data = await fs.readFile(file).then((d) => d.toString("utf8")); + const data = await fs.readFile(file).then((d) => d.toString('utf8')) - const map = {} as Record; - let p = ""; + const map = {} as Record + let p = '' - data.split("\n").forEach((line) => { + data.split('\n').forEach((line) => { if (reTitle.test(line)) { - p = line.slice(3).trim(); + p = line.slice(3).trim() if (!map[p]) { - map[p] = []; + map[p] = [] } else { - throw new Error(`Tag ${p} dup`); + throw new Error(`Tag ${p} dup`) } } else if (reEnd.test(line)) { - p = ""; + p = '' } else if (p) { - map[p].push(line); + map[p].push(line) } - }); + }) if (!map[tag]) { - throw new Error(`could not found "${tag}" in UPDATELOG.md`); + throw new Error(`could not found "${tag}" in UPDATELOG.md`) } - return map[tag].join("\n").trim(); + return map[tag].join('\n').trim() } diff --git a/clash-nyanpasu/scripts/updater-nightly.ts b/clash-nyanpasu/scripts/updater-nightly.ts index f944f97683..2844a078c2 100644 --- a/clash-nyanpasu/scripts/updater-nightly.ts +++ b/clash-nyanpasu/scripts/updater-nightly.ts @@ -1,193 +1,193 @@ -import { execSync } from "child_process"; -import { camelCase, upperFirst } from "lodash-es"; -import fetch from "node-fetch"; -import { context, getOctokit } from "@actions/github"; -import tauriNightly from "../backend/tauri/overrides/nightly.conf.json"; -import { getGithubUrl } from "./utils"; -import { consola } from "./utils/logger"; +import { execSync } from 'child_process' +import { camelCase, upperFirst } from 'lodash-es' +import fetch from 'node-fetch' +import { context, getOctokit } from '@actions/github' +import tauriNightly from '../backend/tauri/overrides/nightly.conf.json' +import { getGithubUrl } from './utils' +import { consola } from './utils/logger' -const UPDATE_TAG_NAME = "updater"; -const UPDATE_JSON_FILE = "update-nightly.json"; -const UPDATE_JSON_PROXY = "update-nightly-proxy.json"; -const UPDATE_FIXED_WEBVIEW_FILE = "update-nightly-fixed-webview.json"; -const UPDATE_FIXED_WEBVIEW_PROXY = "update-nightly-fixed-webview-proxy.json"; +const UPDATE_TAG_NAME = 'updater' +const UPDATE_JSON_FILE = 'update-nightly.json' +const UPDATE_JSON_PROXY = 'update-nightly-proxy.json' +const UPDATE_FIXED_WEBVIEW_FILE = 'update-nightly-fixed-webview.json' +const UPDATE_FIXED_WEBVIEW_PROXY = 'update-nightly-fixed-webview-proxy.json' -const isFixedWebview = process.argv.includes("--fixed-webview"); +const isFixedWebview = process.argv.includes('--fixed-webview') /// generate update.json /// upload to update tag's release asset async function resolveUpdater() { if (process.env.GITHUB_TOKEN === undefined) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } - consola.start("start to generate updater files"); + consola.start('start to generate updater files') const options = { owner: context.repo.owner, repo: context.repo.repo, - }; - const github = getOctokit(process.env.GITHUB_TOKEN); + } + const github = getOctokit(process.env.GITHUB_TOKEN) - consola.debug("resolve latest pre-release files..."); + consola.debug('resolve latest pre-release files...') // latest pre-release tag const { data: latestPreRelease } = await github.rest.repos.getReleaseByTag({ ...options, - tag: "pre-release", - }); + tag: 'pre-release', + }) const shortHash = await execSync(`git rev-parse --short pre-release`) .toString() - .replace("\n", "") - .replace("\r", ""); - consola.info(`latest pre-release short hash: ${shortHash}`); + .replace('\n', '') + .replace('\r', '') + consola.info(`latest pre-release short hash: ${shortHash}`) const updateData = { name: `v${tauriNightly.version}-alpha+${shortHash}`, - notes: "Nightly build. Full changes see commit history.", + notes: 'Nightly build. Full changes see commit history.', pub_date: new Date().toISOString(), platforms: { - win64: { signature: "", url: "" }, // compatible with older formats - linux: { signature: "", url: "" }, // compatible with older formats - darwin: { signature: "", url: "" }, // compatible with older formats - "darwin-aarch64": { signature: "", url: "" }, - "darwin-intel": { signature: "", url: "" }, - "darwin-x86_64": { signature: "", url: "" }, - "linux-x86_64": { signature: "", url: "" }, + win64: { signature: '', url: '' }, // compatible with older formats + linux: { signature: '', url: '' }, // compatible with older formats + darwin: { signature: '', url: '' }, // compatible with older formats + 'darwin-aarch64': { signature: '', url: '' }, + 'darwin-intel': { signature: '', url: '' }, + 'darwin-x86_64': { signature: '', url: '' }, + 'linux-x86_64': { signature: '', url: '' }, // "linux-aarch64": { signature: "", url: "" }, // "linux-armv7": { signature: "", url: "" }, - "windows-x86_64": { signature: "", url: "" }, - "windows-i686": { signature: "", url: "" }, - "windows-aarch64": { signature: "", url: "" }, + 'windows-x86_64': { signature: '', url: '' }, + 'windows-i686': { signature: '', url: '' }, + 'windows-aarch64': { signature: '', url: '' }, }, - }; + } const promises = latestPreRelease.assets.map(async (asset) => { - const { name, browser_download_url } = asset; + const { name, browser_download_url: browserDownloadUrl } = asset function isMatch(name: string, extension: string, arch: string) { return ( name.endsWith(extension) && name.includes(arch) && (isFixedWebview - ? name.includes("fixed-webview") - : !name.includes("fixed-webview")) - ); + ? name.includes('fixed-webview') + : !name.includes('fixed-webview')) + ) } // win64 url - if (isMatch(name, ".nsis.zip", "x64")) { - updateData.platforms.win64.url = browser_download_url; - updateData.platforms["windows-x86_64"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'x64')) { + updateData.platforms.win64.url = browserDownloadUrl + updateData.platforms['windows-x86_64'].url = browserDownloadUrl } // win64 signature - if (isMatch(name, ".nsis.zip.sig", "x64")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.win64.signature = sig; - updateData.platforms["windows-x86_64"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'x64')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.win64.signature = sig + updateData.platforms['windows-x86_64'].signature = sig } // win32 url - if (isMatch(name, ".nsis.zip", "x86")) { - updateData.platforms["windows-i686"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'x86')) { + updateData.platforms['windows-i686'].url = browserDownloadUrl } // win32 signature - if (isMatch(name, ".nsis.zip.sig", "x86")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["windows-i686"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'x86')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['windows-i686'].signature = sig } // win arm64 url - if (isMatch(name, ".nsis.zip", "arm64")) { - updateData.platforms["windows-aarch64"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'arm64')) { + updateData.platforms['windows-aarch64'].url = browserDownloadUrl } // win arm64 signature - if (isMatch(name, ".nsis.zip.sig", "arm64")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["windows-aarch64"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'arm64')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['windows-aarch64'].signature = sig } // darwin url (intel) - if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) { - updateData.platforms.darwin.url = browser_download_url; - updateData.platforms["darwin-intel"].url = browser_download_url; - updateData.platforms["darwin-x86_64"].url = browser_download_url; + if (name.endsWith('.app.tar.gz') && !name.includes('aarch')) { + updateData.platforms.darwin.url = browserDownloadUrl + updateData.platforms['darwin-intel'].url = browserDownloadUrl + updateData.platforms['darwin-x86_64'].url = browserDownloadUrl } // darwin signature (intel) - if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.darwin.signature = sig; - updateData.platforms["darwin-intel"].signature = sig; - updateData.platforms["darwin-x86_64"].signature = sig; + if (name.endsWith('.app.tar.gz.sig') && !name.includes('aarch')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.darwin.signature = sig + updateData.platforms['darwin-intel'].signature = sig + updateData.platforms['darwin-x86_64'].signature = sig } // darwin url (aarch) - if (name.endsWith("aarch64.app.tar.gz")) { - updateData.platforms["darwin-aarch64"].url = browser_download_url; + if (name.endsWith('aarch64.app.tar.gz')) { + updateData.platforms['darwin-aarch64'].url = browserDownloadUrl } // darwin signature (aarch) - if (name.endsWith("aarch64.app.tar.gz.sig")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["darwin-aarch64"].signature = sig; + if (name.endsWith('aarch64.app.tar.gz.sig')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['darwin-aarch64'].signature = sig } // linux url - if (name.endsWith(".AppImage.tar.gz")) { - updateData.platforms.linux.url = browser_download_url; - updateData.platforms["linux-x86_64"].url = browser_download_url; + if (name.endsWith('.AppImage.tar.gz')) { + updateData.platforms.linux.url = browserDownloadUrl + updateData.platforms['linux-x86_64'].url = browserDownloadUrl } // linux signature - if (name.endsWith(".AppImage.tar.gz.sig")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.linux.signature = sig; - updateData.platforms["linux-x86_64"].signature = sig; + if (name.endsWith('.AppImage.tar.gz.sig')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.linux.signature = sig + updateData.platforms['linux-x86_64'].signature = sig } - }); + }) - await Promise.allSettled(promises); - consola.info(updateData); + await Promise.allSettled(promises) + consola.info(updateData) - consola.debug("generate updater metadata..."); + consola.debug('generate updater metadata...') // maybe should test the signature as well // delete the null field Object.entries(updateData.platforms).forEach(([key, value]) => { if (!value.url) { - consola.error(`failed to parse release for "${key}"`); - delete updateData.platforms[key as keyof typeof updateData.platforms]; + consola.error(`failed to parse release for "${key}"`) + delete updateData.platforms[key as keyof typeof updateData.platforms] } - }); + }) // 生成一个代理github的更新文件 // 使用 https://hub.fastgit.xyz/ 做github资源的加速 const updateDataNew = JSON.parse( JSON.stringify(updateData), - ) as typeof updateData; + ) as typeof updateData Object.entries(updateDataNew.platforms).forEach(([key, value]) => { if (value.url) { updateDataNew.platforms[key as keyof typeof updateData.platforms].url = - getGithubUrl(value.url); + getGithubUrl(value.url) } else { - consola.error(`updateDataNew.platforms.${key} is null`); + consola.error(`updateDataNew.platforms.${key} is null`) } - }); + }) // update the update.json - consola.debug("update updater files..."); - let updateRelease; + consola.debug('update updater files...') + let updateRelease try { const { data } = await github.rest.repos.getReleaseByTag({ ...options, tag: UPDATE_TAG_NAME, - }); - updateRelease = data; + }) + updateRelease = data } catch (err) { - consola.error(err); - consola.error("failed to get release by tag, create one"); + consola.error(err) + consola.error('failed to get release by tag, create one') const { data } = await github.rest.repos.createRelease({ ...options, tag_name: UPDATE_TAG_NAME, name: upperFirst(camelCase(UPDATE_TAG_NAME)), - body: "files for programs to check for updates", + body: 'files for programs to check for updates', prerelease: true, - }); - updateRelease = data; + }) + updateRelease = data } // delete the old assets @@ -200,7 +200,7 @@ async function resolveUpdater() { await github.rest.repos.deleteReleaseAsset({ ...options, asset_id: asset.id, - }); + }) } if ( @@ -211,8 +211,8 @@ async function resolveUpdater() { await github.rest.repos .deleteReleaseAsset({ ...options, asset_id: asset.id }) .catch((err) => { - consola.error(err); - }); // do not break the pipeline + consola.error(err) + }) // do not break the pipeline } } @@ -222,28 +222,28 @@ async function resolveUpdater() { release_id: updateRelease.id, name: isFixedWebview ? UPDATE_FIXED_WEBVIEW_FILE : UPDATE_JSON_FILE, data: JSON.stringify(updateData, null, 2), - }); + }) await github.rest.repos.uploadReleaseAsset({ ...options, release_id: updateRelease.id, name: isFixedWebview ? UPDATE_FIXED_WEBVIEW_PROXY : UPDATE_JSON_PROXY, data: JSON.stringify(updateDataNew, null, 2), - }); - consola.success("updater files updated"); + }) + consola.success('updater files updated') } // get the signature file content async function getSignature(url: string) { const response = await fetch(url, { - method: "GET", - headers: { "Content-Type": "application/octet-stream" }, - }); + method: 'GET', + headers: { 'Content-Type': 'application/octet-stream' }, + }) - return response.text(); + return response.text() } resolveUpdater().catch((err) => { - consola.fatal(err); - process.exit(1); -}); + consola.fatal(err) + process.exit(1) +}) diff --git a/clash-nyanpasu/scripts/updater.ts b/clash-nyanpasu/scripts/updater.ts index 918c1d5a20..8629590380 100644 --- a/clash-nyanpasu/scripts/updater.ts +++ b/clash-nyanpasu/scripts/updater.ts @@ -1,49 +1,49 @@ -import fetch from "node-fetch"; -import { context, getOctokit } from "@actions/github"; -import { resolveUpdateLog } from "./updatelog"; -import { getGithubUrl } from "./utils"; -import { colorize, consola } from "./utils/logger"; +import fetch from 'node-fetch' +import { context, getOctokit } from '@actions/github' +import { resolveUpdateLog } from './updatelog' +import { getGithubUrl } from './utils' +import { colorize, consola } from './utils/logger' -const UPDATE_TAG_NAME = "updater"; -const UPDATE_JSON_FILE = "update.json"; -const UPDATE_JSON_PROXY = "update-proxy.json"; -const UPDATE_FIXED_WEBVIEW_FILE = "update-fixed-webview.json"; -const UPDATE_FIXED_WEBVIEW_PROXY = "update-fixed-webview-proxy.json"; -const UPDATE_RELEASE_BODY = process.env.RELEASE_BODY || ""; +const UPDATE_TAG_NAME = 'updater' +const UPDATE_JSON_FILE = 'update.json' +const UPDATE_JSON_PROXY = 'update-proxy.json' +const UPDATE_FIXED_WEBVIEW_FILE = 'update-fixed-webview.json' +const UPDATE_FIXED_WEBVIEW_PROXY = 'update-fixed-webview-proxy.json' +const UPDATE_RELEASE_BODY = process.env.RELEASE_BODY || '' -const isFixedWebview = process.argv.includes("--fixed-webview"); +const isFixedWebview = process.argv.includes('--fixed-webview') /// generate update.json /// upload to update tag's release asset async function resolveUpdater() { if (process.env.GITHUB_TOKEN === undefined) { - throw new Error("GITHUB_TOKEN is required"); + throw new Error('GITHUB_TOKEN is required') } - const options = { owner: context.repo.owner, repo: context.repo.repo }; - const github = getOctokit(process.env.GITHUB_TOKEN); + const options = { owner: context.repo.owner, repo: context.repo.repo } + const github = getOctokit(process.env.GITHUB_TOKEN) const { data: tags } = await github.rest.repos.listTags({ ...options, per_page: 10, page: 1, - }); + }) // get the latest publish tag - const tag = tags.find((t) => t.name.startsWith("v")); - if (!tag) throw new Error("could not found the latest tag"); - consola.debug(colorize`latest tag: {gray.bold ${tag.name}}`); + const tag = tags.find((t) => t.name.startsWith('v')) + if (!tag) throw new Error('could not found the latest tag') + consola.debug(colorize`latest tag: {gray.bold ${tag.name}}`) const { data: latestRelease } = await github.rest.repos.getReleaseByTag({ ...options, tag: tag.name, - }); + }) - let updateLog: string | null = null; + let updateLog: string | null = null try { - updateLog = await resolveUpdateLog(tag.name); + updateLog = await resolveUpdateLog(tag.name) } catch (err) { - consola.error(err); + consola.error(err) } const updateData = { @@ -51,135 +51,135 @@ async function resolveUpdater() { notes: UPDATE_RELEASE_BODY || updateLog || latestRelease.body, pub_date: new Date().toISOString(), platforms: { - win64: { signature: "", url: "" }, // compatible with older formats - linux: { signature: "", url: "" }, // compatible with older formats - darwin: { signature: "", url: "" }, // compatible with older formats - "darwin-aarch64": { signature: "", url: "" }, - "darwin-intel": { signature: "", url: "" }, - "darwin-x86_64": { signature: "", url: "" }, - "linux-x86_64": { signature: "", url: "" }, + win64: { signature: '', url: '' }, // compatible with older formats + linux: { signature: '', url: '' }, // compatible with older formats + darwin: { signature: '', url: '' }, // compatible with older formats + 'darwin-aarch64': { signature: '', url: '' }, + 'darwin-intel': { signature: '', url: '' }, + 'darwin-x86_64': { signature: '', url: '' }, + 'linux-x86_64': { signature: '', url: '' }, // "linux-aarch64": { signature: "", url: "" }, // "linux-armv7": { signature: "", url: "" }, - "windows-x86_64": { signature: "", url: "" }, - "windows-i686": { signature: "", url: "" }, - "windows-aarch64": { signature: "", url: "" }, + 'windows-x86_64': { signature: '', url: '' }, + 'windows-i686': { signature: '', url: '' }, + 'windows-aarch64': { signature: '', url: '' }, }, - }; + } const promises = latestRelease.assets.map(async (asset) => { - const { name, browser_download_url } = asset; + const { name, browser_download_url: browserDownloadUrl } = asset function isMatch(name: string, extension: string, arch: string) { return ( name.endsWith(extension) && name.includes(arch) && (isFixedWebview - ? name.includes("fixed-webview") - : !name.includes("fixed-webview")) - ); + ? name.includes('fixed-webview') + : !name.includes('fixed-webview')) + ) } // win64 url - if (isMatch(name, ".nsis.zip", "x64")) { - updateData.platforms.win64.url = browser_download_url; - updateData.platforms["windows-x86_64"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'x64')) { + updateData.platforms.win64.url = browserDownloadUrl + updateData.platforms['windows-x86_64'].url = browserDownloadUrl } // win64 signature - if (isMatch(name, ".nsis.zip.sig", "x64")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.win64.signature = sig; - updateData.platforms["windows-x86_64"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'x64')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.win64.signature = sig + updateData.platforms['windows-x86_64'].signature = sig } // win32 url - if (isMatch(name, ".nsis.zip", "x86")) { - updateData.platforms["windows-i686"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'x86')) { + updateData.platforms['windows-i686'].url = browserDownloadUrl } // win32 signature - if (isMatch(name, ".nsis.zip.sig", "x86")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["windows-i686"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'x86')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['windows-i686'].signature = sig } // win arm64 url - if (isMatch(name, ".nsis.zip", "arm64")) { - updateData.platforms["windows-aarch64"].url = browser_download_url; + if (isMatch(name, '.nsis.zip', 'arm64')) { + updateData.platforms['windows-aarch64'].url = browserDownloadUrl } // win arm64 signature - if (isMatch(name, ".nsis.zip.sig", "arm64")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["windows-aarch64"].signature = sig; + if (isMatch(name, '.nsis.zip.sig', 'arm64')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['windows-aarch64'].signature = sig } // darwin url (intel) - if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) { - updateData.platforms.darwin.url = browser_download_url; - updateData.platforms["darwin-intel"].url = browser_download_url; - updateData.platforms["darwin-x86_64"].url = browser_download_url; + if (name.endsWith('.app.tar.gz') && !name.includes('aarch')) { + updateData.platforms.darwin.url = browserDownloadUrl + updateData.platforms['darwin-intel'].url = browserDownloadUrl + updateData.platforms['darwin-x86_64'].url = browserDownloadUrl } // darwin signature (intel) - if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.darwin.signature = sig; - updateData.platforms["darwin-intel"].signature = sig; - updateData.platforms["darwin-x86_64"].signature = sig; + if (name.endsWith('.app.tar.gz.sig') && !name.includes('aarch')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.darwin.signature = sig + updateData.platforms['darwin-intel'].signature = sig + updateData.platforms['darwin-x86_64'].signature = sig } // darwin url (aarch) - if (name.endsWith("aarch64.app.tar.gz")) { - updateData.platforms["darwin-aarch64"].url = browser_download_url; + if (name.endsWith('aarch64.app.tar.gz')) { + updateData.platforms['darwin-aarch64'].url = browserDownloadUrl } // darwin signature (aarch) - if (name.endsWith("aarch64.app.tar.gz.sig")) { - const sig = await getSignature(browser_download_url); - updateData.platforms["darwin-aarch64"].signature = sig; + if (name.endsWith('aarch64.app.tar.gz.sig')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms['darwin-aarch64'].signature = sig } // linux url - if (name.endsWith(".AppImage.tar.gz")) { - updateData.platforms.linux.url = browser_download_url; - updateData.platforms["linux-x86_64"].url = browser_download_url; + if (name.endsWith('.AppImage.tar.gz')) { + updateData.platforms.linux.url = browserDownloadUrl + updateData.platforms['linux-x86_64'].url = browserDownloadUrl } // linux signature - if (name.endsWith(".AppImage.tar.gz.sig")) { - const sig = await getSignature(browser_download_url); - updateData.platforms.linux.signature = sig; - updateData.platforms["linux-x86_64"].signature = sig; + if (name.endsWith('.AppImage.tar.gz.sig')) { + const sig = await getSignature(browserDownloadUrl) + updateData.platforms.linux.signature = sig + updateData.platforms['linux-x86_64'].signature = sig } - }); + }) - await Promise.allSettled(promises); - consola.info(updateData); + await Promise.allSettled(promises) + consola.info(updateData) // maybe should test the signature as well // delete the null field Object.entries(updateData.platforms).forEach(([key, value]) => { if (!value.url) { - consola.error(`failed to parse release for "${key}"`); - delete updateData.platforms[key as keyof typeof updateData.platforms]; + consola.error(`failed to parse release for "${key}"`) + delete updateData.platforms[key as keyof typeof updateData.platforms] } - }); + }) // 生成一个代理github的更新文件 // 使用 https://hub.fastgit.xyz/ 做github资源的加速 const updateDataNew = JSON.parse( JSON.stringify(updateData), - ) as typeof updateData; + ) as typeof updateData Object.entries(updateDataNew.platforms).forEach(([key, value]) => { if (value.url) { updateDataNew.platforms[key as keyof typeof updateData.platforms].url = - getGithubUrl(value.url); + getGithubUrl(value.url) } else { - consola.error(`updateDataNew.platforms.${key} is null`); + consola.error(`updateDataNew.platforms.${key} is null`) } - }); + }) // update the update.json const { data: updateRelease } = await github.rest.repos.getReleaseByTag({ ...options, tag: UPDATE_TAG_NAME, - }); + }) // delete the old assets for (const asset of updateRelease.assets) { @@ -191,7 +191,7 @@ async function resolveUpdater() { await github.rest.repos.deleteReleaseAsset({ ...options, asset_id: asset.id, - }); + }) } if ( @@ -202,8 +202,8 @@ async function resolveUpdater() { await github.rest.repos .deleteReleaseAsset({ ...options, asset_id: asset.id }) .catch((err) => { - consola.error(err); - }); // do not break the pipeline + consola.error(err) + }) // do not break the pipeline } } @@ -213,26 +213,26 @@ async function resolveUpdater() { release_id: updateRelease.id, name: isFixedWebview ? UPDATE_FIXED_WEBVIEW_FILE : UPDATE_JSON_FILE, data: JSON.stringify(updateData, null, 2), - }); + }) await github.rest.repos.uploadReleaseAsset({ ...options, release_id: updateRelease.id, name: isFixedWebview ? UPDATE_FIXED_WEBVIEW_PROXY : UPDATE_JSON_PROXY, data: JSON.stringify(updateDataNew, null, 2), - }); + }) } // get the signature file content async function getSignature(url: string) { const response = await fetch(url, { - method: "GET", - headers: { "Content-Type": "application/octet-stream" }, - }); + method: 'GET', + headers: { 'Content-Type': 'application/octet-stream' }, + }) - return response.text(); + return response.text() } resolveUpdater().catch((err) => { - consola.error(err); -}); + consola.error(err) +}) diff --git a/clash-nyanpasu/scripts/utils/arch-check.ts b/clash-nyanpasu/scripts/utils/arch-check.ts index 98de5d0f12..c4cdd13a91 100644 --- a/clash-nyanpasu/scripts/utils/arch-check.ts +++ b/clash-nyanpasu/scripts/utils/arch-check.ts @@ -1,7 +1,7 @@ -import { colorize, consola } from "./logger"; +import { colorize, consola } from './logger' export const archCheck = (platform: string, arch: string) => { - consola.debug(colorize`platform {yellow ${platform}}`); + consola.debug(colorize`platform {yellow ${platform}}`) - consola.debug(colorize`arch {yellow ${arch}}`); -}; + consola.debug(colorize`arch {yellow ${arch}}`) +} diff --git a/clash-nyanpasu/scripts/utils/consts.ts b/clash-nyanpasu/scripts/utils/consts.ts index f90195a722..34ff0c4445 100644 --- a/clash-nyanpasu/scripts/utils/consts.ts +++ b/clash-nyanpasu/scripts/utils/consts.ts @@ -1,9 +1,9 @@ -import { execSync } from "child_process"; +import { execSync } from 'child_process' export const SIDECAR_HOST: string | undefined = process.argv.includes( - "--sidecar-host", + '--sidecar-host', ) - ? process.argv[process.argv.indexOf("--sidecar-host") + 1] - : execSync("rustc -vV") + ? process.argv[process.argv.indexOf('--sidecar-host') + 1] + : execSync('rustc -vV') .toString() - ?.match(/(?<=host: ).+(?=\s*)/g)?.[0]; + ?.match(/(?<=host: ).+(?=\s*)/g)?.[0] diff --git a/clash-nyanpasu/scripts/utils/download.ts b/clash-nyanpasu/scripts/utils/download.ts index 9433e0fef5..e90d1e6782 100644 --- a/clash-nyanpasu/scripts/utils/download.ts +++ b/clash-nyanpasu/scripts/utils/download.ts @@ -1,162 +1,158 @@ -import { execSync } from "child_process"; -import path from "path"; -import zlib from "zlib"; -import AdmZip from "adm-zip"; -import fs from "fs-extra"; -import fetch, { type RequestInit } from "node-fetch"; -import * as tar from "tar"; -import { BinInfo } from "types"; -import { getProxyAgent } from "./"; -import { TAURI_APP_DIR, TEMP_DIR } from "./env"; -import { colorize, consola } from "./logger"; +import { execSync } from 'child_process' +import path from 'path' +import zlib from 'zlib' +import AdmZip from 'adm-zip' +import fs from 'fs-extra' +import fetch, { type RequestInit } from 'node-fetch' +import * as tar from 'tar' +import { BinInfo } from 'types' +import { getProxyAgent } from './' +import { TAURI_APP_DIR, TEMP_DIR } from './env' +import { colorize, consola } from './logger' /** * download sidecar and rename */ export const downloadFile = async (url: string, path: string) => { - const options: Partial = {}; + const options: Partial = {} - const httpProxy = getProxyAgent(); + const httpProxy = getProxyAgent() if (httpProxy) { - options.agent = httpProxy; + options.agent = httpProxy } const response = await fetch(url, { ...options, - method: "GET", + method: 'GET', headers: { - "Content-Type": "application/octet-stream", - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0", + 'Content-Type': 'application/octet-stream', + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0', }, - }); + }) - const buffer = await response.arrayBuffer(); + const buffer = await response.arrayBuffer() - await fs.writeFile(path, new Uint8Array(buffer)); + await fs.writeFile(path, new Uint8Array(buffer)) - consola.success( - colorize`download finished {gray "${url.split("/").at(-1)}"}`, - ); -}; + consola.success(colorize`download finished {gray "${url.split('/').at(-1)}"}`) +} export const resolveSidecar = async ( binInfo: PromiseLike | BinInfo, platform: string, option?: { force?: boolean }, ) => { - const { name, targetFile, tmpFile, exeFile, downloadURL } = await binInfo; + const { name, targetFile, tmpFile, exeFile, downloadURL } = await binInfo - consola.debug(colorize`resolve {cyan ${name}}...`); + consola.debug(colorize`resolve {cyan ${name}}...`) - const sidecarDir = path.join(TAURI_APP_DIR, "sidecar"); + const sidecarDir = path.join(TAURI_APP_DIR, 'sidecar') - const sidecarPath = path.join(sidecarDir, targetFile); + const sidecarPath = path.join(sidecarDir, targetFile) - await fs.mkdirp(sidecarDir); + await fs.mkdirp(sidecarDir) - if (!option?.force && (await fs.pathExists(sidecarPath))) return; + if (!option?.force && (await fs.pathExists(sidecarPath))) return - const tempDir = path.join(TEMP_DIR, name); + const tempDir = path.join(TEMP_DIR, name) - const tempFile = path.join(tempDir, tmpFile); + const tempFile = path.join(tempDir, tmpFile) - const tempExe = path.join(tempDir, exeFile); + const tempExe = path.join(tempDir, exeFile) - await fs.mkdirp(tempDir); + await fs.mkdirp(tempDir) try { if (!(await fs.pathExists(tempFile))) { - await downloadFile(downloadURL, tempFile); + await downloadFile(downloadURL, tempFile) } - if (tmpFile.endsWith(".zip")) { - const zip = new AdmZip(tempFile); + if (tmpFile.endsWith('.zip')) { + const zip = new AdmZip(tempFile) - let entryName; + let entryName zip.getEntries().forEach((entry) => { - consola.debug( - colorize`"{green ${name}}" entry name ${entry.entryName}`, - ); + consola.debug(colorize`"{green ${name}}" entry name ${entry.entryName}`) if ( (entry.entryName.includes(name) && - entry.entryName.endsWith(".exe")) || + entry.entryName.endsWith('.exe')) || (entry.entryName.includes( name - .split("-") - .filter((o) => o !== "alpha") - .join("-"), + .split('-') + .filter((o) => o !== 'alpha') + .join('-'), ) && - entry.entryName.endsWith(".exe")) + entry.entryName.endsWith('.exe')) ) { - entryName = entry.entryName; + entryName = entry.entryName } - }); + }) - zip.extractAllTo(tempDir, true); + zip.extractAllTo(tempDir, true) if (!entryName) { - throw new Error("cannot find exe file in zip"); + throw new Error('cannot find exe file in zip') } - await fs.rename(path.join(tempDir, entryName), tempExe); + await fs.rename(path.join(tempDir, entryName), tempExe) - await fs.rename(tempExe, sidecarPath); + await fs.rename(tempExe, sidecarPath) - consola.debug(colorize`{green "${name}"} unzip finished`); - } else if (tmpFile.endsWith(".tar.gz")) { + consola.debug(colorize`{green "${name}"} unzip finished`) + } else if (tmpFile.endsWith('.tar.gz')) { // decompress and untar the file await tar.x({ file: tempFile, cwd: tempDir, - }); - await fs.rename(tempExe, sidecarPath); - consola.debug(colorize`{green "${name}"} untar finished`); - } else if (tmpFile.endsWith(".gz")) { + }) + await fs.rename(tempExe, sidecarPath) + consola.debug(colorize`{green "${name}"} untar finished`) + } else if (tmpFile.endsWith('.gz')) { // gz - const readStream = fs.createReadStream(tempFile); + const readStream = fs.createReadStream(tempFile) - const writeStream = fs.createWriteStream(sidecarPath); + const writeStream = fs.createWriteStream(sidecarPath) await new Promise((resolve, reject) => { const onError = (error: any) => { - consola.error(colorize`"${name}" gz failed:`, error); - reject(error); - }; + consola.error(colorize`"${name}" gz failed:`, error) + reject(error) + } readStream - .pipe(zlib.createGunzip().on("error", onError)) + .pipe(zlib.createGunzip().on('error', onError)) .pipe(writeStream) - .on("finish", () => { - consola.debug(colorize`{green "${name}"} gunzip finished`); + .on('finish', () => { + consola.debug(colorize`{green "${name}"} gunzip finished`) - execSync(`chmod 755 ${sidecarPath}`); + execSync(`chmod 755 ${sidecarPath}`) - consola.debug(colorize`{green "${name}"}chmod binary finished`); + consola.debug(colorize`{green "${name}"}chmod binary finished`) - resolve(); + resolve() }) - .on("error", onError); - }); + .on('error', onError) + }) } else { // Common Files - await fs.rename(tempFile, sidecarPath); + await fs.rename(tempFile, sidecarPath) - consola.info(colorize`{green "${name}"} rename finished`); + consola.info(colorize`{green "${name}"} rename finished`) - if (platform !== "win32") { - execSync(`chmod 755 ${sidecarPath}`); + if (platform !== 'win32') { + execSync(`chmod 755 ${sidecarPath}`) - consola.info(colorize`{green "${name}"} chmod binary finished`); + consola.info(colorize`{green "${name}"} chmod binary finished`) } } - consola.success(colorize`resolve {green ${name}} finished`); + consola.success(colorize`resolve {green ${name}} finished`) } catch (err) { // 需要删除文件 - await fs.remove(sidecarPath); + await fs.remove(sidecarPath) - throw err; + throw err } finally { // delete temp dir - await fs.remove(tempDir); + await fs.remove(tempDir) } -}; +} diff --git a/clash-nyanpasu/scripts/utils/env.ts b/clash-nyanpasu/scripts/utils/env.ts index a16733252a..0c52579faf 100644 --- a/clash-nyanpasu/scripts/utils/env.ts +++ b/clash-nyanpasu/scripts/utils/env.ts @@ -1,18 +1,18 @@ -import path from "path"; +import path from 'path' -export const cwd = process.cwd(); -export const TAURI_APP_DIR = path.join(cwd, "backend/tauri"); +export const cwd = process.cwd() +export const TAURI_APP_DIR = path.join(cwd, 'backend/tauri') export const TAURI_FIXED_WEBVIEW2_CONFIG_OVERRIDE_PATH = path.join( TAURI_APP_DIR, - "overrides/fixed-webview2.conf.json", -); -export const MANIFEST_DIR = path.join(cwd, "manifest"); -export const GITHUB_PROXY = "https://mirror.ghproxy.com/"; -export const GITHUB_TOKEN = process.env.GITHUB_TOKEN; -export const TEMP_DIR = path.join(cwd, "node_modules/.verge"); -export const MANIFEST_VERSION_PATH = path.join(MANIFEST_DIR, "version.json"); -export const TAURI_APP_TEMP_DIR = path.join(TAURI_APP_DIR, "tmp"); + 'overrides/fixed-webview2.conf.json', +) +export const MANIFEST_DIR = path.join(cwd, 'manifest') +export const GITHUB_PROXY = 'https://mirror.ghproxy.com/' +export const GITHUB_TOKEN = process.env.GITHUB_TOKEN +export const TEMP_DIR = path.join(cwd, 'node_modules/.verge') +export const MANIFEST_VERSION_PATH = path.join(MANIFEST_DIR, 'version.json') +export const TAURI_APP_TEMP_DIR = path.join(TAURI_APP_DIR, 'tmp') export const GIT_SUMMARY_INFO_PATH = path.join( TAURI_APP_TEMP_DIR, - "git-info.json", -); + 'git-info.json', +) diff --git a/clash-nyanpasu/scripts/utils/index.ts b/clash-nyanpasu/scripts/utils/index.ts index 2572ad6e39..4dd6744a1a 100644 --- a/clash-nyanpasu/scripts/utils/index.ts +++ b/clash-nyanpasu/scripts/utils/index.ts @@ -1,61 +1,61 @@ -import figlet from "figlet"; -import { filesize } from "filesize"; -import fs from "fs-extra"; -import { HttpsProxyAgent } from "https-proxy-agent"; -import { GITHUB_PROXY } from "./env"; +import figlet from 'figlet' +import { filesize } from 'filesize' +import fs from 'fs-extra' +import { HttpsProxyAgent } from 'https-proxy-agent' +import { GITHUB_PROXY } from './env' export const getGithubUrl = (url: string) => { - return new URL(url.replace(/^https?:\/\//g, ""), GITHUB_PROXY).toString(); -}; + return new URL(url.replace(/^https?:\/\//g, ''), GITHUB_PROXY).toString() +} export const getFileSize = (path: string): string => { - const stat = fs.statSync(path); - return filesize(stat.size); -}; + const stat = fs.statSync(path) + return filesize(stat.size) +} export const array2text = ( array: string[], - type: "newline" | "space" = "newline", + type: 'newline' | 'space' = 'newline', ): string => { - let result = ""; + let result = '' const getSplit = () => { - if (type == "newline") { - return "\n"; - } else if (type == "space") { - return " "; + if (type === 'newline') { + return '\n' + } else if (type === 'space') { + return ' ' } - }; + } array.forEach((value, index) => { if (index === array.length - 1) { - result += value; + result += value } else { - result += value + getSplit(); + result += value + getSplit() } - }); + }) - return result; -}; + return result +} export const printNyanpasu = () => { - const ascii = figlet.textSync("Clash Nyanpasu", { + const ascii = figlet.textSync('Clash Nyanpasu', { whitespaceBreak: true, - }); + }) - console.log(ascii); -}; + console.log(ascii) +} export const HTTP_PROXY = process.env.HTTP_PROXY || process.env.http_proxy || process.env.HTTPS_PROXY || - process.env.https_proxy; + process.env.https_proxy export function getProxyAgent() { if (HTTP_PROXY) { - return new HttpsProxyAgent(HTTP_PROXY); + return new HttpsProxyAgent(HTTP_PROXY) } - return undefined; + return undefined } diff --git a/clash-nyanpasu/scripts/utils/logger.ts b/clash-nyanpasu/scripts/utils/logger.ts index 739d40a456..98eb6f04ef 100644 --- a/clash-nyanpasu/scripts/utils/logger.ts +++ b/clash-nyanpasu/scripts/utils/logger.ts @@ -1,6 +1,6 @@ -import { createColorize } from "colorize-template"; -import { createConsola } from "consola"; -import pc from "picocolors"; +import { createColorize } from 'colorize-template' +import { createConsola } from 'consola' +import pc from 'picocolors' export const consola = createConsola({ level: process.env.LOG_LEVEL ? Number.parseInt(process.env.LOG_LEVEL) : 5, @@ -10,10 +10,10 @@ export const consola = createConsola({ compact: false, date: true, }, -}); +}) export const colorize = createColorize({ ...pc, success: pc.green, error: pc.red, -}); +}) diff --git a/clash-nyanpasu/scripts/utils/manifest.ts b/clash-nyanpasu/scripts/utils/manifest.ts index 70253b101c..5026f44aa5 100644 --- a/clash-nyanpasu/scripts/utils/manifest.ts +++ b/clash-nyanpasu/scripts/utils/manifest.ts @@ -1,164 +1,164 @@ -import consola from "consola"; -import { SupportedArch } from "../types/index"; -import { applyProxy, octokit } from "./octokit"; +import consola from 'consola' +import { SupportedArch } from '../types/index' +import { applyProxy, octokit } from './octokit' -export type ArchMapping = { [key in SupportedArch]: string }; +export type ArchMapping = { [key in SupportedArch]: string } -export type NodeArch = NodeJS.Architecture | "armel"; +export type NodeArch = NodeJS.Architecture | 'armel' // resolvers block export type LatestVersionResolver = Promise<{ - name: string; - version: string; - archMapping: ArchMapping; -}>; + name: string + version: string + archMapping: ArchMapping +}> export const resolveMihomo = async (): LatestVersionResolver => { const latestRelease = await octokit.rest.repos.getLatestRelease( applyProxy({ - owner: "MetaCubeX", - repo: "mihomo", + owner: 'MetaCubeX', + repo: 'mihomo', }), - ); + ) - consola.debug(`mihomo latest release: ${latestRelease.data.tag_name}`); + consola.debug(`mihomo latest release: ${latestRelease.data.tag_name}`) const archMapping: ArchMapping = { - [SupportedArch.WindowsX86_32]: "mihomo-windows-386-{}.zip", - [SupportedArch.WindowsX86_64]: "mihomo-windows-amd64-compatible-{}.zip", - [SupportedArch.WindowsArm64]: "mihomo-windows-arm64-{}.zip", - [SupportedArch.LinuxAarch64]: "mihomo-linux-arm64-{}.gz", - [SupportedArch.LinuxAmd64]: "mihomo-linux-amd64-compatible-{}.gz", - [SupportedArch.LinuxI386]: "mihomo-linux-386-{}.gz", - [SupportedArch.DarwinArm64]: "mihomo-darwin-arm64-{}.gz", - [SupportedArch.DarwinX64]: "mihomo-darwin-amd64-compatible-{}.gz", - [SupportedArch.LinuxArmv7]: "mihomo-linux-armv5-{}.gz", - [SupportedArch.LinuxArmv7hf]: "mihomo-linux-armv7-{}.gz", - } satisfies ArchMapping; + [SupportedArch.WindowsX86_32]: 'mihomo-windows-386-{}.zip', + [SupportedArch.WindowsX86_64]: 'mihomo-windows-amd64-compatible-{}.zip', + [SupportedArch.WindowsArm64]: 'mihomo-windows-arm64-{}.zip', + [SupportedArch.LinuxAarch64]: 'mihomo-linux-arm64-{}.gz', + [SupportedArch.LinuxAmd64]: 'mihomo-linux-amd64-compatible-{}.gz', + [SupportedArch.LinuxI386]: 'mihomo-linux-386-{}.gz', + [SupportedArch.DarwinArm64]: 'mihomo-darwin-arm64-{}.gz', + [SupportedArch.DarwinX64]: 'mihomo-darwin-amd64-compatible-{}.gz', + [SupportedArch.LinuxArmv7]: 'mihomo-linux-armv5-{}.gz', + [SupportedArch.LinuxArmv7hf]: 'mihomo-linux-armv7-{}.gz', + } satisfies ArchMapping return { - name: "mihomo", + name: 'mihomo', version: latestRelease.data.tag_name, archMapping, - }; -}; + } +} export const resolveMihomoAlpha = async (): LatestVersionResolver => { const resp = await fetch( - "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt", - ); + 'https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt', + ) - const alphaReleaseHash = (await resp.text()).trim(); + const alphaReleaseHash = (await resp.text()).trim() - consola.debug(`mihomo alpha release: ${alphaReleaseHash}`); + consola.debug(`mihomo alpha release: ${alphaReleaseHash}`) const archMapping: ArchMapping = { - [SupportedArch.WindowsX86_32]: "mihomo-windows-386-{}.zip", - [SupportedArch.WindowsX86_64]: "mihomo-windows-amd64-compatible-{}.zip", - [SupportedArch.WindowsArm64]: "mihomo-windows-arm64-{}.zip", - [SupportedArch.LinuxAarch64]: "mihomo-linux-arm64-{}.gz", - [SupportedArch.LinuxAmd64]: "mihomo-linux-amd64-compatible-{}.gz", - [SupportedArch.LinuxI386]: "mihomo-linux-386-{}.gz", - [SupportedArch.DarwinArm64]: "mihomo-darwin-arm64-{}.gz", - [SupportedArch.DarwinX64]: "mihomo-darwin-amd64-compatible-{}.gz", - [SupportedArch.LinuxArmv7]: "mihomo-linux-armv5-{}.gz", - [SupportedArch.LinuxArmv7hf]: "mihomo-linux-armv7-{}.gz", - } satisfies ArchMapping; + [SupportedArch.WindowsX86_32]: 'mihomo-windows-386-{}.zip', + [SupportedArch.WindowsX86_64]: 'mihomo-windows-amd64-compatible-{}.zip', + [SupportedArch.WindowsArm64]: 'mihomo-windows-arm64-{}.zip', + [SupportedArch.LinuxAarch64]: 'mihomo-linux-arm64-{}.gz', + [SupportedArch.LinuxAmd64]: 'mihomo-linux-amd64-compatible-{}.gz', + [SupportedArch.LinuxI386]: 'mihomo-linux-386-{}.gz', + [SupportedArch.DarwinArm64]: 'mihomo-darwin-arm64-{}.gz', + [SupportedArch.DarwinX64]: 'mihomo-darwin-amd64-compatible-{}.gz', + [SupportedArch.LinuxArmv7]: 'mihomo-linux-armv5-{}.gz', + [SupportedArch.LinuxArmv7hf]: 'mihomo-linux-armv7-{}.gz', + } satisfies ArchMapping return { - name: "mihomo_alpha", + name: 'mihomo_alpha', version: alphaReleaseHash, archMapping, - }; -}; + } +} export const resolveClashRs = async (): LatestVersionResolver => { const latestRelease = await octokit.rest.repos.getLatestRelease( applyProxy({ - owner: "Watfaq", - repo: "clash-rs", + owner: 'Watfaq', + repo: 'clash-rs', }), - ); + ) - consola.debug(`clash-rs latest release: ${latestRelease.data.tag_name}`); + consola.debug(`clash-rs latest release: ${latestRelease.data.tag_name}`) const archMapping: ArchMapping = { - [SupportedArch.WindowsX86_32]: "clash-i686-pc-windows-msvc-static-crt.exe", - [SupportedArch.WindowsX86_64]: "clash-x86_64-pc-windows-msvc.exe", - [SupportedArch.WindowsArm64]: "clash-aarch64-pc-windows-msvc.exe", - [SupportedArch.LinuxAarch64]: "clash-aarch64-unknown-linux-gnu-static-crt", - [SupportedArch.LinuxAmd64]: "clash-x86_64-unknown-linux-gnu-static-crt", - [SupportedArch.LinuxI386]: "clash-i686-unknown-linux-gnu-static-crt", - [SupportedArch.DarwinArm64]: "clash-aarch64-apple-darwin", - [SupportedArch.DarwinX64]: "clash-x86_64-apple-darwin", - [SupportedArch.LinuxArmv7]: "clash-armv7-unknown-linux-gnueabi-static-crt", - [SupportedArch.LinuxArmv7hf]: "clash-armv7-unknown-linux-gnueabihf", - } satisfies ArchMapping; + [SupportedArch.WindowsX86_32]: 'clash-i686-pc-windows-msvc-static-crt.exe', + [SupportedArch.WindowsX86_64]: 'clash-x86_64-pc-windows-msvc.exe', + [SupportedArch.WindowsArm64]: 'clash-aarch64-pc-windows-msvc.exe', + [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxAmd64]: 'clash-x86_64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu-static-crt', + [SupportedArch.DarwinArm64]: 'clash-aarch64-apple-darwin', + [SupportedArch.DarwinX64]: 'clash-x86_64-apple-darwin', + [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi-static-crt', + [SupportedArch.LinuxArmv7hf]: 'clash-armv7-unknown-linux-gnueabihf', + } satisfies ArchMapping return { - name: "clash_rs", + name: 'clash_rs', version: latestRelease.data.tag_name, archMapping, - }; -}; + } +} export const resolveClashRsAlpha = async (): LatestVersionResolver => { const resp = await fetch( - "https://github.com/Watfaq/clash-rs/releases/download/latest/version.txt", - ); + 'https://github.com/Watfaq/clash-rs/releases/download/latest/version.txt', + ) const alphaVersion = resp.ok - ? (await resp.text()).trim().split(" ").pop()! - : "latest"; + ? (await resp.text()).trim().split(' ').pop()! + : 'latest' - consola.debug(`clash-rs alpha latest release: ${alphaVersion}`); + consola.debug(`clash-rs alpha latest release: ${alphaVersion}`) const archMapping: ArchMapping = { - [SupportedArch.WindowsX86_32]: "clash-i686-pc-windows-msvc-static-crt.exe", - [SupportedArch.WindowsX86_64]: "clash-x86_64-pc-windows-msvc.exe", - [SupportedArch.WindowsArm64]: "clash-aarch64-pc-windows-msvc.exe", - [SupportedArch.LinuxAarch64]: "clash-aarch64-unknown-linux-gnu-static-crt", - [SupportedArch.LinuxAmd64]: "clash-x86_64-unknown-linux-gnu-static-crt", - [SupportedArch.LinuxI386]: "clash-i686-unknown-linux-gnu-static-crt", - [SupportedArch.DarwinArm64]: "clash-aarch64-apple-darwin", - [SupportedArch.DarwinX64]: "clash-x86_64-apple-darwin", - [SupportedArch.LinuxArmv7]: "clash-armv7-unknown-linux-gnueabi-static-crt", - [SupportedArch.LinuxArmv7hf]: "clash-armv7-unknown-linux-gnueabihf", - } satisfies ArchMapping; + [SupportedArch.WindowsX86_32]: 'clash-i686-pc-windows-msvc-static-crt.exe', + [SupportedArch.WindowsX86_64]: 'clash-x86_64-pc-windows-msvc.exe', + [SupportedArch.WindowsArm64]: 'clash-aarch64-pc-windows-msvc.exe', + [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxAmd64]: 'clash-x86_64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu-static-crt', + [SupportedArch.DarwinArm64]: 'clash-aarch64-apple-darwin', + [SupportedArch.DarwinX64]: 'clash-x86_64-apple-darwin', + [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi-static-crt', + [SupportedArch.LinuxArmv7hf]: 'clash-armv7-unknown-linux-gnueabihf', + } satisfies ArchMapping return { - name: "clash_rs_alpha", + name: 'clash_rs_alpha', version: alphaVersion, archMapping, - }; -}; + } +} export const resolveClashPremium = async (): LatestVersionResolver => { const latestRelease = await octokit.rest.repos.getLatestRelease( applyProxy({ - owner: "zhongfly", - repo: "Clash-premium-backup", + owner: 'zhongfly', + repo: 'Clash-premium-backup', }), - ); + ) - consola.debug(`clash-premium latest release: ${latestRelease.data.tag_name}`); + consola.debug(`clash-premium latest release: ${latestRelease.data.tag_name}`) const archMapping: ArchMapping = { - [SupportedArch.WindowsX86_32]: "clash-windows-386-n{}.zip", - [SupportedArch.WindowsX86_64]: "clash-windows-amd64-n{}.zip", - [SupportedArch.WindowsArm64]: "clash-windows-arm64-n{}.zip", - [SupportedArch.LinuxAarch64]: "clash-linux-arm64-n{}.gz", - [SupportedArch.LinuxAmd64]: "clash-linux-amd64-n{}.gz", - [SupportedArch.LinuxI386]: "clash-linux-386-n{}.gz", - [SupportedArch.DarwinArm64]: "clash-darwin-arm64-n{}.gz", - [SupportedArch.DarwinX64]: "clash-darwin-amd64-n{}.gz", - [SupportedArch.LinuxArmv7]: "clash-linux-armv5-n{}.gz", - [SupportedArch.LinuxArmv7hf]: "clash-linux-armv7-n{}.gz", - } satisfies ArchMapping; + [SupportedArch.WindowsX86_32]: 'clash-windows-386-n{}.zip', + [SupportedArch.WindowsX86_64]: 'clash-windows-amd64-n{}.zip', + [SupportedArch.WindowsArm64]: 'clash-windows-arm64-n{}.zip', + [SupportedArch.LinuxAarch64]: 'clash-linux-arm64-n{}.gz', + [SupportedArch.LinuxAmd64]: 'clash-linux-amd64-n{}.gz', + [SupportedArch.LinuxI386]: 'clash-linux-386-n{}.gz', + [SupportedArch.DarwinArm64]: 'clash-darwin-arm64-n{}.gz', + [SupportedArch.DarwinX64]: 'clash-darwin-amd64-n{}.gz', + [SupportedArch.LinuxArmv7]: 'clash-linux-armv5-n{}.gz', + [SupportedArch.LinuxArmv7hf]: 'clash-linux-armv7-n{}.gz', + } satisfies ArchMapping return { - name: "clash_premium", + name: 'clash_premium', version: latestRelease.data.tag_name, archMapping, - }; -}; + } +} diff --git a/clash-nyanpasu/scripts/utils/octokit.ts b/clash-nyanpasu/scripts/utils/octokit.ts index a3e7d26699..18e88ed8ff 100644 --- a/clash-nyanpasu/scripts/utils/octokit.ts +++ b/clash-nyanpasu/scripts/utils/octokit.ts @@ -1,11 +1,11 @@ -import { Octokit } from "octokit"; -import { ProxyAgent, fetch as undiciFetch } from "undici"; -import { HTTP_PROXY } from "./"; +import { Octokit } from 'octokit' +import { ProxyAgent, fetch as undiciFetch } from 'undici' +import { HTTP_PROXY } from './' const BASE_OPTIONS = { - owner: "libnyanpasu", - repo: "clash-nyanpasu", -}; + owner: 'libnyanpasu', + repo: 'clash-nyanpasu', +} export const fetcher = ( url: string, @@ -14,10 +14,10 @@ export const fetcher = ( return undiciFetch(url, { ...options, dispatcher: HTTP_PROXY ? new ProxyAgent(HTTP_PROXY) : undefined, - }); -}; + }) +} -export const octokit = new Octokit(applyProxy(BASE_OPTIONS)); +export const octokit = new Octokit(applyProxy(BASE_OPTIONS)) export function applyProxy(opts: ConstructorParameters[0]) { return { @@ -26,5 +26,5 @@ export function applyProxy(opts: ConstructorParameters[0]) { fetch: fetcher, }, auth: process.env.GITHUB_TOKEN || process.env.GH_TOKEN || undefined, - } satisfies ConstructorParameters[0]; + } satisfies ConstructorParameters[0] } diff --git a/clash-nyanpasu/scripts/utils/resolve.ts b/clash-nyanpasu/scripts/utils/resolve.ts index 81a9c77497..08c8ac4c5a 100644 --- a/clash-nyanpasu/scripts/utils/resolve.ts +++ b/clash-nyanpasu/scripts/utils/resolve.ts @@ -1,12 +1,12 @@ -import crypto from "node:crypto"; -import path from "path"; -import AdmZip from "adm-zip"; -import fs from "fs-extra"; -import { BinInfo } from "../types"; -import { downloadFile, resolveSidecar } from "./download"; -import { TAURI_APP_DIR, TEMP_DIR } from "./env"; -import { colorize, consola } from "./logger"; -import { NodeArch } from "./manifest"; +import crypto from 'node:crypto' +import path from 'path' +import AdmZip from 'adm-zip' +import fs from 'fs-extra' +import { BinInfo } from '../types' +import { downloadFile, resolveSidecar } from './download' +import { TAURI_APP_DIR, TEMP_DIR } from './env' +import { colorize, consola } from './logger' +import { NodeArch } from './manifest' import { getClashBackupInfo, getClashMetaAlphaInfo, @@ -14,7 +14,7 @@ import { getClashRustAlphaInfo, getClashRustInfo, getNyanpasuServiceInfo, -} from "./resource"; +} from './resource' /** * download the file to the resources dir @@ -23,41 +23,41 @@ export const resolveResource = async ( binInfo: { file: string; downloadURL: string }, options?: { force?: boolean }, ) => { - const { file, downloadURL } = binInfo; + const { file, downloadURL } = binInfo - const resDir = path.join(TAURI_APP_DIR, "resources"); + const resDir = path.join(TAURI_APP_DIR, 'resources') - const targetPath = path.join(resDir, file); + const targetPath = path.join(resDir, file) - if (!options?.force && (await fs.pathExists(targetPath))) return; + if (!options?.force && (await fs.pathExists(targetPath))) return - await fs.mkdirp(resDir); + await fs.mkdirp(resDir) - await downloadFile(downloadURL, targetPath); + await downloadFile(downloadURL, targetPath) - consola.success(colorize`resolve {green ${file}} finished`); -}; + consola.success(colorize`resolve {green ${file}} finished`) +} export class Resolve { private infoOption: { - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost: string; - }; + platform: NodeJS.Platform + arch: NodeArch + sidecarHost: string + } constructor( private readonly options: { - force?: boolean; - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost: string; + force?: boolean + platform: NodeJS.Platform + arch: NodeArch + sidecarHost: string }, ) { this.infoOption = { platform: this.options.platform, arch: this.options.arch, sidecarHost: this.options.sidecarHost, - }; + } } /** @@ -65,141 +65,141 @@ export class Resolve { * get the wintun.dll (not required) */ public async wintun() { - const { platform } = process; - let arch: string = this.options.arch || "x64"; - if (platform !== "win32") return; + const { platform } = process + let arch: string = this.options.arch || 'x64' + if (platform !== 'win32') return switch (arch) { - case "x64": - arch = "amd64"; - break; - case "ia32": - arch = "x86"; - break; - case "arm": - arch = "arm"; - break; - case "arm64": - arch = "arm64"; - break; + case 'x64': + arch = 'amd64' + break + case 'ia32': + arch = 'x86' + break + case 'arm': + arch = 'arm' + break + case 'arm64': + arch = 'arm64' + break default: - throw new Error(`unsupported arch ${arch}`); + throw new Error(`unsupported arch ${arch}`) } - const url = "https://www.wintun.net/builds/wintun-0.14.1.zip"; + const url = 'https://www.wintun.net/builds/wintun-0.14.1.zip' const hash = - "07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51"; + '07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51' - const tempDir = path.join(TEMP_DIR, "wintun"); + const tempDir = path.join(TEMP_DIR, 'wintun') - const tempZip = path.join(tempDir, "wintun.zip"); + const tempZip = path.join(tempDir, 'wintun.zip') // const wintunPath = path.join(tempDir, "wintun/bin/amd64/wintun.dll"); - const targetPath = path.join(TAURI_APP_DIR, "resources", "wintun.dll"); + const targetPath = path.join(TAURI_APP_DIR, 'resources', 'wintun.dll') - if (!this.options?.force && (await fs.pathExists(targetPath))) return; + if (!this.options?.force && (await fs.pathExists(targetPath))) return - await fs.mkdirp(tempDir); + await fs.mkdirp(tempDir) if (!(await fs.pathExists(tempZip))) { - await downloadFile(url, tempZip); + await downloadFile(url, tempZip) } // check hash - const hashBuffer = await fs.readFile(tempZip); - const sha256 = crypto.createHash("sha256"); - sha256.update(hashBuffer); - const hashValue = sha256.digest("hex"); + const hashBuffer = await fs.readFile(tempZip) + const sha256 = crypto.createHash('sha256') + sha256.update(hashBuffer) + const hashValue = sha256.digest('hex') if (hashValue !== hash) { - throw new Error(`wintun. hash not match ${hashValue}`); + throw new Error(`wintun. hash not match ${hashValue}`) } // unzip - const zip = new AdmZip(tempZip); + const zip = new AdmZip(tempZip) - zip.extractAllTo(tempDir, true); + zip.extractAllTo(tempDir, true) // recursive list path for debug use const files = (await fs.readdir(tempDir, { recursive: true })).filter( - (file) => file.includes("wintun.dll"), - ); - consola.debug(colorize`{green wintun} founded dlls: ${files}`); + (file) => file.includes('wintun.dll'), + ) + consola.debug(colorize`{green wintun} founded dlls: ${files}`) - const file = files.find((file) => file.includes(arch)); + const file = files.find((file) => file.includes(arch)) if (!file) { - throw new Error(`wintun. not found arch ${arch}`); + throw new Error(`wintun. not found arch ${arch}`) } - const wintunPath = path.join(tempDir, file.toString()); + const wintunPath = path.join(tempDir, file.toString()) if (!(await fs.pathExists(wintunPath))) { - throw new Error(`path not found "${wintunPath}"`); + throw new Error(`path not found "${wintunPath}"`) } // prepare resource dir - await fs.mkdirp(path.dirname(targetPath)); - await fs.copyFile(wintunPath, targetPath); + await fs.mkdirp(path.dirname(targetPath)) + await fs.copyFile(wintunPath, targetPath) - await fs.remove(tempDir); + await fs.remove(tempDir) - consola.success(colorize`resolve {green wintun.dll} finished`); + consola.success(colorize`resolve {green wintun.dll} finished`) } public async service() { - return await this.sidecar(getNyanpasuServiceInfo(this.infoOption)); + return await this.sidecar(getNyanpasuServiceInfo(this.infoOption)) } public mmdb() { return resolveResource({ - file: "Country.mmdb", + file: 'Country.mmdb', downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb`, - }); + }) } public geosite() { return resolveResource({ - file: "geosite.dat", + file: 'geosite.dat', downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`, - }); + }) } public geoip() { return resolveResource({ - file: "geoip.dat", + file: 'geoip.dat', downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`, - }); + }) } public enableLoopback() { return resolveResource({ - file: "enableLoopback.exe", + file: 'enableLoopback.exe', downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`, - }); + }) } private sidecar(binInfo: BinInfo | PromiseLike) { return resolveSidecar(binInfo, this.options.platform, { force: this.options.force, - }); + }) } public async clash() { - return await this.sidecar(getClashBackupInfo(this.infoOption)); + return await this.sidecar(getClashBackupInfo(this.infoOption)) } public async clashMeta() { - return await this.sidecar(getClashMetaInfo(this.infoOption)); + return await this.sidecar(getClashMetaInfo(this.infoOption)) } public async clashMetaAlpha() { - return await this.sidecar(getClashMetaAlphaInfo(this.infoOption)); + return await this.sidecar(getClashMetaAlphaInfo(this.infoOption)) } public async clashRust() { - return await this.sidecar(getClashRustInfo(this.infoOption)); + return await this.sidecar(getClashRustInfo(this.infoOption)) } public async clashRustAlpha() { - return await this.sidecar(getClashRustAlphaInfo(this.infoOption)); + return await this.sidecar(getClashRustAlphaInfo(this.infoOption)) } } diff --git a/clash-nyanpasu/scripts/utils/resource.ts b/clash-nyanpasu/scripts/utils/resource.ts index ff43e10e10..308515b681 100644 --- a/clash-nyanpasu/scripts/utils/resource.ts +++ b/clash-nyanpasu/scripts/utils/resource.ts @@ -1,48 +1,48 @@ // import { ArchMapping } from 'utils/manifest'; -import consola from "consola"; -import fetch, { type RequestInit } from "node-fetch"; +import consola from 'consola' +import fetch, { type RequestInit } from 'node-fetch' import { CLASH_META_ALPHA_MANIFEST, CLASH_META_MANIFEST, -} from "../manifest/clash-meta"; -import { CLASH_MANIFEST } from "../manifest/clash-premium"; +} from '../manifest/clash-meta' +import { CLASH_MANIFEST } from '../manifest/clash-premium' import { CLASH_RS_ALPHA_MANIFEST, CLASH_RS_MANIFEST, -} from "../manifest/clash-rs"; -import { BinInfo, SupportedArch } from "../types"; -import { getProxyAgent } from "./"; -import { SIDECAR_HOST } from "./consts"; +} from '../manifest/clash-rs' +import { BinInfo, SupportedArch } from '../types' +import { getProxyAgent } from './' +import { SIDECAR_HOST } from './consts' -const SERVICE_REPO = "libnyanpasu/nyanpasu-service"; +const SERVICE_REPO = 'libnyanpasu/nyanpasu-service' -type NodeArch = NodeJS.Architecture | "armel"; +type NodeArch = NodeJS.Architecture | 'armel' function mappingArch(platform: NodeJS.Platform, arch: NodeArch): SupportedArch { - const label = `${platform}-${arch}`; + const label = `${platform}-${arch}` switch (label) { - case "darwin-x64": - return SupportedArch.DarwinX64; - case "darwin-arm64": - return SupportedArch.DarwinArm64; - case "win32-x64": - return SupportedArch.WindowsX86_64; - case "win32-ia32": - return SupportedArch.WindowsX86_32; - case "win32-arm64": - return SupportedArch.WindowsArm64; - case "linux-x64": - return SupportedArch.LinuxAmd64; - case "linux-ia32": - return SupportedArch.LinuxI386; - case "linux-arm": - return SupportedArch.LinuxArmv7hf; - case "linux-arm64": - return SupportedArch.LinuxAarch64; - case "linux-armel": - return SupportedArch.LinuxArmv7; + case 'darwin-x64': + return SupportedArch.DarwinX64 + case 'darwin-arm64': + return SupportedArch.DarwinArm64 + case 'win32-x64': + return SupportedArch.WindowsX86_64 + case 'win32-ia32': + return SupportedArch.WindowsX86_32 + case 'win32-arm64': + return SupportedArch.WindowsArm64 + case 'linux-x64': + return SupportedArch.LinuxAmd64 + case 'linux-ia32': + return SupportedArch.LinuxI386 + case 'linux-arm': + return SupportedArch.LinuxArmv7hf + case 'linux-arm64': + return SupportedArch.LinuxAarch64 + case 'linux-armel': + return SupportedArch.LinuxArmv7 default: - throw new Error("Unsupported platform/architecture: " + label); + throw new Error('Unsupported platform/architecture: ' + label) } } @@ -51,309 +51,308 @@ export const getClashInfo = ({ arch, sidecarHost, }: { - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost?: string; + platform: NodeJS.Platform + arch: NodeArch + sidecarHost?: string }): BinInfo => { - const { ARCH_MAPPING, URL_PREFIX, LATEST_DATE } = CLASH_MANIFEST; - const archLabel = mappingArch(platform, arch); - const name = ARCH_MAPPING[archLabel].replace("{}", LATEST_DATE as string); + const { ARCH_MAPPING, URL_PREFIX, LATEST_DATE } = CLASH_MANIFEST + const archLabel = mappingArch(platform, arch) + const name = ARCH_MAPPING[archLabel].replace('{}', LATEST_DATE as string) - const isWin = platform === "win32"; + const isWin = platform === 'win32' - const downloadURL = `${URL_PREFIX}${name}`; + const downloadURL = `${URL_PREFIX}${name}` - const exeFile = `${name}${isWin ? ".exe" : ""}`; + const exeFile = `${name}${isWin ? '.exe' : ''}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `clash-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `clash-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "clash", + name: 'clash', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getClashBackupInfo = ({ platform, arch, sidecarHost, }: { - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost?: string; + platform: NodeJS.Platform + arch: NodeArch + sidecarHost?: string }): BinInfo => { - const { ARCH_MAPPING, BACKUP_URL_PREFIX, BACKUP_LATEST_DATE } = - CLASH_MANIFEST; + const { ARCH_MAPPING, BACKUP_URL_PREFIX, BACKUP_LATEST_DATE } = CLASH_MANIFEST - const archLabel = mappingArch(platform, arch); + const archLabel = mappingArch(platform, arch) const name = ARCH_MAPPING[archLabel].replace( - "{}", + '{}', BACKUP_LATEST_DATE as string, - ); - const isWin = platform === "win32"; + ) + const isWin = platform === 'win32' - const downloadURL = `${BACKUP_URL_PREFIX}${BACKUP_LATEST_DATE}/${name}`; + const downloadURL = `${BACKUP_URL_PREFIX}${BACKUP_LATEST_DATE}/${name}` - const exeFile = `${name}${isWin ? ".exe" : ""}`; + const exeFile = `${name}${isWin ? '.exe' : ''}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `clash-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `clash-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "clash", + name: 'clash', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getClashMetaInfo = ({ platform, arch, sidecarHost, }: { - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost?: string; + platform: NodeJS.Platform + arch: NodeArch + sidecarHost?: string }): BinInfo => { - const { ARCH_MAPPING, URL_PREFIX, VERSION } = CLASH_META_MANIFEST; - const archLabel = mappingArch(platform, arch); + const { ARCH_MAPPING, URL_PREFIX, VERSION } = CLASH_META_MANIFEST + const archLabel = mappingArch(platform, arch) - const name = ARCH_MAPPING[archLabel].replace("{}", VERSION as string); + const name = ARCH_MAPPING[archLabel].replace('{}', VERSION as string) - const isWin = platform === "win32"; + const isWin = platform === 'win32' - const downloadURL = `${URL_PREFIX}/${name}`; + const downloadURL = `${URL_PREFIX}/${name}` - const exeFile = `${name}${isWin ? ".exe" : ""}`; + const exeFile = `${name}${isWin ? '.exe' : ''}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `mihomo-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `mihomo-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "mihomo", + name: 'mihomo', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getClashMetaAlphaInfo = async ({ platform, arch, sidecarHost, }: { - platform: NodeJS.Platform; - arch: NodeArch; - sidecarHost?: string; + platform: NodeJS.Platform + arch: NodeArch + sidecarHost?: string }): Promise => { - const { ARCH_MAPPING, URL_PREFIX } = CLASH_META_ALPHA_MANIFEST; - const version = await getMetaAlphaLatestVersion(); - const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch); - const name = ARCH_MAPPING[archLabel].replace("{}", version); - const isWin = platform === "win32"; - const downloadURL = `${URL_PREFIX}/${name}`; + const { ARCH_MAPPING, URL_PREFIX } = CLASH_META_ALPHA_MANIFEST + const version = await getMetaAlphaLatestVersion() + const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch) + const name = ARCH_MAPPING[archLabel].replace('{}', version) + const isWin = platform === 'win32' + const downloadURL = `${URL_PREFIX}/${name}` - const exeFile = `${name}${isWin ? ".exe" : ""}`; + const exeFile = `${name}${isWin ? '.exe' : ''}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `mihomo-alpha-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `mihomo-alpha-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "mihomo-alpha", + name: 'mihomo-alpha', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getClashRustInfo = ({ platform, arch, sidecarHost, }: { - platform: string; - arch: string; - sidecarHost?: string; + platform: string + arch: string + sidecarHost?: string }): BinInfo => { - const { ARCH_MAPPING, URL_PREFIX, VERSION } = CLASH_RS_MANIFEST; + const { ARCH_MAPPING, URL_PREFIX, VERSION } = CLASH_RS_MANIFEST - const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch); - const name = ARCH_MAPPING[archLabel].replace("{}", VERSION as string); + const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch) + const name = ARCH_MAPPING[archLabel].replace('{}', VERSION as string) - const isWin = platform === "win32"; + const isWin = platform === 'win32' - const exeFile = `${name}`; + const exeFile = `${name}` - const downloadURL = `${URL_PREFIX}${VERSION}/${name}`; + const downloadURL = `${URL_PREFIX}${VERSION}/${name}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `clash-rs-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `clash-rs-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "clash-rs", + name: 'clash-rs', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getClashRsAlphaLatestVersion = async () => { - const { VERSION_URL } = CLASH_RS_ALPHA_MANIFEST; + const { VERSION_URL } = CLASH_RS_ALPHA_MANIFEST try { - const opts = {} as Partial; + const opts = {} as Partial - const httpProxy = getProxyAgent(); + const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy; + opts.agent = httpProxy } const response = await fetch(VERSION_URL!, { - method: "GET", + method: 'GET', ...opts, - }); + }) - const v = (await response.text()).trim().split(" ").pop()!; + const v = (await response.text()).trim().split(' ').pop()! - consola.info(`Clash Rs Alpha latest release version: ${v}`); + consola.info(`Clash Rs Alpha latest release version: ${v}`) - return v.trim(); + return v.trim() } catch (error) { - console.error("Error fetching latest release version:", error); + console.error('Error fetching latest release version:', error) - process.exit(1); + process.exit(1) } -}; +} export const getClashRustAlphaInfo = async ({ platform, arch, sidecarHost, }: { - platform: string; - arch: string; - sidecarHost?: string; + platform: string + arch: string + sidecarHost?: string }): Promise => { - const { ARCH_MAPPING, URL_PREFIX } = CLASH_RS_ALPHA_MANIFEST; - const version = await getClashRsAlphaLatestVersion(); - const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch); - const name = ARCH_MAPPING[archLabel].replace("{}", version as string); + const { ARCH_MAPPING, URL_PREFIX } = CLASH_RS_ALPHA_MANIFEST + const version = await getClashRsAlphaLatestVersion() + const archLabel = mappingArch(platform as NodeJS.Platform, arch as NodeArch) + const name = ARCH_MAPPING[archLabel].replace('{}', version as string) - const isWin = platform === "win32"; + const isWin = platform === 'win32' - const exeFile = `${name}`; + const exeFile = `${name}` - const downloadURL = `${URL_PREFIX}/${name}`; + const downloadURL = `${URL_PREFIX}/${name}` - const tmpFile = `${name}`; + const tmpFile = `${name}` - const targetFile = `clash-rs-alpha-${sidecarHost}${isWin ? ".exe" : ""}`; + const targetFile = `clash-rs-alpha-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "clash-rs-alpha", + name: 'clash-rs-alpha', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} export const getMetaAlphaLatestVersion = async () => { - const { VERSION_URL } = CLASH_META_ALPHA_MANIFEST; + const { VERSION_URL } = CLASH_META_ALPHA_MANIFEST try { - const opts = {} as Partial; + const opts = {} as Partial - const httpProxy = getProxyAgent(); + const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy; + opts.agent = httpProxy } const response = await fetch(VERSION_URL!, { - method: "GET", + method: 'GET', ...opts, - }); + }) - const v = await response.text(); + const v = await response.text() - consola.info(`Mihomo Alpha latest release version: ${v}`); + consola.info(`Mihomo Alpha latest release version: ${v}`) - return v.trim(); + return v.trim() } catch (error) { - console.error("Error fetching latest release version:", error); + console.error('Error fetching latest release version:', error) - process.exit(1); + process.exit(1) } -}; +} export const getNyanpasuServiceLatestVersion = async () => { try { - const opts = {} as Partial; + const opts = {} as Partial - const httpProxy = getProxyAgent(); + const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy; + opts.agent = httpProxy } - const url = new URL("https://github.com"); - url.pathname = `/${SERVICE_REPO}/releases/latest`; + const url = new URL('https://github.com') + url.pathname = `/${SERVICE_REPO}/releases/latest` const response = await fetch(url, { - method: "GET", - redirect: "manual", + method: 'GET', + redirect: 'manual', ...opts, - }); + }) - const location = response.headers.get("location"); + const location = response.headers.get('location') if (!location) { - throw new Error("Cannot find location from the response header"); + throw new Error('Cannot find location from the response header') } - const tag = location.split("/").pop(); + const tag = location.split('/').pop() if (!tag) { - throw new Error("Cannot find tag from the location"); + throw new Error('Cannot find tag from the location') } - consola.info(`Nyanpasu Service latest release version: ${tag}`); - return tag.trim(); + consola.info(`Nyanpasu Service latest release version: ${tag}`) + return tag.trim() } catch (error) { - console.error("Error fetching latest release version:", error); - process.exit(1); + console.error('Error fetching latest release version:', error) + process.exit(1) } -}; +} export const getNyanpasuServiceInfo = async ({ sidecarHost, }: { - sidecarHost: string; + sidecarHost: string }): Promise => { - const name = `nyanpasu-service`; - const isWin = SIDECAR_HOST?.includes("windows"); - const urlExt = isWin ? "zip" : "tar.gz"; + const name = `nyanpasu-service` + const isWin = SIDECAR_HOST?.includes('windows') + const urlExt = isWin ? 'zip' : 'tar.gz' // first we had to get the latest tag - const version = await getNyanpasuServiceLatestVersion(); - const downloadURL = `https://github.com/${SERVICE_REPO}/releases/download/${version}/${name}-${sidecarHost}.${urlExt}`; - const exeFile = `${name}${isWin ? ".exe" : ""}`; - const tmpFile = `${name}-${sidecarHost}.${urlExt}`; - const targetFile = `nyanpasu-service-${sidecarHost}${isWin ? ".exe" : ""}`; + const version = await getNyanpasuServiceLatestVersion() + const downloadURL = `https://github.com/${SERVICE_REPO}/releases/download/${version}/${name}-${sidecarHost}.${urlExt}` + const exeFile = `${name}${isWin ? '.exe' : ''}` + const tmpFile = `${name}-${sidecarHost}.${urlExt}` + const targetFile = `nyanpasu-service-${sidecarHost}${isWin ? '.exe' : ''}` return { - name: "nyanpasu-service", + name: 'nyanpasu-service', targetFile, exeFile, tmpFile, downloadURL, - }; -}; + } +} diff --git a/clash-nyanpasu/scripts/utils/shell.ts b/clash-nyanpasu/scripts/utils/shell.ts index 34bc47f423..d9a52c7f4c 100644 --- a/clash-nyanpasu/scripts/utils/shell.ts +++ b/clash-nyanpasu/scripts/utils/shell.ts @@ -1,5 +1,5 @@ -import { execSync } from "child_process"; +import { execSync } from 'child_process' -export const GIT_SHORT_HASH = execSync("git rev-parse --short HEAD") +export const GIT_SHORT_HASH = execSync('git rev-parse --short HEAD') .toString() - .trim(); + .trim() diff --git a/clash-nyanpasu/scripts/utils/telegram.ts b/clash-nyanpasu/scripts/utils/telegram.ts index 740f80a82a..e289989f98 100644 --- a/clash-nyanpasu/scripts/utils/telegram.ts +++ b/clash-nyanpasu/scripts/utils/telegram.ts @@ -1,23 +1,23 @@ -import { TelegramClient } from "telegram"; -import { StringSession } from "telegram/sessions"; +import { TelegramClient } from 'telegram' +import { StringSession } from 'telegram/sessions' if (!process.env.TELEGRAM_API_ID) { - throw new Error("TELEGRAM_API_ID is required"); + throw new Error('TELEGRAM_API_ID is required') } -const TELEGRAM_API_ID = Number(process.env.TELEGRAM_API_ID); +const TELEGRAM_API_ID = Number(process.env.TELEGRAM_API_ID) if (!process.env.TELEGRAM_API_HASH) { - throw new Error("TELEGRAM_API_ID is required"); + throw new Error('TELEGRAM_API_ID is required') } -const TELEGRAM_API_HASH = process.env.TELEGRAM_API_HASH; +const TELEGRAM_API_HASH = process.env.TELEGRAM_API_HASH export const client = new TelegramClient( - new StringSession(""), + new StringSession(''), TELEGRAM_API_ID, TELEGRAM_API_HASH, { connectionRetries: 5, }, -); +) diff --git a/filebrowser/auth/proxy.go b/filebrowser/auth/proxy.go index 11a7f9a046..9d1405405c 100644 --- a/filebrowser/auth/proxy.go +++ b/filebrowser/auth/proxy.go @@ -1,9 +1,9 @@ package auth import ( + "crypto/rand" "errors" "net/http" - "os" fbErrors "github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/settings" @@ -19,11 +19,40 @@ type ProxyAuth struct { } // Auth authenticates the user via an HTTP header. -func (a ProxyAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) { +func (a ProxyAuth) Auth(r *http.Request, usr users.Store, setting *settings.Settings, srv *settings.Server) (*users.User, error) { username := r.Header.Get(a.Header) user, err := usr.Get(srv.Root, username) if errors.Is(err, fbErrors.ErrNotExist) { - return nil, os.ErrPermission + randomPasswordBytes := make([]byte, 32) //nolint:gomnd + _, err = rand.Read(randomPasswordBytes) + if err != nil { + return nil, err + } + + var hashedRandomPassword string + hashedRandomPassword, err = users.HashPwd(string(randomPasswordBytes)) + if err != nil { + return nil, err + } + + user = &users.User{ + Username: username, + Password: hashedRandomPassword, + LockPassword: true, + } + setting.Defaults.Apply(user) + + var userHome string + userHome, err = setting.MakeUserDir(user.Username, user.Scope, srv.Root) + if err != nil { + return nil, err + } + user.Scope = userHome + + err = usr.Save(user) + if err != nil { + return nil, err + } } return user, err diff --git a/filebrowser/go.mod b/filebrowser/go.mod index b09774cc19..b6be3d7bf2 100644 --- a/filebrowser/go.mod +++ b/filebrowser/go.mod @@ -24,9 +24,9 @@ require ( github.com/stretchr/testify v1.9.0 github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce go.etcd.io/bbolt v1.3.11 - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.31.0 golang.org/x/image v0.19.0 - golang.org/x/text v0.17.0 + golang.org/x/text v0.21.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -65,7 +65,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.28.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/filebrowser/go.sum b/filebrowser/go.sum index ccc9fea9d7..7254e9b55a 100644 --- a/filebrowser/go.sum +++ b/filebrowser/go.sum @@ -174,8 +174,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -192,8 +192,8 @@ golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -204,14 +204,14 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/lede/target/linux/generic/hack-6.12/800-GPIO-add-named-gpio-exports.patch b/lede/target/linux/generic/hack-6.12/800-GPIO-add-named-gpio-exports.patch index 4fe2d87df3..a68b2fe80e 100644 --- a/lede/target/linux/generic/hack-6.12/800-GPIO-add-named-gpio-exports.patch +++ b/lede/target/linux/generic/hack-6.12/800-GPIO-add-named-gpio-exports.patch @@ -15,7 +15,7 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1187,3 +1189,72 @@ void of_gpiochip_remove(struct gpio_chip +@@ -1187,3 +1189,73 @@ void of_gpiochip_remove(struct gpio_chip { of_node_put(dev_of_node(&chip->gpiodev->dev)); } @@ -44,17 +44,19 @@ Signed-off-by: John Crispin + of_property_read_string(cnp, "gpio-export,name", &name); + + if (!name) -+ // max_gpio = of_gpio_count(cnp); ++ max_gpio = of_gpio_named_count(cnp, "gpios"); + + for (i = 0; i < max_gpio; i++) { ++ struct gpio_desc *desc; + unsigned flags = 0; + enum of_gpio_flags of_flags; + -+ gpio = of_get_named_gpio(cnp, i, &of_flags); -+ if (!gpio_is_valid(gpio)) -+ return gpio; ++ desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags); ++ if (IS_ERR(desc)) ++ return PTR_ERR(desc); ++ gpio = desc_to_gpio(desc); + -+ if (of_flags == OF_GPIO_ACTIVE_LOW) ++ if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + if (!of_property_read_u32(cnp, "gpio-export,output", &val)) @@ -66,7 +68,7 @@ Signed-off-by: John Crispin + continue; + + dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); -+ gpio_export_with_name(gpio, dmc, name); ++ gpio_export_with_name(gpio_to_desc(gpio), dmc, name); + nb++; + } + } @@ -79,7 +81,6 @@ Signed-off-by: John Crispin +static struct platform_driver gpio_export_driver = { + .driver = { + .name = "gpio-export", -+ .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_export_ids), + }, + .probe = of_gpio_export_probe, @@ -88,22 +89,24 @@ Signed-off-by: John Crispin +module_platform_driver(gpio_export_driver); + +#endif -\ No newline at end of file --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h -@@ -628,6 +628,7 @@ static inline int devm_acpi_dev_add_driv +@@ -628,7 +628,10 @@ static inline int devm_acpi_dev_add_driv #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) -+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); int gpiod_export(struct gpio_desc *desc, bool direction_may_change); ++int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, ++ const char *name); int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); -@@ -637,6 +638,13 @@ void gpiod_unexport(struct gpio_desc *de + void gpiod_unexport(struct gpio_desc *desc); +@@ -637,11 +640,25 @@ void gpiod_unexport(struct gpio_desc *de #include -+static inline int _gpiod_export(struct gpio_desc *desc, ++static inline int __gpiod_export(struct gpio_desc *desc, + bool direction_may_change, + const char *name) +{ @@ -113,6 +116,18 @@ Signed-off-by: John Crispin static inline int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { + return -ENOSYS; + } ++ ++static inline int gpio_export_with_name(struct gpio_desc *desc, ++ bool direction_may_change, ++ const char *name) ++{ ++ return -ENOSYS; ++} + + static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -571,7 +571,7 @@ static struct class gpio_class = { @@ -133,7 +148,7 @@ Signed-off-by: John Crispin dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, -@@ -650,6 +652,12 @@ err_unlock: +@@ -650,8 +652,21 @@ err_unlock: gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -145,4 +160,13 @@ Signed-off-by: John Crispin +} EXPORT_SYMBOL_GPL(gpiod_export); ++int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, ++ const char *name) ++{ ++ return __gpiod_export(desc, direction_may_change, name); ++} ++EXPORT_SYMBOL_GPL(gpio_export_with_name); ++ static int match_export(struct device *dev, const void *desc) + { + struct gpiod_data *data = dev_get_drvdata(dev); diff --git a/lede/target/linux/generic/pending-6.12/465-m25p80-mx-disable-software-protection.patch b/lede/target/linux/generic/pending-6.12/465-m25p80-mx-disable-software-protection.patch index e0adcdd9f0..5667e273f1 100644 --- a/lede/target/linux/generic/pending-6.12/465-m25p80-mx-disable-software-protection.patch +++ b/lede/target/linux/generic/pending-6.12/465-m25p80-mx-disable-software-protection.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; -+ nor->flags |= SNOR_F_HAS_LOCK; ++ nor->flags |= SNOR_F_HAS_LOCK; return 0; } diff --git a/lede/target/linux/generic/pending-6.12/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch b/lede/target/linux/generic/pending-6.12/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch index 9fecf843d0..6e08beabda 100644 --- a/lede/target/linux/generic/pending-6.12/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch +++ b/lede/target/linux/generic/pending-6.12/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch @@ -24,7 +24,7 @@ Signed-off-by: Nick Hainke { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; -+ nor->flags &= ~SNOR_F_HAS_16BIT_SR; - nor->flags |= SNOR_F_HAS_LOCK; ++ nor->flags &= ~SNOR_F_HAS_16BIT_SR; + nor->flags |= SNOR_F_HAS_LOCK; return 0; diff --git a/lede/target/linux/rockchip/Makefile b/lede/target/linux/rockchip/Makefile index 2160442f77..c3d46c278e 100644 --- a/lede/target/linux/rockchip/Makefile +++ b/lede/target/linux/rockchip/Makefile @@ -16,7 +16,7 @@ endef include $(INCLUDE_DIR)/target.mk -DEFAULT_PACKAGES += uboot-envtools partx-utils e2fsprogs mkf2fs kmod-gpio-button-hotplug \ +DEFAULT_PACKAGES += uboot-envtools partx-utils e2fsprogs mkf2fs kmod-button-hotplug \ automount autocore-arm e2fsprogs ethtool haveged htop usb-modeswitch KERNELNAME:=Image dtbs diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3399-fine-3399.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3399-fine-3399.dts index e02460479a..3e9105d006 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3399-fine-3399.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3399-fine-3399.dts @@ -5,7 +5,7 @@ #include #include #include "rk3399.dtsi" -#include "rk3399-op1-opp.dtsi" +#include "rk3399-opp.dtsi" / { model = "RUMU3F Fine3399"; diff --git a/lede/target/linux/rockchip/image/armv8.mk b/lede/target/linux/rockchip/image/armv8.mk index 830e77d10a..13648ab772 100644 --- a/lede/target/linux/rockchip/image/armv8.mk +++ b/lede/target/linux/rockchip/image/armv8.mk @@ -80,7 +80,7 @@ define Device/dilusense_dlfr100 SOC := rk3399 UBOOT_DEVICE_NAME := dlfr100-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += dilusense_dlfr100 @@ -108,7 +108,7 @@ define Device/fastrhino_common DEVICE_VENDOR := FastRhino SOC := rk3568 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss endef define Device/fastrhino_r66s @@ -160,7 +160,7 @@ define Device/friendlyarm_nanopi-r2c SOC := rk3328 UBOOT_DEVICE_NAME := nanopi-r2c-rk3328 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-usb-net-rtl8152 + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-usb-net-rtl8152 endef TARGET_DEVICES += friendlyarm_nanopi-r2c @@ -170,7 +170,7 @@ define Device/friendlyarm_nanopi-r2c-plus SOC := rk3328 UBOOT_DEVICE_NAME := nanopi-r2c-plus-rk3328 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-usb-net-rtl8152 + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-usb-net-rtl8152 endef TARGET_DEVICES += friendlyarm_nanopi-r2c-plus @@ -180,7 +180,7 @@ define Device/friendlyarm_nanopi-r2s SOC := rk3328 UBOOT_DEVICE_NAME := nanopi-r2s-rk3328 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-usb-net-rtl8152 + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-usb-net-rtl8152 endef TARGET_DEVICES += friendlyarm_nanopi-r2s @@ -190,7 +190,7 @@ define Device/friendlyarm_nanopi-r2s-plus SOC := rk3328 UBOOT_DEVICE_NAME := nanopi-r2s-plus-rk3328 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-usb-net-rtl8152 + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-usb-net-rtl8152 endef TARGET_DEVICES += friendlyarm_nanopi-r2s-plus @@ -200,7 +200,7 @@ define Device/friendlyarm_nanopi-r3s SOC := rk3566 UBOOT_DEVICE_NAME := nanopi-r3s-rk3566 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += friendlyarm_nanopi-r3s @@ -210,7 +210,7 @@ define Device/friendlyarm_nanopi-r4s SOC := rk3399 UBOOT_DEVICE_NAME := nanopi-r4s-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += friendlyarm_nanopi-r4s @@ -220,7 +220,7 @@ define Device/friendlyarm_nanopi-r4se SOC := rk3399 UBOOT_DEVICE_NAME := nanopi-r4se-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += friendlyarm_nanopi-r4se @@ -230,7 +230,7 @@ define Device/friendlyarm_nanopi-r5c SOC := rk3568 UBOOT_DEVICE_NAME := nanopi-r5c-rk3568 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss endef TARGET_DEVICES += friendlyarm_nanopi-r5c @@ -240,7 +240,7 @@ define Device/friendlyarm_nanopi-r5s SOC := rk3568 UBOOT_DEVICE_NAME := nanopi-r5s-rk3568 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss endef TARGET_DEVICES += friendlyarm_nanopi-r5s @@ -250,7 +250,7 @@ define Device/friendlyarm_nanopi-r6c SOC := rk3588s UBOOT_DEVICE_NAME := nanopi-r6c-rk3588s IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss endef TARGET_DEVICES += friendlyarm_nanopi-r6c @@ -260,7 +260,7 @@ define Device/friendlyarm_nanopi-r6s SOC := rk3588s UBOOT_DEVICE_NAME := nanopi-r6s-rk3588s IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss endef TARGET_DEVICES += friendlyarm_nanopi-r6s @@ -339,7 +339,7 @@ define Device/lyt_t68m SOC := rk3568 UBOOT_DEVICE_NAME := generic-rk3568 IMAGE/sysupgrade.img.gz := boot-common | boot-script vop | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-drm-rockchip kmod-mt7921e kmod-r8125-rss wpad-openssl uboot-envtools + DEVICE_PACKAGES := kmod-drm-rockchip kmod-gpio-button-hotplug kmod-r8125-rss uboot-envtools endef TARGET_DEVICES += lyt_t68m @@ -350,7 +350,7 @@ define Device/mmbox_anas3035 DEVICE_DTS := rockchip/rk3568-mmbox-anas3035 UBOOT_DEVICE_NAME := mmbox-anas3035-rk3568 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8125-rss kmod-ata-ahci-dwc kmod-hwmon-pwmfan kmod-hwmon-drivetemp + DEVICE_PACKAGES := kmod-ata-ahci-dwc kmod-hwmon-drivetemp kmod-hwmon-pwmfan kmod-r8125-rss endef TARGET_DEVICES += mmbox_anas3035 @@ -370,7 +370,6 @@ define Device/pine64_rockpro64 SOC := rk3399 UBOOT_DEVICE_NAME := rockpro64-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := -urngd endef TARGET_DEVICES += pine64_rockpro64 @@ -380,7 +379,7 @@ define Device/radxa_e20c DEVICE_DTS := rockchip/rk3528-radxa-e20c UBOOT_DEVICE_NAME := evb-rk3528 IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 -urngd endef TARGET_DEVICES += radxa_e20c @@ -414,16 +413,14 @@ define Device/radxa_rock-3c endef TARGET_DEVICES += radxa_rock-3c -define Device/radxa_rock-pi-4 +define Device/radxa_rock-pi-4a DEVICE_VENDOR := Radxa - DEVICE_MODEL := ROCK Pi 4 + DEVICE_MODEL := ROCK Pi 4A SOC := rk3399 - SUPPORTED_DEVICES := radxa,rockpi4 + SUPPORTED_DEVICES := radxa,rockpi4a radxa,rockpi4 UBOOT_DEVICE_NAME := rock-pi-4-rk3399 - IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := -urngd endef -TARGET_DEVICES += radxa_rock-pi-4 +TARGET_DEVICES += radxa_rock-pi-4a define Device/radxa_rock-5a DEVICE_VENDOR := Radxa @@ -441,7 +438,7 @@ define Device/rongpin_king3399 SOC := rk3399 UBOOT_DEVICE_NAME := king3399-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd kmod-brcmfmac cypress-firmware-4356-sdio wpad-openssl + DEVICE_PACKAGES := kmod-r8168 kmod-brcmfmac cypress-firmware-4356-sdio wpad-openssl endef TARGET_DEVICES += rongpin_king3399 @@ -451,7 +448,7 @@ define Device/rocktech_mpc1903 SOC := rk3399 UBOOT_DEVICE_NAME := mpc1903-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-usb-net-smsc75xx kmod-usb-serial-cp210x -urngd + DEVICE_PACKAGES := kmod-usb-net-smsc75xx kmod-usb-serial-cp210x endef TARGET_DEVICES += rocktech_mpc1903 @@ -461,7 +458,7 @@ define Device/rumu3f_fine-3399 SOC := rk3399 UBOOT_DEVICE_NAME := fine3399-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += rumu3f_fine-3399 @@ -472,7 +469,7 @@ define Device/scensmart_sv901-eaio UBOOT_DEVICE_NAME := sv901-eaio-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-bin | gzip | append-metadata DEVICE_PACKAGES := brcmfmac-nvram-4356-sdio cypress-firmware-4356-sdio kmod-brcmfmac \ - kmod-switch-rtl8367b swconfig wpad -urngd + kmod-gpio-button-hotplug kmod-switch-rtl8367b swconfig wpad endef TARGET_DEVICES += scensmart_sv901-eaio @@ -509,7 +506,7 @@ define Device/sharevdi_h3399pc SOC := rk3399 UBOOT_DEVICE_NAME := h3399pc-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += sharevdi_h3399pc @@ -519,7 +516,7 @@ define Device/sharevdi_guangmiao-g4c SOC := rk3399 UBOOT_DEVICE_NAME := guangmiao-g4c-rk3399 IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata - DEVICE_PACKAGES := kmod-r8168 -urngd + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8168 endef TARGET_DEVICES += sharevdi_guangmiao-g4c diff --git a/lede/target/linux/rockchip/patches-5.15/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch b/lede/target/linux/rockchip/patches-5.15/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch index 9090e96dce..c3989d977c 100644 --- a/lede/target/linux/rockchip/patches-5.15/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch +++ b/lede/target/linux/rockchip/patches-5.15/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch @@ -20,11 +20,11 @@ Signed-off-by: Tianling Shen }; + opp06 { + opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <1225000>; ++ opp-microvolt = <1225000 1225000 1250000>; + }; + opp07 { + opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <1275000>; ++ opp-microvolt = <1275000 1275000 1275000>; + }; }; @@ -35,11 +35,11 @@ Signed-off-by: Tianling Shen }; + opp08 { + opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <1250000>; ++ opp-microvolt = <1250000 1250000 1250000>; + }; + opp09 { + opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <1325000>; ++ opp-microvolt = <1325000 1325000 1325000>; + }; }; diff --git a/lede/target/linux/rockchip/patches-6.1/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch b/lede/target/linux/rockchip/patches-6.1/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch index ee8527a2fc..ba96cb4ae1 100644 --- a/lede/target/linux/rockchip/patches-6.1/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch +++ b/lede/target/linux/rockchip/patches-6.1/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch @@ -20,11 +20,11 @@ Signed-off-by: Tianling Shen }; + opp06 { + opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <1225000>; ++ opp-microvolt = <1225000 1225000 1250000>; + }; + opp07 { + opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <1275000>; ++ opp-microvolt = <1275000 1275000 1275000>; + }; }; @@ -35,11 +35,11 @@ Signed-off-by: Tianling Shen }; + opp08 { + opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <1250000>; ++ opp-microvolt = <1250000 1250000 1250000>; + }; + opp09 { + opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <1325000>; ++ opp-microvolt = <1325000 1325000 1325000>; + }; }; diff --git a/lede/target/linux/rockchip/patches-6.6/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch b/lede/target/linux/rockchip/patches-6.6/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch index ee8527a2fc..ba96cb4ae1 100644 --- a/lede/target/linux/rockchip/patches-6.6/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch +++ b/lede/target/linux/rockchip/patches-6.6/992-rockchip-rk3399-overclock-to-2.2-1.8-GHz.patch @@ -20,11 +20,11 @@ Signed-off-by: Tianling Shen }; + opp06 { + opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <1225000>; ++ opp-microvolt = <1225000 1225000 1250000>; + }; + opp07 { + opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <1275000>; ++ opp-microvolt = <1275000 1275000 1275000>; + }; }; @@ -35,11 +35,11 @@ Signed-off-by: Tianling Shen }; + opp08 { + opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <1250000>; ++ opp-microvolt = <1250000 1250000 1250000>; + }; + opp09 { + opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <1325000>; ++ opp-microvolt = <1325000 1325000 1325000>; + }; }; diff --git a/mieru/pkg/appctl/url.go b/mieru/pkg/appctl/url.go index a1e546e5f1..ac2d0fd78d 100644 --- a/mieru/pkg/appctl/url.go +++ b/mieru/pkg/appctl/url.go @@ -18,13 +18,22 @@ package appctl import ( "encoding/base64" "fmt" + "net" "net/url" + "regexp" + "strconv" + "strings" pb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb" + "github.com/enfein/mieru/v3/pkg/common" "github.com/enfein/mieru/v3/pkg/stderror" "google.golang.org/protobuf/proto" ) +var ( + safeURLRegExp = regexp.MustCompile(`^[0-9A-Za-z_-]+$`) +) + // ClientConfigToURL creates a URL to share the client configuration. func ClientConfigToURL(config *pb.ClientConfig) (string, error) { if config == nil { @@ -37,6 +46,69 @@ func ClientConfigToURL(config *pb.ClientConfig) (string, error) { return "mieru://" + base64.StdEncoding.EncodeToString(b), nil } +// ClientProfileToMultiURLs creates a list of human readable URLs to share +// the client profile configuration. +func ClientProfileToMultiURLs(profile *pb.ClientProfile) (urls []string, err error) { + if profile == nil { + return nil, stderror.ErrNullPointer + } + profileName := profile.GetProfileName() + userName := profile.GetUser().GetName() + password := profile.GetUser().GetPassword() + servers := profile.GetServers() + if profileName == "" { + return nil, fmt.Errorf("profile name is empty") + } + if userName == "" { + return nil, fmt.Errorf("user name in profile %s is empty", profileName) + } + if !isSafeURLString(userName) { + return nil, fmt.Errorf("user name %q in profile %s can't be safely encoded to URL. Only allow A-Z, a-z, 0-9, underscore _, and hyphen -", userName, profileName) + } + if password == "" { + return nil, fmt.Errorf("password in profile %s is empty", profileName) + } + if !isSafeURLString(password) { + return nil, fmt.Errorf("password %q in profile %s can't be safely encoded to URL. Only allow A-Z, a-z, 0-9, underscore _, and hyphen -", password, profileName) + } + if len(servers) == 0 { + return nil, fmt.Errorf("profile %s has no server", profileName) + } + for _, server := range servers { + u := &url.URL{Scheme: "mierus"} // mierus => mieru simple + u.User = url.UserPassword(userName, password) + if server.GetDomainName() != "" { + u.Host = server.GetDomainName() + } else if server.GetIpAddress() != "" { + u.Host = common.MaybeDecorateIPv6(server.GetIpAddress()) + } else { + return nil, fmt.Errorf("profile %s has a server with no domain name or IP address", profileName) + } + if len(server.GetPortBindings()) == 0 { + return nil, fmt.Errorf("profile %s has a server %s with no port bindings", profileName, u.Host) + } + q := url.Values{} + q.Add("profile", profileName) + if profile.Mtu != nil { + q.Add("mtu", strconv.Itoa(int(profile.GetMtu()))) + } + if profile.Multiplexing != nil && profile.Multiplexing.Level != nil { + q.Add("multiplexing", profile.GetMultiplexing().GetLevel().String()) + } + for _, binding := range server.GetPortBindings() { + if binding.GetPortRange() != "" { + q.Add("port", binding.GetPortRange()) + } else { + q.Add("port", strconv.Itoa(int(binding.GetPort()))) + } + q.Add("protocol", binding.GetProtocol().String()) + } + u.RawQuery = q.Encode() + urls = append(urls, u.String()) + } + return +} + // URLToClientConfig returns a client configuration based on the URL. func URLToClientConfig(s string) (*pb.ClientConfig, error) { u, err := url.Parse(s) @@ -59,3 +131,112 @@ func URLToClientConfig(s string) (*pb.ClientConfig, error) { } return c, nil } + +// URLToClientProfile returns a client profile based on the mieru simple URL. +func URLToClientProfile(s string) (*pb.ClientProfile, error) { + u, err := url.Parse(s) + if err != nil { + return nil, fmt.Errorf("url.Parse() failed: %w", err) + } + if u.Scheme != "mierus" { + return nil, fmt.Errorf("unrecognized URL scheme %q", u.Scheme) + } + if u.Opaque != "" { + return nil, fmt.Errorf("URL is opaque") + } + + p := &pb.ClientProfile{ + User: &pb.User{}, + } + if u.User == nil { + return nil, fmt.Errorf("URL has no user info") + } + if u.User.Username() == "" { + return nil, fmt.Errorf("URL has no user name") + } + pw, _ := u.User.Password() + if pw == "" { + return nil, fmt.Errorf("URL has no password") + } + p.User.Name = proto.String(u.User.Username()) + p.User.Password = proto.String(pw) + + if u.Hostname() == "" { + return nil, fmt.Errorf("URL has no host") + } + server := &pb.ServerEndpoint{} + if net.ParseIP(u.Hostname()) != nil { + server.IpAddress = proto.String(u.Hostname()) + } else { + server.DomainName = proto.String(u.Hostname()) + } + + q := u.Query() + if q.Get("profile") == "" { + return nil, fmt.Errorf("URL has no profile name") + } + p.ProfileName = proto.String(q.Get("profile")) + if q.Get("mtu") != "" { + mtu, err := strconv.Atoi(q.Get("mtu")) + if err != nil { + return nil, fmt.Errorf("URL has invalid MTU %q", q.Get("mtu")) + } + p.Mtu = proto.Int32(int32(mtu)) + } + if q.Get("multiplexing") != "" { + level := pb.MultiplexingLevel(pb.MultiplexingLevel_value[q.Get("multiplexing")]) + p.Multiplexing = &pb.MultiplexingConfig{ + Level: &level, + } + } + + portList := q["port"] + protocolList := q["protocol"] + if len(portList) != len(protocolList) { + return nil, fmt.Errorf("URL has mismatched number of port and number of protocol") + } + for idx, port := range portList { + portNum, err := strconv.Atoi(port) + if err != nil { + portRangeParts := strings.Split(port, "-") + if len(portRangeParts) != 2 { + return nil, fmt.Errorf("URL has invalid port or port range %q", port) + } + beginPort, err := strconv.Atoi(portRangeParts[0]) + if err != nil { + return nil, fmt.Errorf("URL has invalid begin of port range %q", portRangeParts[0]) + } + endPort, err := strconv.Atoi(portRangeParts[1]) + if err != nil { + return nil, fmt.Errorf("URL has invalid end of port range %q", portRangeParts[1]) + } + if beginPort < 1 || beginPort > 65535 { + return nil, fmt.Errorf("URL has invalid begin port number %d", beginPort) + } + if endPort < 1 || endPort > 65535 { + return nil, fmt.Errorf("URL has invalid end port number %d", endPort) + } + if beginPort > endPort { + return nil, fmt.Errorf("URL's begin port number %d is greater than end port number %d", beginPort, endPort) + } + server.PortBindings = append(server.PortBindings, &pb.PortBinding{ + PortRange: proto.String(fmt.Sprintf("%d-%d", beginPort, endPort)), + Protocol: pb.TransportProtocol(pb.TransportProtocol_value[protocolList[idx]]).Enum(), + }) + } else { + if portNum < 1 || portNum > 65535 { + return nil, fmt.Errorf("URL has invalid port number %d", portNum) + } + server.PortBindings = append(server.PortBindings, &pb.PortBinding{ + Port: proto.Int32(int32(portNum)), + Protocol: pb.TransportProtocol(pb.TransportProtocol_value[protocolList[idx]]).Enum(), + }) + } + } + p.Servers = append(p.Servers, server) + return p, nil +} + +func isSafeURLString(input string) bool { + return safeURLRegExp.MatchString(input) +} diff --git a/mieru/pkg/appctl/url_test.go b/mieru/pkg/appctl/url_test.go index 2d6ceeef99..60bfb93869 100644 --- a/mieru/pkg/appctl/url_test.go +++ b/mieru/pkg/appctl/url_test.go @@ -22,7 +22,7 @@ import ( "google.golang.org/protobuf/proto" ) -func TestURL(t *testing.T) { +func TestClientConfigWithURL(t *testing.T) { c := &pb.ClientConfig{ Profiles: []*pb.ClientProfile{ { @@ -42,6 +42,10 @@ func TestURL(t *testing.T) { }, }, }, + Mtu: proto.Int32(1280), + Multiplexing: &pb.MultiplexingConfig{ + Level: pb.MultiplexingLevel_MULTIPLEXING_MIDDLE.Enum(), + }, }, }, ActiveProfile: proto.String("default"), @@ -62,3 +66,114 @@ func TestURL(t *testing.T) { t.Fatalf("client config is not equal after generating and loading URL:\n%s\n%s", c.String(), c2.String()) } } + +func TestClientProfileWithMultiURLs(t *testing.T) { + p := &pb.ClientProfile{ + ProfileName: proto.String("default"), + User: &pb.User{ + Name: proto.String("qingguanyidao"), + Password: proto.String("tongshangkuanyi"), + }, + Servers: []*pb.ServerEndpoint{ + { + IpAddress: proto.String("2001:db8::1"), + PortBindings: []*pb.PortBinding{ + { + Port: proto.Int32(6666), + Protocol: pb.TransportProtocol_TCP.Enum(), + }, + { + PortRange: proto.String("8964-8965"), + Protocol: pb.TransportProtocol_UDP.Enum(), + }, + }, + }, + { + DomainName: proto.String("example.com"), + PortBindings: []*pb.PortBinding{ + { + Port: proto.Int32(9999), + Protocol: pb.TransportProtocol_TCP.Enum(), + }, + }, + }, + }, + Mtu: proto.Int32(1280), + Multiplexing: &pb.MultiplexingConfig{ + Level: pb.MultiplexingLevel_MULTIPLEXING_MIDDLE.Enum(), + }, + } + + p0 := &pb.ClientProfile{ + ProfileName: proto.String("default"), + User: &pb.User{ + Name: proto.String("qingguanyidao"), + Password: proto.String("tongshangkuanyi"), + }, + Servers: []*pb.ServerEndpoint{ + { + IpAddress: proto.String("2001:db8::1"), + PortBindings: []*pb.PortBinding{ + { + Port: proto.Int32(6666), + Protocol: pb.TransportProtocol_TCP.Enum(), + }, + { + PortRange: proto.String("8964-8965"), + Protocol: pb.TransportProtocol_UDP.Enum(), + }, + }, + }, + }, + Mtu: proto.Int32(1280), + Multiplexing: &pb.MultiplexingConfig{ + Level: pb.MultiplexingLevel_MULTIPLEXING_MIDDLE.Enum(), + }, + } + + p1 := &pb.ClientProfile{ + ProfileName: proto.String("default"), + User: &pb.User{ + Name: proto.String("qingguanyidao"), + Password: proto.String("tongshangkuanyi"), + }, + Servers: []*pb.ServerEndpoint{ + { + DomainName: proto.String("example.com"), + PortBindings: []*pb.PortBinding{ + { + Port: proto.Int32(9999), + Protocol: pb.TransportProtocol_TCP.Enum(), + }, + }, + }, + }, + Mtu: proto.Int32(1280), + Multiplexing: &pb.MultiplexingConfig{ + Level: pb.MultiplexingLevel_MULTIPLEXING_MIDDLE.Enum(), + }, + } + + urls, err := ClientProfileToMultiURLs(p) + if err != nil { + t.Fatalf("ClientConfigToMultiURLs() failed: %v", err) + } + if len(urls) != 2 { + t.Fatalf("got %d URLs, want 2", len(urls)) + } + + profile0, err := URLToClientProfile(urls[0]) + if err != nil { + t.Fatalf("URLToClientProfile() failed: %v", err) + } + if !proto.Equal(profile0, p0) { + t.Errorf("profile is not equal after generating and loading URL %q", urls[0]) + } + profile1, err := URLToClientProfile(urls[1]) + if err != nil { + t.Fatalf("URLToClientProfile() failed: %v", err) + } + if !proto.Equal(profile1, p1) { + t.Errorf("profile is not equal after generating and loading URL %q", urls[1]) + } +} diff --git a/mieru/pkg/cli/client.go b/mieru/pkg/cli/client.go index 2971f15689..ab43882bed 100644 --- a/mieru/pkg/cli/client.go +++ b/mieru/pkg/cli/client.go @@ -248,93 +248,102 @@ var clientHelpFunc = func(s []string) error { entries: []helpCmdEntry{ { cmd: "help", - help: "Show mieru client help.", + help: []string{"Show mieru client help."}, }, { cmd: "start", - help: "Start mieru client in background.", + help: []string{"Start mieru client in background."}, }, { cmd: "stop", - help: "Stop mieru client.", + help: []string{"Stop mieru client."}, }, { cmd: "status", - help: "Check mieru client status.", + help: []string{"Check mieru client status."}, }, { cmd: "test [URL]", - help: "Test mieru client connection to the Internet via proxy server.", + help: []string{"Test mieru client connection to the Internet via proxy server."}, }, { cmd: "apply config ", - help: "Apply client configuration from JSON file.", + help: []string{"Apply client configuration from JSON file."}, }, { cmd: "describe config", - help: "Show current client configuration.", + help: []string{"Show current client configuration."}, }, { cmd: "import config ", - help: "Import client configuration from URL.", + help: []string{"Import client configuration from URL."}, }, { cmd: "export config", - help: "Export client configuration as URL.", + help: []string{"Export client configuration as URL."}, }, { cmd: "delete profile ", - help: "Delete an inactive client configuration profile.", + help: []string{"Delete an inactive client configuration profile."}, }, { - cmd: "delete http proxy", - help: "Delete HTTP(S) proxy. Allow socks5 user password authentication to be used.", + cmd: "delete http proxy", + help: []string{ + "Delete HTTP(S) proxy.", + "Allow socks5 user password authentication to be used.", + }, }, { - cmd: "delete socks5 authentication", - help: "Delete socks5 user password authentication. Allow HTTP(S) proxy to be used.", + cmd: "delete socks5 authentication", + help: []string{ + "Delete socks5 user password authentication.", + "Allow HTTP(S) proxy to be used.", + }, }, { cmd: "get metrics", - help: "Get mieru client metrics.", + help: []string{"Get mieru client metrics."}, }, { cmd: "get connections", - help: "Get mieru client connections.", + help: []string{"Get mieru client connections."}, }, { cmd: "version", - help: "Show mieru client version.", + help: []string{"Show mieru client version."}, }, { cmd: "check update", - help: "Check mieru client update.", + help: []string{"Check mieru client update."}, }, }, advanced: []helpCmdEntry{ { - cmd: "run", - help: "Run mieru client in foreground.", + cmd: "run", + help: []string{ + "Run mieru client in foreground.", + "Use environment variable MIERU_CONFIG_JSON_FILE to load configuration.", + }, }, { cmd: "get thread-dump", - help: "Get mieru client thread dump.", + help: []string{"Get mieru client thread dump."}, }, { cmd: "get heap-profile ", - help: "Get mieru client heap profile and save results to the file.", + help: []string{"Get mieru client heap profile and save results to the file."}, }, { cmd: "get memory-statistics", - help: "Get mieru client memory statistics.", + help: []string{"Get mieru client memory statistics."}, }, { cmd: "profile cpu start ", - help: "Start mieru client CPU profile and save results to the file.", + help: []string{"Start mieru client CPU profile and save results to the file."}, }, { cmd: "profile cpu stop", - help: "Stop mieru client CPU profile.", + help: []string{"Stop mieru client CPU profile."}, }, }, } diff --git a/mieru/pkg/cli/helpfmt.go b/mieru/pkg/cli/helpfmt.go index b2c7317a11..774c875501 100644 --- a/mieru/pkg/cli/helpfmt.go +++ b/mieru/pkg/cli/helpfmt.go @@ -25,7 +25,7 @@ type helpFormatter struct { type helpCmdEntry struct { cmd string - help string + help []string } func (m helpFormatter) print() { @@ -37,7 +37,9 @@ func (m helpFormatter) print() { log.Infof("Commands:") for _, entry := range m.entries { log.Infof(" %s", entry.cmd) - log.Infof(" %s", entry.help) + for _, line := range entry.help { + log.Infof(" %s", line) + } log.Infof("") } } @@ -45,7 +47,9 @@ func (m helpFormatter) print() { log.Infof("Commands for developers and experienced users:") for _, entry := range m.advanced { log.Infof(" %s", entry.cmd) - log.Infof(" %s", entry.help) + for _, line := range entry.help { + log.Infof(" %s", line) + } log.Infof("") } } diff --git a/mieru/pkg/cli/server.go b/mieru/pkg/cli/server.go index 3c7b378229..cd663d305e 100644 --- a/mieru/pkg/cli/server.go +++ b/mieru/pkg/cli/server.go @@ -200,77 +200,80 @@ var serverHelpFunc = func(s []string) error { entries: []helpCmdEntry{ { cmd: "help", - help: "Show mita server help.", + help: []string{"Show mita server help."}, }, { cmd: "start", - help: "Start mita server proxy service.", + help: []string{"Start mita server proxy service."}, }, { cmd: "stop", - help: "Stop mita server proxy service.", + help: []string{"Stop mita server proxy service."}, }, { cmd: "reload", - help: "Reload mita server configuration without stopping proxy service.", + help: []string{"Reload mita server configuration without stopping proxy service."}, }, { cmd: "status", - help: "Check mita server proxy service status.", + help: []string{"Check mita server proxy service status."}, }, { cmd: "apply config ", - help: "Apply server configuration from JSON file.", + help: []string{"Apply server configuration from JSON file."}, }, { cmd: "describe config", - help: "Show current server configuration.", + help: []string{"Show current server configuration."}, }, { cmd: "delete user ", - help: "Delete a user from server configuration.", + help: []string{"Delete a user from server configuration."}, }, { cmd: "get metrics", - help: "Get mita server metrics.", + help: []string{"Get mita server metrics."}, }, { cmd: "get connections", - help: "Get mita server connections.", + help: []string{"Get mita server connections."}, }, { cmd: "version", - help: "Show mita server version.", + help: []string{"Show mita server version."}, }, { cmd: "check update", - help: "Check mita server update.", + help: []string{"Check mita server update."}, }, }, advanced: []helpCmdEntry{ { - cmd: "run", - help: "Run mita server in foreground.", + cmd: "run", + help: []string{ + "Run mita server in foreground.", + "Use environment variable MITA_CONFIG_JSON_FILE to load configuration.", + }, }, { cmd: "get thread-dump", - help: "Get mita server thread dump.", + help: []string{"Get mita server thread dump."}, }, { cmd: "get heap-profile ", - help: "Get mita server heap profile and save results to the file.", + help: []string{"Get mita server heap profile and save results to the file."}, }, { cmd: "get memory-statistics", - help: "Get mita server memory statistics.", + help: []string{"Get mita server memory statistics."}, }, { cmd: "profile cpu start ", - help: "Start mita server CPU profile and save results to the file.", + help: []string{"Start mita server CPU profile and save results to the file."}, }, { cmd: "profile cpu stop", - help: "Stop mita server CPU profile.", + help: []string{"Stop mita server CPU profile."}, }, }, } diff --git a/mieru/pkg/protocol/session.go b/mieru/pkg/protocol/session.go index f26870ff51..4c89f2b623 100644 --- a/mieru/pkg/protocol/session.go +++ b/mieru/pkg/protocol/session.go @@ -430,15 +430,22 @@ func (s *Session) writeChunk(b []byte) (n int, err error) { seqBeforeWrite, _ := s.sendQueue.MinSeq() // Determine number of fragments to write. - // Return if there is no enough space in send queue. nFragment := 1 fragmentSize := MaxFragmentSize(s.mtu, s.conn.TransportProtocol()) if len(b) > fragmentSize { nFragment = (len(b)-1)/fragmentSize + 1 } - if s.sendQueue.Remaining() <= nFragment { // leave one slot in case it is needed - time.Sleep(tickInterval) // add back pressure - return 0, nil + for s.sendQueue.Remaining() < nFragment { + select { + case <-s.closedChan: + return 0, io.EOF + case <-s.outputErr: + return 0, io.ErrClosedPipe + case <-timeC: + return 0, stderror.ErrTimeout + default: + } + time.Sleep(tickInterval) // add back pressure if queue is full } s.oLock.Lock() diff --git a/mieru/pkg/protocol/underlay_packet.go b/mieru/pkg/protocol/underlay_packet.go index 65cfdc4aac..abe0501e6e 100644 --- a/mieru/pkg/protocol/underlay_packet.go +++ b/mieru/pkg/protocol/underlay_packet.go @@ -179,25 +179,7 @@ func (u *PacketUnderlay) RunEventLoop(ctx context.Context) error { case <-u.done: return nil case <-u.idleSessionTicker.C: - // Close idle sessions. - u.sessionMap.Range(func(k, v any) bool { - session := v.(*Session) - select { - case <-session.closedChan: - log.Debugf("Found closed %v", session) - if err := u.RemoveSession(session); err != nil { - log.Debugf("%v RemoveSession() failed: %v", u, err) - } - default: - } - if time.Since(session.lastRXTime) > idleSessionTimeout { - log.Debugf("Found idle %v", session) - if err := u.RemoveSession(session); err != nil { - log.Debugf("%v RemoveSession() failed: %v", u, err) - } - } - return true - }) + u.closeIdleSessions() default: } seg, addr, err := u.readOneSegment() @@ -439,7 +421,8 @@ func (u *PacketUnderlay) readOneSegment() (*segment, net.Addr, error) { } } if len(decryptedMeta) != MetadataLength { - return nil, nil, fmt.Errorf("decrypted metadata size %d is unexpected", len(decryptedMeta)) + log.Debugf("decrypted metadata size %d is unexpected", len(decryptedMeta)) + continue } // Read payload and construct segment. @@ -491,8 +474,14 @@ func (u *PacketUnderlay) readOneSegment() (*segment, net.Addr, error) { seg.block = blockCipher } return seg, addr, nil + } else { + if u.isClient { + return nil, nil, fmt.Errorf("unable to handle protocol %d", p) + } else { + log.Debugf("%v unable to handle protocol %d", u, p) + continue + } } - return nil, nil, fmt.Errorf("unable to handle protocol %d", p) } } @@ -714,3 +703,24 @@ func (u *PacketUnderlay) writeOneSegment(seg *segment, addr net.Addr) error { } return nil } + +func (u *PacketUnderlay) closeIdleSessions() { + u.sessionMap.Range(func(k, v any) bool { + session := v.(*Session) + select { + case <-session.closedChan: + log.Debugf("Found closed %v", session) + if err := u.RemoveSession(session); err != nil { + log.Debugf("%v RemoveSession() failed: %v", u, err) + } + default: + } + if time.Since(session.lastRXTime) > idleSessionTimeout { + log.Debugf("Found idle %v", session) + if err := u.RemoveSession(session); err != nil { + log.Debugf("%v RemoveSession() failed: %v", u, err) + } + } + return true + }) +} diff --git a/openwrt-packages/luci-app-store/Makefile b/openwrt-packages/luci-app-store/Makefile index f738e21838..53b0695225 100644 --- a/openwrt-packages/luci-app-store/Makefile +++ b/openwrt-packages/luci-app-store/Makefile @@ -11,7 +11,7 @@ LUCI_DEPENDS:=+curl +opkg +luci-base +tar +libuci-lua +mount-utils +luci-lib-tas LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19) LUCI_PKGARCH:=all -PKG_VERSION:=0.1.27-2 +PKG_VERSION:=0.1.27-3 # PKG_RELEASE MUST be empty for luci.mk PKG_RELEASE:= diff --git a/openwrt-packages/luci-app-store/root/bin/is-opkg b/openwrt-packages/luci-app-store/root/bin/is-opkg index ab5470a8c2..0566af2688 100755 --- a/openwrt-packages/luci-app-store/root/bin/is-opkg +++ b/openwrt-packages/luci-app-store/root/bin/is-opkg @@ -74,7 +74,7 @@ opkg_wrap_mirrors() { alias fcurl='curl -L --fail --show-error' check_space() { - local free="$((`df -k / | awk 'NR==2 {print $4}'` >> 10 ))" + local free="$((`df -kP / | awk 'NR==2 {print $4}'` >> 10 ))" if [ "$free" -lt 1 ]; then echo "Root disk full!" >&2 exit 1 diff --git a/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml b/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml index b52038fa02..711a2f8bc9 100644 --- a/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml +++ b/openwrt-passwall/.github/workflows/Auto compile with openwrt sdk.yml @@ -11,11 +11,6 @@ on: description: 'SSH connection to Actions' required: false default: 'false' - push: - branches: - - 'main' - paths: - - 'luci-app-passwall/Makefile' env: TZ: Asia/Shanghai passwall: ${{ github.repository }} diff --git a/openwrt-passwall/luci-app-passwall/Makefile b/openwrt-passwall/luci-app-passwall/Makefile index fa1cd41382..2b724683e3 100644 --- a/openwrt-passwall/luci-app-passwall/Makefile +++ b/openwrt-passwall/luci-app-passwall/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall -PKG_VERSION:=24.12.08 -PKG_RELEASE:=1 +PKG_VERSION:=24.12.17 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh index 7d1f95afd3..40b657cd68 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1969,7 +1969,7 @@ start() { } [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start set_cache_var "USE_TABLES" "$USE_TABLES" - [ -z $(get_cache_var "ACL_default_dns_port") ] && lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1 + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1 if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) set_cache_var "bak_bridge_nf_ipt" "$bridge_nf_ipt" @@ -1999,7 +1999,7 @@ stop() { source $APP_PATH/helper_smartdns.sh del rm -rf $GLOBAL_DNSMASQ_CONF rm -rf $GLOBAL_DNSMASQ_CONF_PATH - [ -z $(get_cache_var "ACL_default_dns_port") ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 bak_bridge_nf_ipt=$(get_cache_var "bak_bridge_nf_ipt") [ -n "${bak_bridge_nf_ipt}" ] && sysctl -w net.bridge.bridge-nf-call-iptables=${bak_bridge_nf_ipt} >/dev/null 2>&1 bak_bridge_nf_ip6t=$(get_cache_var "bak_bridge_nf_ip6t") diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/iptables.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/iptables.sh index 9f82a1fb6d..826297bf82 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/iptables.sh @@ -214,11 +214,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -n $(get_cache_var "ACL_${sid}_tcp_node") ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") - [ -n $(get_cache_var "ACL_${sid}_udp_node") ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") - [ -n $(get_cache_var "ACL_${sid}_tcp_port") ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") - [ -n $(get_cache_var "ACL_${sid}_udp_port") ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/nftables.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/nftables.sh index 6ba24c1ec6..27ff6638e2 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -274,11 +274,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -n $(get_cache_var "ACL_${sid}_tcp_node") ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") - [ -n $(get_cache_var "ACL_${sid}_udp_node") ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") - [ -n $(get_cache_var "ACL_${sid}_tcp_port") ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") - [ -n $(get_cache_var "ACL_${sid}_udp_port") ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index f76b368745..a7d403fa7a 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh @@ -82,7 +82,7 @@ test_auto_switch() { local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { - if [ -n $(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") ]; then + if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else #echolog "自动切换检测:未知错误" diff --git a/openwrt-passwall2/luci-app-passwall2/Makefile b/openwrt-passwall2/luci-app-passwall2/Makefile index 0f9cb501d6..29fe817222 100644 --- a/openwrt-passwall2/luci-app-passwall2/Makefile +++ b/openwrt-passwall2/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=24.12.16 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/iptables.sh b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/iptables.sh index 7dc3791683..b81d39288c 100755 --- a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/iptables.sh +++ b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/iptables.sh @@ -292,9 +292,9 @@ load_acl() { [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS node_remark=$(config_n_get $NODE remarks) - [ -n $(get_cache_var "ACL_${sid}_node") ] && node=$(get_cache_var "ACL_${sid}_node") - [ -n $(get_cache_var "ACL_${sid}_redir_port") ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node") + [ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") [ "$node" = "default" ] && dns_redirect_port=${DNS_REDIRECT_PORT} [ -n "$node" ] && [ "$node" != "default" ] && node_remark=$(config_n_get $node remarks) @@ -806,8 +806,6 @@ add_firewall_rule() { ip -6 rule add fwmark 1 table 100 ip -6 route add local ::/0 dev lo table 100 - filter_direct_node_list - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { local ipt_tmp=$ipt_n [ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m @@ -935,6 +933,8 @@ add_firewall_rule() { # 加载ACLS load_acl + filter_direct_node_list + echolog "防火墙规则加载完成!" } diff --git a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/nftables.sh b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/nftables.sh index c14c09f960..9473ee1e61 100755 --- a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/nftables.sh +++ b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/nftables.sh @@ -347,9 +347,9 @@ load_acl() { [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS node_remark=$(config_n_get $NODE remarks) - [ -n $(get_cache_var "ACL_${sid}_node") ] && node=$(get_cache_var "ACL_${sid}_node") - [ -n $(get_cache_var "ACL_${sid}_redir_port") ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node") + [ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") [ "$node" = "default" ] && dns_redirect_port=${DNS_REDIRECT_PORT} [ -n "$node" ] && [ "$node" != "default" ] && node_remark=$(config_n_get $node remarks) @@ -862,8 +862,6 @@ add_firewall_rule() { ip -6 route add local ::/0 dev lo table 100 } - filter_direct_node_list - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { TCP_LOCALHOST_PROXY=$LOCALHOST_PROXY UDP_LOCALHOST_PROXY=$LOCALHOST_PROXY @@ -985,6 +983,8 @@ add_firewall_rule() { # 加载ACLS load_acl + filter_direct_node_list + echolog "防火墙规则加载完成!" } diff --git a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh index ee4e88d8ad..651a473494 100755 --- a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh +++ b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh @@ -78,7 +78,7 @@ test_auto_switch() { local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { - if [ -n $(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") ]; then + if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else #echolog "自动切换检测:未知错误" diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index b41ce7acb7..f0d0362a3f 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -1469,9 +1469,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", diff --git a/sing-box/.github/workflows/build.yml b/sing-box/.github/workflows/build.yml index 8a4d3ec8bf..c37179ee6d 100644 --- a/sing-box/.github/workflows/build.yml +++ b/sing-box/.github/workflows/build.yml @@ -393,7 +393,7 @@ jobs: - name: Setup Xcode stable if: matrix.if && github.ref == 'refs/heads/main-next' run: |- - sudo xcode-select -s /Applications/Xcode_16.1.app + sudo xcode-select -s /Applications/Xcode_16.2.app - name: Setup Xcode beta if: matrix.if && github.ref == 'refs/heads/dev-next' run: |- @@ -492,7 +492,7 @@ jobs: -authenticationKeyID $ASC_KEY_ID \ -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID - name: Publish to TestFlight - if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch' + if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch' && github.ref =='refs/heads/dev-next' run: |- go run -v ./cmd/internal/app_store_connect publish_testflight ${{ matrix.platform }} - name: Build image diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/100.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/100.png deleted file mode 100644 index 87b49a299b..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/100.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/114.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/114.png deleted file mode 100644 index a89cecfeff..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/114.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/120.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/120.png deleted file mode 100644 index 08eb7d9869..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/120.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/144.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/144.png deleted file mode 100644 index 48a3e7512d..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/144.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/152.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/152.png deleted file mode 100644 index 00a9960b16..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/152.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/167.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/167.png deleted file mode 100644 index 713f83f36d..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/167.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/180.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/180.png deleted file mode 100644 index 42819bb471..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/180.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/20.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/20.png deleted file mode 100644 index eb62ba3371..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/20.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/29.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/29.png deleted file mode 100644 index 44d1f93c92..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/29.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/40.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/40.png deleted file mode 100644 index 9f2320e9c9..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/40.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/50.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/50.png deleted file mode 100644 index f6871cedbf..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/50.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/57.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/57.png deleted file mode 100644 index 7942d4681b..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/57.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/58.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/58.png deleted file mode 100644 index 8e5cb59958..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/58.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/60.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/60.png deleted file mode 100644 index 5951cae25c..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/60.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/72.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/72.png deleted file mode 100644 index 6b405eba5d..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/72.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/76.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/76.png deleted file mode 100644 index 9166aa451d..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/76.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/80.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/80.png deleted file mode 100644 index f4c0c93ed7..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/80.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/87.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/87.png deleted file mode 100644 index 3c1f73d5ff..0000000000 Binary files a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/87.png and /dev/null differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png new file mode 100644 index 0000000000..0d8bd94cc5 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png new file mode 100644 index 0000000000..0d8bd94cc5 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png new file mode 100644 index 0000000000..45aa3269a3 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png new file mode 100644 index 0000000000..63d4ebcbce Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png new file mode 100644 index 0000000000..707423b08e Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png new file mode 100644 index 0000000000..15d736a5a7 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png new file mode 100644 index 0000000000..15d736a5a7 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png new file mode 100644 index 0000000000..d8f1c43681 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png new file mode 100644 index 0000000000..707423b08e Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png new file mode 100644 index 0000000000..fb7a15fec4 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png new file mode 100644 index 0000000000..fb7a15fec4 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png new file mode 100644 index 0000000000..043732a6fd Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png new file mode 100644 index 0000000000..0d8bd94cc5 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png new file mode 100644 index 0000000000..043732a6fd Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png new file mode 100644 index 0000000000..007d7327c2 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png new file mode 100644 index 0000000000..dd7fd29635 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png new file mode 100644 index 0000000000..b256d5e0a7 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png new file mode 100644 index 0000000000..6b04023e5b Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png new file mode 100644 index 0000000000..b1d5c769c6 Binary files /dev/null and b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png differ diff --git a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/Contents.json b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/Contents.json index 799689a51b..5511b32063 100644 --- a/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/sing-box/clients/apple/SFI/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,151 +1,145 @@ { "images" : [ { - "filename" : "40.png", + "filename" : "AppIcon-20@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { - "filename" : "60.png", + "filename" : "AppIcon-20@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { - "filename" : "29.png", + "filename" : "AppIcon-29.png", "idiom" : "iphone", "scale" : "1x", "size" : "29x29" }, { - "filename" : "58.png", + "filename" : "AppIcon-29@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { - "filename" : "87.png", + "filename" : "AppIcon-29@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { - "filename" : "80.png", + "filename" : "AppIcon-40@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { - "filename" : "120.png", + "filename" : "AppIcon-40@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { - "filename" : "57.png", "idiom" : "iphone", "scale" : "1x", "size" : "57x57" }, { - "filename" : "114.png", "idiom" : "iphone", "scale" : "2x", "size" : "57x57" }, { - "filename" : "120.png", + "filename" : "AppIcon-60@2x~car.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { - "filename" : "180.png", + "filename" : "AppIcon-60@3x~car.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { - "filename" : "20.png", + "filename" : "AppIcon-20~ipad.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { - "filename" : "40.png", + "filename" : "AppIcon-20@2x~ipad.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { - "filename" : "29.png", + "filename" : "AppIcon-29~ipad.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { - "filename" : "58.png", + "filename" : "AppIcon-29@2x~ipad.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { - "filename" : "40.png", + "filename" : "AppIcon-40~ipad.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { - "filename" : "80.png", + "filename" : "AppIcon-40@2x~ipad.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { - "filename" : "50.png", "idiom" : "ipad", "scale" : "1x", "size" : "50x50" }, { - "filename" : "100.png", "idiom" : "ipad", "scale" : "2x", "size" : "50x50" }, { - "filename" : "72.png", "idiom" : "ipad", "scale" : "1x", "size" : "72x72" }, { - "filename" : "144.png", "idiom" : "ipad", "scale" : "2x", "size" : "72x72" }, { - "filename" : "76.png", + "filename" : "AppIcon~ipad.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { - "filename" : "152.png", + "filename" : "AppIcon@2x~ipad.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { - "filename" : "167.png", + "filename" : "AppIcon-83.5@2x~ipad.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { - "filename" : "1024.png", + "filename" : "AppIcon~ios-marketing.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" diff --git a/sing-box/cmd/internal/app_store_connect/client.go b/sing-box/cmd/internal/app_store_connect/client.go deleted file mode 100644 index bdc7607633..0000000000 --- a/sing-box/cmd/internal/app_store_connect/client.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "context" - "fmt" - _ "unsafe" - - "github.com/cidertool/asc-go/asc" -) - -type Client struct { - *asc.Client -} - -func (c *Client) UpdateBuildForAppStoreVersion(ctx context.Context, id string, buildID *string) (*asc.Response, error) { - linkage := newRelationshipDeclaration(buildID, "builds") - url := fmt.Sprintf("appStoreVersions/%s/relationships/build", id) - return c.patch(ctx, url, newRequestBody(linkage), nil) -} - -func newRelationshipDeclaration(id *string, relationshipType string) *asc.RelationshipData { - if id == nil { - return nil - } - - return &asc.RelationshipData{ - ID: *id, - Type: relationshipType, - } -} diff --git a/sing-box/cmd/internal/app_store_connect/client_linkname.go b/sing-box/cmd/internal/app_store_connect/client_linkname.go deleted file mode 100644 index 7ccfc4fe41..0000000000 --- a/sing-box/cmd/internal/app_store_connect/client_linkname.go +++ /dev/null @@ -1,140 +0,0 @@ -package main - -import ( - "context" - "net/http" - "net/url" - "reflect" - _ "unsafe" - - "github.com/cidertool/asc-go/asc" - "github.com/google/go-querystring/query" -) - -func (c *Client) newRequest(ctx context.Context, method string, path string, body *requestBody, options ...requestOption) (*http.Request, error) { - return clientNewRequest(c.Client, ctx, method, path, body, options...) -} - -//go:linkname clientNewRequest github.com/cidertool/asc-go/asc.(*Client).newRequest -func clientNewRequest(c *asc.Client, ctx context.Context, method string, path string, body *requestBody, options ...requestOption) (*http.Request, error) - -func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) (*asc.Response, error) { - return clientDo(c.Client, ctx, req, v) -} - -//go:linkname clientDo github.com/cidertool/asc-go/asc.(*Client).do -func clientDo(c *asc.Client, ctx context.Context, req *http.Request, v interface{}) (*asc.Response, error) - -// get sends a GET request to the API as configured. -func (c *Client) get(ctx context.Context, url string, query interface{}, v interface{}, options ...requestOption) (*asc.Response, error) { - var err error - if query != nil { - url, err = appendingQueryOptions(url, query) - if err != nil { - return nil, err - } - } - - req, err := c.newRequest(ctx, "GET", url, nil, options...) - if err != nil { - return nil, err - } - - resp, err := c.do(ctx, req, v) - if err != nil { - return resp, err - } - - return resp, err -} - -// post sends a POST request to the API as configured. -func (c *Client) post(ctx context.Context, url string, body *requestBody, v interface{}) (*asc.Response, error) { - req, err := c.newRequest(ctx, "POST", url, body, withContentType("application/json")) - if err != nil { - return nil, err - } - - resp, err := c.do(ctx, req, v) - if err != nil { - return resp, err - } - - return resp, err -} - -// patch sends a PATCH request to the API as configured. -func (c *Client) patch(ctx context.Context, url string, body *requestBody, v interface{}) (*asc.Response, error) { - req, err := c.newRequest(ctx, "PATCH", url, body, withContentType("application/json")) - if err != nil { - return nil, err - } - - resp, err := c.do(ctx, req, v) - if err != nil { - return resp, err - } - - return resp, err -} - -// delete sends a DELETE request to the API as configured. -func (c *Client) delete(ctx context.Context, url string, body *requestBody) (*asc.Response, error) { - req, err := c.newRequest(ctx, "DELETE", url, body, withContentType("application/json")) - if err != nil { - return nil, err - } - - return c.do(ctx, req, nil) -} - -// request is a common structure for a request body sent to the API. -type requestBody struct { - Data interface{} `json:"data"` - Included interface{} `json:"included,omitempty"` -} - -func newRequestBody(data interface{}) *requestBody { - return newRequestBodyWithIncluded(data, nil) -} - -func newRequestBodyWithIncluded(data interface{}, included interface{}) *requestBody { - return &requestBody{Data: data, Included: included} -} - -type requestOption func(*http.Request) - -func withAccept(typ string) requestOption { - return func(req *http.Request) { - req.Header.Set("Accept", typ) - } -} - -func withContentType(typ string) requestOption { - return func(req *http.Request) { - req.Header.Set("Content-Type", typ) - } -} - -// AddOptions adds the parameters in opt as URL query parameters to s. opt -// must be a struct whose fields may contain "url" tags. -func appendingQueryOptions(s string, opt interface{}) (string, error) { - v := reflect.ValueOf(opt) - if v.Kind() == reflect.Ptr && v.IsNil() { - return s, nil - } - - u, err := url.Parse(s) - if err != nil { - return s, err - } - - qs, err := query.Values(opt) - if err != nil { - return s, err - } - - u.RawQuery = qs.Encode() - - return u.String(), nil -} diff --git a/sing-box/cmd/internal/app_store_connect/main.go b/sing-box/cmd/internal/app_store_connect/main.go index b6e893193c..1fe347424b 100644 --- a/sing-box/cmd/internal/app_store_connect/main.go +++ b/sing-box/cmd/internal/app_store_connect/main.go @@ -7,13 +7,12 @@ import ( "strconv" "time" + "github.com/sagernet/asc-go/asc" "github.com/sagernet/sing-box/cmd/internal/build_shared" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" - - "github.com/cidertool/asc-go/asc" ) func main() { @@ -54,7 +53,7 @@ const ( groupID = "5c5f3b78-b7a0-40c0-bcad-e6ef87bbefda" ) -func createClient(expireDuration time.Duration) *Client { +func createClient(expireDuration time.Duration) *asc.Client { privateKey, err := os.ReadFile(os.Getenv("ASC_KEY_PATH")) if err != nil { log.Fatal(err) @@ -63,7 +62,7 @@ func createClient(expireDuration time.Duration) *Client { if err != nil { log.Fatal(err) } - return &Client{asc.NewClient(tokenConfig.Client())} + return asc.NewClient(tokenConfig.Client()) } func fetchMacOSVersion(ctx context.Context) error { @@ -218,33 +217,39 @@ func cancelAppStore(ctx context.Context, platform string) error { return err } client := createClient(time.Minute) - log.Info(platform, " list versions") - versions, _, err := client.Apps.ListAppStoreVersionsForApp(ctx, appID, &asc.ListAppStoreVersionsQuery{ - FilterPlatform: []string{string(platform)}, - }) - if err != nil { - return err - } - version := common.Find(versions.Data, func(it asc.AppStoreVersion) bool { - return *it.Attributes.VersionString == tag - }) - if version.ID == "" { + for { + log.Info(platform, " list versions") + versions, response, err := client.Apps.ListAppStoreVersionsForApp(ctx, appID, &asc.ListAppStoreVersionsQuery{ + FilterPlatform: []string{string(platform)}, + }) + if isRetryable(response) { + continue + } else if err != nil { + return err + } + version := common.Find(versions.Data, func(it asc.AppStoreVersion) bool { + return *it.Attributes.VersionString == tag + }) + if version.ID == "" { + return nil + } + log.Info(platform, " ", tag, " get submission") + submission, response, err := client.Submission.GetAppStoreVersionSubmissionForAppStoreVersion(ctx, version.ID, nil) + if response != nil && response.StatusCode == http.StatusNotFound { + return nil + } + if isRetryable(response) { + continue + } else if err != nil { + return err + } + log.Info(platform, " ", tag, " delete submission") + _, err = client.Submission.DeleteSubmission(ctx, submission.Data.ID) + if err != nil { + return err + } return nil } - log.Info(string(platform), " ", tag, " get submission") - submission, response, err := client.Submission.GetAppStoreVersionSubmissionForAppStoreVersion(ctx, version.ID, nil) - if response != nil && response.StatusCode == http.StatusNotFound { - return nil - } - if err != nil { - return err - } - log.Info(platform, " ", tag, " delete submission") - _, err = client.Submission.DeleteSubmission(ctx, submission.Data.ID) - if err != nil { - return err - } - return nil } func prepareAppStore(ctx context.Context) error { @@ -321,7 +326,7 @@ func prepareAppStore(ctx context.Context) error { log.Fatal(string(platform), " ", tag, " unknown state ", string(*version.Attributes.AppStoreState)) } log.Info(string(platform), " ", tag, " update build") - response, err = client.UpdateBuildForAppStoreVersion(ctx, version.ID, buildID) + response, err = client.Apps.UpdateBuildForAppStoreVersion(ctx, version.ID, buildID) if err != nil { return err } @@ -428,3 +433,15 @@ func publishAppStore(ctx context.Context) error { } return nil } + +func isRetryable(response *asc.Response) bool { + if response == nil { + return false + } + switch response.StatusCode { + case http.StatusInternalServerError, http.StatusUnprocessableEntity: + return true + default: + return false + } +} diff --git a/sing-box/docs/changelog.md b/sing-box/docs/changelog.md index 0e5207f149..21caf556f8 100644 --- a/sing-box/docs/changelog.md +++ b/sing-box/docs/changelog.md @@ -4,6 +4,7 @@ icon: material/alert-decagram #### 1.11.0-beta.12 +* Add `rule-set merge` command * Fixes and improvements ### 1.10.4 diff --git a/sing-box/go.mod b/sing-box/go.mod index 9d080358ee..936e995027 100644 --- a/sing-box/go.mod +++ b/sing-box/go.mod @@ -4,13 +4,11 @@ go 1.20 require ( github.com/caddyserver/certmagic v0.20.0 - github.com/cidertool/asc-go v0.5.1 github.com/cloudflare/circl v1.3.7 github.com/cretz/bine v0.2.0 github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.3.0 - github.com/google/go-querystring v1.0.0 github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 github.com/libdns/alidns v1.0.3 github.com/libdns/cloudflare v0.1.1 @@ -19,6 +17,7 @@ require ( github.com/mholt/acmez v1.2.0 github.com/miekg/dns v1.1.62 github.com/oschwald/maxminddb-golang v1.12.0 + github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 github.com/sagernet/cors v1.2.1 @@ -60,7 +59,7 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.6 // indirect - github.com/cenkalti/backoff/v4 v4.1.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -70,6 +69,7 @@ require ( github.com/gobwas/pool v0.2.1 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/sing-box/go.sum b/sing-box/go.sum index 3a04deb5b3..13c1bb1ae1 100644 --- a/sing-box/go.sum +++ b/sing-box/go.sum @@ -4,10 +4,8 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= -github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cidertool/asc-go v0.5.1 h1:KYki2Y8IXJMOkOXy9y1sdr8tz6IdW2ti770K4bk7WY0= -github.com/cidertool/asc-go v0.5.1/go.mod h1:LyrZWU7DeCh8cWrFwXcpl93ixRUUL2aEZV7/0h07FxA= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -38,10 +36,11 @@ github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= @@ -97,6 +96,8 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1 github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 h1:qi+ijeREa0yfAaO+NOcZ81gv4uzOfALUIdhkiIFvmG4= +github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY= diff --git a/small/luci-app-mihomo/Makefile b/small/luci-app-mihomo/Makefile index 04db9128a3..f4a93255d6 100644 --- a/small/luci-app-mihomo/Makefile +++ b/small/luci-app-mihomo/Makefile @@ -1,6 +1,6 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=1.13.3 +PKG_VERSION:=1.14.0 LUCI_TITLE:=LuCI Support for mihomo LUCI_DEPENDS:=+luci-base +mihomo diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js new file mode 100644 index 0000000000..59b2683f38 --- /dev/null +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js @@ -0,0 +1,148 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require poll'; +'require tools.mihomo as mihomo'; + +function renderStatus(running) { + return updateStatus(E('input', { id: 'core_status', style: 'border: unset; font-style: italic; font-weight: bold;', readonly: '' }), running); +} + +function updateStatus(element, running) { + if (element) { + element.style.color = running ? 'green' : 'red'; + element.value = running ? _('Running') : _('Not Running'); + } + return element; +} + +return view.extend({ + load: function () { + return Promise.all([ + uci.load('mihomo'), + mihomo.appVersion(), + mihomo.coreVersion(), + mihomo.status(), + mihomo.listProfiles() + ]); + }, + render: function (data) { + const subscriptions = uci.sections('mihomo', 'subscription'); + const appVersion = data[1]; + const coreVersion = data[2]; + const running = data[3]; + const profiles = data[4]; + + let m, s, o; + + m = new form.Map('mihomo', _('MihomoTProxy'), `${_('Transparent Proxy with Mihomo on OpenWrt.')} ${_('How To Use')}`); + + s = m.section(form.NamedSection, 'status', 'status', _('Status')); + + o = s.option(form.Value, '_app_version', _('App Version')); + o.readonly = true; + o.load = function () { + return appVersion.trim(); + }; + o.write = function () { }; + + o = s.option(form.Value, '_core_version', _('Core Version')); + o.readonly = true; + o.load = function () { + return coreVersion.trim(); + }; + o.write = function () { }; + + o = s.option(form.DummyValue, '_core_status', _('Core Status')); + o.cfgvalue = function () { + return renderStatus(running); + }; + poll.add(function () { + return L.resolveDefault(mihomo.status()).then(function (running) { + updateStatus(document.getElementById('core_status'), running); + }); + }); + + o = s.option(form.Button, 'reload', '-'); + o.inputstyle = 'action'; + o.inputtitle = _('Reload Service'); + o.onclick = function () { + return mihomo.reload(); + }; + + o = s.option(form.Button, 'restart', '-'); + o.inputstyle = 'negative'; + o.inputtitle = _('Restart Service'); + o.onclick = function () { + return mihomo.restart(); + }; + + o = s.option(form.Button, 'update_dashboard', '-'); + o.inputstyle = 'positive'; + o.inputtitle = _('Update Dashboard'); + o.onclick = function () { + return mihomo.callMihomoAPI('POST', '/upgrade/ui'); + }; + + o = s.option(form.Button, 'open_dashboard', '-'); + o.inputtitle = _('Open Dashboard'); + o.onclick = function () { + return mihomo.openDashboard(); + }; + + s = m.section(form.NamedSection, 'config', 'config', _('App Config')); + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.rmempty = false; + + o = s.option(form.ListValue, 'profile', _('Choose Profile')); + o.optional = true; + + for (const profile of profiles) { + o.value('file:' + profile.name, _('File:') + profile.name); + }; + + for (const subscription of subscriptions) { + o.value('subscription:' + subscription['.name'], _('Subscription:') + subscription.name); + }; + + o = s.option(form.Value, 'start_delay', _('Start Delay')); + o.datatype = 'uinteger'; + o.placeholder = '0'; + + o = s.option(form.Flag, 'scheduled_restart', _('Scheduled Restart')); + o.rmempty = false; + + o = s.option(form.Value, 'cron_expression', _('Cron Expression')); + o.retain = true; + o.rmempty = false; + o.depends('scheduled_restart', '1'); + + o = s.option(form.Flag, 'test_profile', _('Test Profile')); + o.rmempty = false; + + o = s.option(form.Flag, 'fast_reload', _('Fast Reload')); + o.rmempty = false; + + s = m.section(form.NamedSection, 'config', 'config', _('Core Environment Variable Config')); + + o = s.option(form.Flag, 'disable_safe_path_check', _('Disable Safe Path Check')); + o.ucisection = 'env'; + o.rmempty = false; + + o = s.option(form.Flag, 'disable_loopback_detector', _('Disable Loopback Detector')); + o.ucisection = 'env'; + o.rmempty = false; + + o = s.option(form.Flag, 'disable_quic_go_gso', _('Disable GSO of quic-go')); + o.ucisection = 'env'; + o.rmempty = false; + + o = s.option(form.Flag, 'disable_quic_go_ecn', _('Disable ECN of quic-go')); + o.ucisection = 'env'; + o.rmempty = false; + + return m.render(); + } +}); diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js deleted file mode 100644 index 58b8493263..0000000000 --- a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js +++ /dev/null @@ -1,617 +0,0 @@ -'use strict'; -'require form'; -'require view'; -'require uci'; -'require fs'; -'require network'; -'require rpc'; -'require poll'; -'require tools.widgets as widgets'; -'require tools.mihomo as mihomo'; - -function renderStatus(running) { - return updateStatus(E('input', { id: 'core_status', style: 'border: unset; font-style: italic; font-weight: bold;', readonly: '' }), running); -} - -function updateStatus(element, running) { - if (element) { - element.style.color = running ? 'green' : 'red'; - element.value = running ? _('Running') : _('Not Running'); - } - return element; -} - -return view.extend({ - load: function () { - return Promise.all([ - uci.load('mihomo'), - mihomo.listProfiles(), - mihomo.appVersion(), - mihomo.coreVersion(), - mihomo.status(), - mihomo.getUsers(), - mihomo.getGroups(), - network.getHostHints(), - ]); - }, - render: function (data) { - const subscriptions = uci.sections('mihomo', 'subscription'); - const profiles = data[1]; - const appVersion = data[2]; - const coreVersion = data[3]; - const running = data[4]; - const users = data[5]; - const groups = data[6]; - const hosts = data[7].hosts; - - let m, s, o, so; - - m = new form.Map('mihomo', _('MihomoTProxy'), `${_('Transparent Proxy with Mihomo on OpenWrt.')} ${_('How To Use')}`); - - s = m.section(form.NamedSection, 'status', 'status', _('Status')); - - o = s.option(form.Value, '_app_version', _('App Version')); - o.readonly = true; - o.load = function () { - return appVersion.trim(); - }; - o.write = function () { }; - - o = s.option(form.Value, '_core_version', _('Core Version')); - o.readonly = true; - o.load = function () { - return coreVersion.trim(); - }; - o.write = function () { }; - - o = s.option(form.DummyValue, '_core_status', _('Core Status')); - o.cfgvalue = function () { - return renderStatus(running); - }; - poll.add(function () { - return L.resolveDefault(mihomo.status()).then(function (running) { - updateStatus(document.getElementById('core_status'), running); - }); - }); - - o = s.option(form.Button, 'reload', '-'); - o.inputstyle = 'action'; - o.inputtitle = _('Reload Service'); - o.onclick = function () { - return mihomo.reload(); - }; - - o = s.option(form.Button, 'restart', '-'); - o.inputstyle = 'negative'; - o.inputtitle = _('Restart Service'); - o.onclick = function () { - return mihomo.restart(); - }; - - o = s.option(form.Button, 'update_dashboard', '-'); - o.inputstyle = 'positive'; - o.inputtitle = _('Update Dashboard'); - o.onclick = function () { - return mihomo.callMihomoAPI('POST', '/upgrade/ui'); - }; - - o = s.option(form.Button, 'open_dashboard', '-'); - o.inputtitle = _('Open Dashboard'); - o.onclick = function () { - return mihomo.openDashboard(); - }; - - s = m.section(form.NamedSection, 'config', 'config', _('Basic Config')); - - s.tab('app', _('App Config')); - - o = s.taboption('app', form.Flag, 'enabled', _('Enable')); - o.rmempty = false; - - o = s.taboption('app', form.ListValue, 'profile', _('Choose Profile')); - o.optional = true; - - for (const profile of profiles) { - o.value('file:' + profile.name, _('File:') + profile.name); - }; - - for (const subscription of subscriptions) { - o.value('subscription:' + subscription['.name'], _('Subscription:') + subscription.name); - }; - - o = s.taboption('app', form.FileUpload, 'upload_profile', _('Upload Profile')); - o.root_directory = mihomo.profilesDir; - - o = s.taboption('app', form.Flag, 'mixin', _('Mixin')); - o.rmempty = false; - - s.tab('startup', _('Startup Config')); - - o = s.taboption('startup', form.Value, 'start_delay', _('Start Delay')); - o.datatype = 'uinteger'; - o.placeholder = '0'; - - o = s.taboption('startup', form.Flag, 'scheduled_restart', _('Scheduled Restart')); - o.rmempty = false; - - o = s.taboption('startup', form.Value, 'cron_expression', _('Cron Expression')); - o.retain = true; - o.rmempty = false; - o.depends('scheduled_restart', '1'); - - o = s.taboption('startup', form.Flag, 'test_profile', _('Test Profile')); - o.rmempty = false; - - o = s.taboption('startup', form.Flag, 'fast_reload', _('Fast Reload')); - o.rmempty = false; - - s.tab('core_env', _('Core Environment Variable Config')); - - o = s.taboption('core_env', form.Flag, 'disable_safe_path_check', _('Disable Safe Path Check')); - o.ucisection = 'env'; - o.rmempty = false; - - o = s.taboption('core_env', form.Flag, 'disable_loopback_detector', _('Disable Loopback Detector')); - o.ucisection = 'env'; - o.rmempty = false; - - o = s.taboption('core_env', form.Flag, 'disable_quic_go_gso', _('Disable GSO of quic-go')); - o.ucisection = 'env'; - o.rmempty = false; - - o = s.taboption('core_env', form.Flag, 'disable_quic_go_ecn', _('Disable ECN of quic-go')); - o.ucisection = 'env'; - o.rmempty = false; - - s = m.section(form.NamedSection, 'proxy', 'proxy', _('Proxy Config')); - - s.tab('transparent_proxy', _('Transparent Proxy')); - - o = s.taboption('transparent_proxy', form.Flag, 'transparent_proxy', _('Enable')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.ListValue, 'tcp_transparent_proxy_mode', _('TCP Proxy Mode')); - o.value('redirect', _('Redirect Mode')); - o.value('tproxy', _('TPROXY Mode')); - o.value('tun', _('TUN Mode')); - - o = s.taboption('transparent_proxy', form.ListValue, 'udp_transparent_proxy_mode', _('UDP Proxy Mode')); - o.value('tproxy', _('TPROXY Mode')); - o.value('tun', _('TUN Mode')); - - o = s.taboption('transparent_proxy', form.Flag, 'ipv4_dns_hijack', _('IPv4 DNS Hijack')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.Flag, 'ipv6_dns_hijack', _('IPv6 DNS Hijack')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.Flag, 'ipv4_proxy', _('IPv4 Proxy')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.Flag, 'ipv6_proxy', _('IPv6 Proxy')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.Flag, 'router_proxy', _('Router Proxy')); - o.rmempty = false; - - o = s.taboption('transparent_proxy', form.Flag, 'lan_proxy', _('Lan Proxy')); - o.rmempty = false; - - s.tab('access_control', _('Access Control')); - - o = s.taboption('access_control', form.ListValue, 'access_control_mode', _('Mode')); - o.value('all', _('All Mode')); - o.value('allow', _('Allow Mode')); - o.value('block', _('Block Mode')); - - o = s.taboption('access_control', form.DynamicList, 'acl_ip', 'IP'); - o.datatype = 'ipmask4'; - o.retain = true; - o.depends('access_control_mode', 'allow'); - o.depends('access_control_mode', 'block'); - - for (const mac in hosts) { - const host = hosts[mac]; - for (const ip of host.ipaddrs) { - const hint = host.name || mac; - o.value(ip, hint ? '%s (%s)'.format(ip, hint) : ip); - }; - }; - - o = s.taboption('access_control', form.DynamicList, 'acl_ip6', 'IP6'); - o.datatype = 'ipmask6'; - o.retain = true; - o.depends('access_control_mode', 'allow'); - o.depends('access_control_mode', 'block'); - - for (const mac in hosts) { - const host = hosts[mac]; - for (const ip of host.ip6addrs) { - const hint = host.name || mac; - o.value(ip, hint ? '%s (%s)'.format(ip, hint) : ip); - }; - }; - - o = s.taboption('access_control', form.DynamicList, 'acl_mac', 'MAC'); - o.datatype = 'macaddr'; - o.retain = true; - o.depends('access_control_mode', 'allow'); - o.depends('access_control_mode', 'block'); - - for (const mac in hosts) { - const host = hosts[mac]; - const hint = host.name || host.ipaddrs[0]; - o.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); - }; - - o = s.taboption('access_control', widgets.NetworkSelect, 'acl_interface', _('Interface')); - o.multiple = true; - o.optional = true; - o.retain = true; - o.depends('access_control_mode', 'allow'); - o.depends('access_control_mode', 'block'); - - s.tab('bypass', _('Bypass')); - - o = s.taboption('bypass', form.MultiValue, 'bypass_user', _('Bypass User')); - o.create = true; - - for (const user of users) { - o.value(user); - }; - - o = s.taboption('bypass', form.MultiValue, 'bypass_group', _('Bypass Group')); - o.create = true; - - for (const group of groups) { - o.value(group); - }; - - o = s.taboption('bypass', form.Flag, 'bypass_china_mainland_ip', _('Bypass China Mainland IP')); - o.rmempty = false; - - o = s.taboption('bypass', form.Value, 'proxy_tcp_dport', _('Destination TCP Port to Proxy')); - o.rmempty = false; - o.value('0-65535', _('All Port')); - o.value('21 22 80 110 143 194 443 465 853 993 995 8080 8443', _('Commonly Used Port')); - - o = s.taboption('bypass', form.Value, 'proxy_udp_dport', _('Destination UDP Port to Proxy')); - o.rmempty = false; - o.value('0-65535', _('All Port')); - o.value('123 443 8443', _('Commonly Used Port')); - - s = m.section(form.GridSection, 'subscription', _('Subscription Config')); - s.addremove = true; - s.anonymous = true; - s.sortable = true; - s.modaltitle = _('Edit Subscription'); - - o = s.option(form.Value, 'name', _('Subscription Name')); - o.rmempty = false; - - o = s.option(form.Value, 'used', _('Used')); - o.modalonly = false; - o.optional = true; - o.readonly = true; - - o = s.option(form.Value, 'total', _('Total')); - o.modalonly = false; - o.optional = true; - o.readonly = true; - - o = s.option(form.Value, 'expire', _('Expire At')); - o.modalonly = false; - o.optional = true; - o.readonly = true; - - o = s.option(form.Value, 'update', _('Update At')); - o.modalonly = false; - o.optional = true; - o.readonly = true; - - o = s.option(form.Button, 'update_subscription'); - o.editable = true; - o.inputstyle = 'positive'; - o.inputtitle = _('Update'); - o.modalonly = false; - o.onclick = function (_, section_id) { - return mihomo.updateSubscription(section_id); - }; - - o = s.option(form.Value, 'url', _('Subscription Url')); - o.modalonly = true; - o.rmempty = false; - - o = s.option(form.Value, 'user_agent', _('User Agent')); - o.default = 'clash'; - o.modalonly = true; - o.rmempty = false; - o.value('mihomo'); - o.value('clash.meta'); - o.value('clash'); - - o = s.option(form.ListValue, 'prefer', _('Prefer')); - o.default = 'remote'; - o.modalonly = true; - o.value('remote', _('Remote')); - o.value('local', _('Local')); - - s = m.section(form.NamedSection, 'mixin', 'mixin', _('Mixin Config')); - - s.tab('general', _('General Config')); - - o = s.taboption('general', form.ListValue, 'log_level', '*' + ' ' + _('Log Level')); - o.value('silent'); - o.value('error'); - o.value('warning'); - o.value('info'); - o.value('debug'); - - o = s.taboption('general', form.ListValue, 'mode', _('Mode')); - o.value('global', _('Global Mode')); - o.value('rule', _('Rule Mode')); - o.value('direct', _('Direct Mode')); - - o = s.taboption('general', form.ListValue, 'match_process', _('Match Process')); - o.value('strict', _('Auto')); - o.value('always', _('Enable')); - o.value('off', _('Disable')); - - o = s.taboption('general', widgets.NetworkSelect, 'outbound_interface', '*' + ' ' + _('Outbound Interface')); - o.optional = true; - - o = s.taboption('general', form.Flag, 'ipv6', '*' + ' ' + _('IPv6')); - o.rmempty = false; - - o = s.taboption('general', form.Value, 'tcp_keep_alive_idle', _('TCP Keep Alive Idle')); - o.datatype = 'uinteger'; - o.placeholder = '600'; - - o = s.taboption('general', form.Value, 'tcp_keep_alive_interval', _('TCP Keep Alive Interval')); - o.datatype = 'uinteger'; - o.placeholder = '15'; - - s.tab('external_control', _('External Control Config')); - - o = s.taboption('external_control', form.Value, 'ui_name', '*' + ' ' + _('UI Name')); - o.rmempty = false; - - o = s.taboption('external_control', form.Value, 'ui_url', '*' + ' ' + _('UI Url')); - o.rmempty = false; - o.value('https://ghp.ci/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip', 'MetaCubeXD'); - o.value('https://ghp.ci/https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD'); - o.value('https://ghp.ci/https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord'); - o.value('https://ghp.ci/https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip', 'Zashboard'); - - o = s.taboption('external_control', form.Value, 'api_port', '*' + ' ' + _('API Port')); - o.datatype = 'port'; - o.placeholder = '9090'; - - o = s.taboption('external_control', form.Value, 'api_secret', '*' + ' ' + _('API Secret')); - o.password = true; - o.rmempty = false; - - o = s.taboption('external_control', form.Flag, 'selection_cache', _('Save Proxy Selection')); - o.rmempty = false; - - s.tab('inbound', _('Inbound Config')); - - o = s.taboption('inbound', form.Flag, 'allow_lan', '*' + ' ' + _('Allow Lan')); - o.rmempty = false; - - o = s.taboption('inbound', form.Value, 'http_port', '*' + ' ' + _('HTTP Port')); - o.datatype = 'port'; - o.placeholder = '8080'; - - o = s.taboption('inbound', form.Value, 'socks_port', '*' + ' ' + _('SOCKS Port')); - o.datatype = 'port'; - o.placeholder = '1080'; - - o = s.taboption('inbound', form.Value, 'mixed_port', '*' + ' ' + _('Mixed Port')); - o.datatype = 'port'; - o.placeholder = '7890'; - - o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port')); - o.datatype = 'port'; - o.placeholder = '7891'; - - o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port')); - o.datatype = 'port'; - o.placeholder = '7892'; - - o = s.taboption('inbound', form.Flag, 'authentication', '*' + ' ' + _('Overwrite Authentication')); - o.rmempty = false; - - o = s.taboption('inbound', form.SectionValue, '_authentications', form.TableSection, 'authentication', _('Edit Authentications')); - o.retain = true; - o.depends('authentication', '1'); - - o.subsection.addremove = true; - o.subsection.anonymous = true; - o.subsection.sortable = true; - - so = o.subsection.option(form.Flag, 'enabled', _('Enable')); - so.rmempty = false; - - so = o.subsection.option(form.Value, 'username', _('Username')); - so.rmempty = false; - - so = o.subsection.option(form.Value, 'password', _('Password')); - so.password = true; - so.rmempty = false; - - s.tab('tun', _('TUN Config')); - - o = s.taboption('tun', form.ListValue, 'tun_stack', '*' + ' ' + _('Stack')); - o.value('system', 'System'); - o.value('gvisor', 'gVisor'); - o.value('mixed', 'Mixed'); - - o = s.taboption('tun', form.Value, 'tun_mtu', '*' + ' ' + _('MTU')); - o.datatype = 'uinteger'; - o.placeholder = '9000'; - - o = s.taboption('tun', form.Flag, 'tun_gso', '*' + ' ' + _('GSO')); - o.rmempty = false; - - o = s.taboption('tun', form.Value, 'tun_gso_max_size', '*' + ' ' + _('GSO Max Size')); - o.datatype = 'uinteger'; - o.placeholder = '65536'; - o.retain = true; - o.depends('tun_gso', '1'); - - o = s.taboption('tun', form.Flag, 'tun_endpoint_independent_nat', '*' + ' ' + _('Endpoint Independent NAT')); - o.rmempty = false; - - s.tab('dns', _('DNS Config')); - - o = s.taboption('dns', form.Value, 'dns_port', '*' + ' ' + _('DNS Port')); - o.datatype = 'port'; - o.placeholder = '1053'; - - o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode')); - o.value('normal', 'Normal'); - o.value('fake-ip', 'Fake-IP'); - o.value('redir-host', 'Redir-Host'); - - o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range')); - o.datatype = 'cidr4'; - o.placeholder = '198.18.0.1/16'; - o.retain = true; - o.depends('dns_mode', 'fake-ip'); - - o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter')); - o.retain = true; - o.rmempty = false; - o.depends('dns_mode', 'fake-ip'); - - o = s.taboption('dns', form.DynamicList, 'fake_ip_filters', _('Edit Fake-IP Filters')); - o.retain = true; - o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); - - o = s.taboption('dns', form.ListValue, 'fake_ip_filter_mode', _('Fake-IP Filter Mode')); - o.retain = true; - o.value('blacklist', _('Block Mode')); - o.value('whitelist', _('Allow Mode')); - o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); - - o = s.taboption('dns', form.Flag, 'fake_ip_cache', _('Fake-IP Cache')); - o.retain = true; - o.rmempty = false; - o.depends('dns_mode', 'fake-ip'); - - o = s.taboption('dns', form.Flag, 'dns_respect_rules', _('Respect Rules')); - o.rmempty = false; - - o = s.taboption('dns', form.Flag, 'dns_doh_prefer_http3', _('DoH Prefer HTTP/3')); - o.rmempty = false; - - o = s.taboption('dns', form.Flag, 'dns_ipv6', _('IPv6')); - o.rmempty = false; - - o = s.taboption('dns', form.Flag, 'dns_system_hosts', _('Use System Hosts')); - o.rmempty = false; - - o = s.taboption('dns', form.Flag, 'dns_hosts', _('Use Hosts')); - o.rmempty = false; - - o = s.taboption('dns', form.Flag, 'hosts', _('Overwrite Hosts')); - o.rmempty = false; - - o = s.taboption('dns', form.SectionValue, '_hosts', form.TableSection, 'host', _('Edit Hosts')); - o.retain = true; - o.depends('hosts', '1'); - - o.subsection.addremove = true; - o.subsection.anonymous = true; - o.subsection.sortable = true; - - so = o.subsection.option(form.Flag, 'enabled', _('Enable')); - so.rmempty = false; - - so = o.subsection.option(form.Value, 'domain_name', _('Domain Name')); - so.rmempty = false; - - so = o.subsection.option(form.DynamicList, 'ip', _('IP')); - - o = s.taboption('dns', form.Flag, 'dns_nameserver', _('Overwrite Nameserver')); - o.rmempty = false; - - o = s.taboption('dns', form.SectionValue, '_dns_nameserver', form.TableSection, 'nameserver', _('Edit Nameservers')); - o.retain = true; - o.depends('dns_nameserver', '1'); - - o.subsection.addremove = true; - o.subsection.anonymous = true; - o.subsection.sortable = true; - - so = o.subsection.option(form.Flag, 'enabled', _('Enable')); - so.rmempty = false; - - so = o.subsection.option(form.ListValue, 'type', _('Type')); - so.value('default-nameserver'); - so.value('proxy-server-nameserver'); - so.value('direct-nameserver'); - so.value('nameserver'); - so.value('fallback'); - - so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver')); - - o = s.taboption('dns', form.Flag, 'dns_nameserver_policy', _('Overwrite Nameserver Policy')); - o.rmempty = false; - - o = s.taboption('dns', form.SectionValue, '_dns_nameserver_policies', form.TableSection, 'nameserver_policy', _('Edit Nameserver Policies')); - o.retain = true; - o.depends('dns_nameserver_policy', '1'); - - o.subsection.addremove = true; - o.subsection.anonymous = true; - o.subsection.sortable = true; - - so = o.subsection.option(form.Flag, 'enabled', _('Enable')); - so.rmempty = false; - - so = o.subsection.option(form.Value, 'matcher', _('Matcher')); - so.rmempty = false; - - so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver')); - - s.tab('geox', _('GeoX Config')); - - o = s.taboption('geox', form.ListValue, 'geoip_format', _('GeoIP Format')); - o.value('dat', 'DAT'); - o.value('mmdb', 'MMDB'); - - o = s.taboption('geox', form.ListValue, 'geodata_loader', _('GeoData Loader')); - o.value('standard', _('Standard Loader')); - o.value('memconservative', _('Memory Conservative Loader')); - - o = s.taboption('geox', form.Value, 'geosite_url', _('GeoSite Url')); - o.rmempty = false; - - o = s.taboption('geox', form.Value, 'geoip_mmdb_url', _('GeoIP(MMDB) Url')); - o.rmempty = false; - - o = s.taboption('geox', form.Value, 'geoip_dat_url', _('GeoIP(DAT) Url')); - o.rmempty = false; - - o = s.taboption('geox', form.Value, 'geoip_asn_url', _('GeoIP(ASN) Url')); - o.rmempty = false; - - o = s.taboption('geox', form.Flag, 'geox_auto_update', _('GeoX Auto Update')); - o.rmempty = false; - - o = s.taboption('geox', form.Value, 'geox_update_interval', _('GeoX Update Interval')); - o.datatype = 'uinteger'; - o.placeholder = '24'; - o.retain = true; - o.depends('geox_auto_update', '1'); - - s.tab('mixin_file_content', _('Mixin File Content')); - - o = s.taboption('mixin_file_content', form.Flag, 'mixin_file_content', '*' + ' ' + _('Enable'), _('Please go to the editor tab to edit the file for mixin')); - o.rmempty = false; - - return m.render(); - } -}); diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js index 9a21cf1d47..a94a9674cb 100644 --- a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js @@ -9,7 +9,7 @@ return view.extend({ load: function () { return Promise.all([ uci.load('mihomo'), - mihomo.listProfiles(), + mihomo.listProfiles() ]); }, render: function (data) { @@ -20,9 +20,9 @@ return view.extend({ m = new form.Map('mihomo'); - s = m.section(form.NamedSection, 'editor', 'editor'); + s = m.section(form.NamedSection, 'editor', 'editor', _('Editor')); - o = s.option(form.ListValue, '_profile', _('Choose Profile')); + o = s.option(form.ListValue, '_file', _('Choose File')); o.optional = true; for (const profile of profiles) { @@ -43,19 +43,19 @@ return view.extend({ }; o.onchange = function (event, section_id, value) { return L.resolveDefault(fs.read_direct(value), '').then(function (content) { - m.lookupOption('mihomo.editor._profile_content')[0].getUIElement('editor').setValue(content); + m.lookupOption('mihomo.editor._file_content')[0].getUIElement('editor').setValue(content); }); }; - o = s.option(form.TextValue, '_profile_content',); + o = s.option(form.TextValue, '_file_content',); o.rows = 25; o.wrap = false; o.write = function (section_id, formvalue) { - const path = m.lookupOption('mihomo.editor._profile')[0].formvalue('editor'); + const path = m.lookupOption('mihomo.editor._file')[0].formvalue('editor'); return fs.write(path, formvalue); }; o.remove = function (section_id) { - const path = m.lookupOption('mihomo.editor._profile')[0].formvalue('editor'); + const path = m.lookupOption('mihomo.editor._file')[0].formvalue('editor'); return fs.write(path); }; diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js index 79a255c8aa..bde0be6fa7 100644 --- a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js @@ -2,9 +2,8 @@ 'require form'; 'require view'; 'require uci'; -'require fs'; 'require poll'; -'require tools.mihomo as mihomo' +'require tools.mihomo as mihomo'; return view.extend({ load: function () { @@ -22,7 +21,7 @@ return view.extend({ m = new form.Map('mihomo'); - s = m.section(form.NamedSection, 'log', 'log'); + s = m.section(form.NamedSection, 'log', 'log', _('Log')); s.tab('app_log', _('App Log')); @@ -95,4 +94,4 @@ return view.extend({ handleSaveApply: null, handleSave: null, handleReset: null -}); +}); \ No newline at end of file diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js new file mode 100644 index 0000000000..660a59009e --- /dev/null +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js @@ -0,0 +1,303 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require fs'; +'require poll'; +'require tools.widgets as widgets'; +'require tools.mihomo as mihomo'; + +return view.extend({ + load: function () { + return Promise.all([ + uci.load('mihomo') + ]); + }, + render: function (data) { + let m, s, o, so; + + m = new form.Map('mihomo'); + + s = m.section(form.NamedSection, 'config', 'config', _('Mixin Config')); + + o = s.option(form.Flag, 'mixin', _('Enable')); + o.rmempty = false; + + s = m.section(form.NamedSection, 'mixin', 'mixin', _('Mixin Option')); + + s.tab('general', _('General Config')); + + o = s.taboption('general', form.ListValue, 'log_level', '*' + ' ' + _('Log Level')); + o.value('silent'); + o.value('error'); + o.value('warning'); + o.value('info'); + o.value('debug'); + + o = s.taboption('general', form.ListValue, 'mode', _('Mode')); + o.value('global', _('Global Mode')); + o.value('rule', _('Rule Mode')); + o.value('direct', _('Direct Mode')); + + o = s.taboption('general', form.ListValue, 'match_process', _('Match Process')); + o.value('strict', _('Auto')); + o.value('always', _('Enable')); + o.value('off', _('Disable')); + + o = s.taboption('general', widgets.NetworkSelect, 'outbound_interface', '*' + ' ' + _('Outbound Interface')); + o.optional = true; + + o = s.taboption('general', form.Flag, 'ipv6', '*' + ' ' + _('IPv6')); + o.rmempty = false; + + o = s.taboption('general', form.Value, 'tcp_keep_alive_idle', _('TCP Keep Alive Idle')); + o.datatype = 'uinteger'; + o.placeholder = '600'; + + o = s.taboption('general', form.Value, 'tcp_keep_alive_interval', _('TCP Keep Alive Interval')); + o.datatype = 'uinteger'; + o.placeholder = '15'; + + s.tab('external_control', _('External Control Config')); + + o = s.taboption('external_control', form.Value, 'ui_name', '*' + ' ' + _('UI Name')); + + o = s.taboption('external_control', form.Value, 'ui_url', '*' + ' ' + _('UI Url')); + o.rmempty = false; + o.value('https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip', 'Zashboard'); + o.value('https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip', 'MetaCubeXD'); + o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD'); + o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord'); + + o = s.taboption('external_control', form.Value, 'api_port', '*' + ' ' + _('API Port')); + o.datatype = 'port'; + o.placeholder = '9090'; + + o = s.taboption('external_control', form.Value, 'api_secret', '*' + ' ' + _('API Secret')); + o.password = true; + o.rmempty = false; + + o = s.taboption('external_control', form.Flag, 'selection_cache', _('Save Proxy Selection')); + o.rmempty = false; + + s.tab('inbound', _('Inbound Config')); + + o = s.taboption('inbound', form.Flag, 'allow_lan', '*' + ' ' + _('Allow Lan')); + o.rmempty = false; + + o = s.taboption('inbound', form.Value, 'http_port', '*' + ' ' + _('HTTP Port')); + o.datatype = 'port'; + o.placeholder = '8080'; + + o = s.taboption('inbound', form.Value, 'socks_port', '*' + ' ' + _('SOCKS Port')); + o.datatype = 'port'; + o.placeholder = '1080'; + + o = s.taboption('inbound', form.Value, 'mixed_port', '*' + ' ' + _('Mixed Port')); + o.datatype = 'port'; + o.placeholder = '7890'; + + o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port')); + o.datatype = 'port'; + o.placeholder = '7891'; + + o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port')); + o.datatype = 'port'; + o.placeholder = '7892'; + + o = s.taboption('inbound', form.Flag, 'authentication', '*' + ' ' + _('Overwrite Authentication')); + o.rmempty = false; + + o = s.taboption('inbound', form.SectionValue, '_authentications', form.TableSection, 'authentication', _('Edit Authentications')); + o.retain = true; + o.depends('authentication', '1'); + + o.subsection.addremove = true; + o.subsection.anonymous = true; + o.subsection.sortable = true; + + so = o.subsection.option(form.Flag, 'enabled', _('Enable')); + so.rmempty = false; + + so = o.subsection.option(form.Value, 'username', _('Username')); + so.rmempty = false; + + so = o.subsection.option(form.Value, 'password', _('Password')); + so.password = true; + so.rmempty = false; + + s.tab('tun', _('TUN Config')); + + o = s.taboption('tun', form.ListValue, 'tun_stack', '*' + ' ' + _('Stack')); + o.value('system', 'System'); + o.value('gvisor', 'gVisor'); + o.value('mixed', 'Mixed'); + + o = s.taboption('tun', form.Value, 'tun_mtu', '*' + ' ' + _('MTU')); + o.datatype = 'uinteger'; + o.placeholder = '9000'; + + o = s.taboption('tun', form.Flag, 'tun_gso', '*' + ' ' + _('GSO')); + o.rmempty = false; + + o = s.taboption('tun', form.Value, 'tun_gso_max_size', '*' + ' ' + _('GSO Max Size')); + o.datatype = 'uinteger'; + o.placeholder = '65536'; + o.retain = true; + o.depends('tun_gso', '1'); + + o = s.taboption('tun', form.Flag, 'tun_endpoint_independent_nat', '*' + ' ' + _('Endpoint Independent NAT')); + o.rmempty = false; + + s.tab('dns', _('DNS Config')); + + o = s.taboption('dns', form.Value, 'dns_port', '*' + ' ' + _('DNS Port')); + o.datatype = 'port'; + o.placeholder = '1053'; + + o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode')); + o.value('normal', 'Normal'); + o.value('fake-ip', 'Fake-IP'); + o.value('redir-host', 'Redir-Host'); + + o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range')); + o.datatype = 'cidr4'; + o.placeholder = '198.18.0.1/16'; + o.retain = true; + o.depends('dns_mode', 'fake-ip'); + + o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter')); + o.retain = true; + o.rmempty = false; + o.depends('dns_mode', 'fake-ip'); + + o = s.taboption('dns', form.DynamicList, 'fake_ip_filters', _('Edit Fake-IP Filters')); + o.retain = true; + o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); + + o = s.taboption('dns', form.ListValue, 'fake_ip_filter_mode', _('Fake-IP Filter Mode')); + o.retain = true; + o.value('blacklist', _('Block Mode')); + o.value('whitelist', _('Allow Mode')); + o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' }); + + o = s.taboption('dns', form.Flag, 'fake_ip_cache', _('Fake-IP Cache')); + o.retain = true; + o.rmempty = false; + o.depends('dns_mode', 'fake-ip'); + + o = s.taboption('dns', form.Flag, 'dns_respect_rules', _('Respect Rules')); + o.rmempty = false; + + o = s.taboption('dns', form.Flag, 'dns_doh_prefer_http3', _('DoH Prefer HTTP/3')); + o.rmempty = false; + + o = s.taboption('dns', form.Flag, 'dns_ipv6', _('IPv6')); + o.rmempty = false; + + o = s.taboption('dns', form.Flag, 'dns_system_hosts', _('Use System Hosts')); + o.rmempty = false; + + o = s.taboption('dns', form.Flag, 'dns_hosts', _('Use Hosts')); + o.rmempty = false; + + o = s.taboption('dns', form.Flag, 'hosts', _('Overwrite Hosts')); + o.rmempty = false; + + o = s.taboption('dns', form.SectionValue, '_hosts', form.TableSection, 'host', _('Edit Hosts')); + o.retain = true; + o.depends('hosts', '1'); + + o.subsection.addremove = true; + o.subsection.anonymous = true; + o.subsection.sortable = true; + + so = o.subsection.option(form.Flag, 'enabled', _('Enable')); + so.rmempty = false; + + so = o.subsection.option(form.Value, 'domain_name', _('Domain Name')); + so.rmempty = false; + + so = o.subsection.option(form.DynamicList, 'ip', _('IP')); + + o = s.taboption('dns', form.Flag, 'dns_nameserver', _('Overwrite Nameserver')); + o.rmempty = false; + + o = s.taboption('dns', form.SectionValue, '_dns_nameserver', form.TableSection, 'nameserver', _('Edit Nameservers')); + o.retain = true; + o.depends('dns_nameserver', '1'); + + o.subsection.addremove = true; + o.subsection.anonymous = true; + o.subsection.sortable = true; + + so = o.subsection.option(form.Flag, 'enabled', _('Enable')); + so.rmempty = false; + + so = o.subsection.option(form.ListValue, 'type', _('Type')); + so.value('default-nameserver'); + so.value('proxy-server-nameserver'); + so.value('direct-nameserver'); + so.value('nameserver'); + so.value('fallback'); + + so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver')); + + o = s.taboption('dns', form.Flag, 'dns_nameserver_policy', _('Overwrite Nameserver Policy')); + o.rmempty = false; + + o = s.taboption('dns', form.SectionValue, '_dns_nameserver_policies', form.TableSection, 'nameserver_policy', _('Edit Nameserver Policies')); + o.retain = true; + o.depends('dns_nameserver_policy', '1'); + + o.subsection.addremove = true; + o.subsection.anonymous = true; + o.subsection.sortable = true; + + so = o.subsection.option(form.Flag, 'enabled', _('Enable')); + so.rmempty = false; + + so = o.subsection.option(form.Value, 'matcher', _('Matcher')); + so.rmempty = false; + + so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver')); + + s.tab('geox', _('GeoX Config')); + + o = s.taboption('geox', form.ListValue, 'geoip_format', _('GeoIP Format')); + o.value('dat', 'DAT'); + o.value('mmdb', 'MMDB'); + + o = s.taboption('geox', form.ListValue, 'geodata_loader', _('GeoData Loader')); + o.value('standard', _('Standard Loader')); + o.value('memconservative', _('Memory Conservative Loader')); + + o = s.taboption('geox', form.Value, 'geosite_url', _('GeoSite Url')); + o.rmempty = false; + + o = s.taboption('geox', form.Value, 'geoip_mmdb_url', _('GeoIP(MMDB) Url')); + o.rmempty = false; + + o = s.taboption('geox', form.Value, 'geoip_dat_url', _('GeoIP(DAT) Url')); + o.rmempty = false; + + o = s.taboption('geox', form.Value, 'geoip_asn_url', _('GeoIP(ASN) Url')); + o.rmempty = false; + + o = s.taboption('geox', form.Flag, 'geox_auto_update', _('GeoX Auto Update')); + o.rmempty = false; + + o = s.taboption('geox', form.Value, 'geox_update_interval', _('GeoX Update Interval')); + o.datatype = 'uinteger'; + o.placeholder = '24'; + o.retain = true; + o.depends('geox_auto_update', '1'); + + s.tab('mixin_file_content', _('Mixin File Content')); + + o = s.taboption('mixin_file_content', form.Flag, 'mixin_file_content', '*' + ' ' + _('Enable'), _('Please go to the editor tab to edit the file for mixin')); + o.rmempty = false; + + return m.render(); + } +}); \ No newline at end of file diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js new file mode 100644 index 0000000000..6952ea5818 --- /dev/null +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js @@ -0,0 +1,86 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require tools.mihomo as mihomo'; + +return view.extend({ + load: function () { + return Promise.all([ + uci.load('mihomo') + ]); + }, + render: function (data) { + let m, s, o, so; + + m = new form.Map('mihomo'); + + s = m.section(form.NamedSection, 'config', 'config', _('Profile')); + + o = s.option(form.FileUpload, '_upload_profile', _('Upload Profile')); + o.browser = true; + o.enable_download = true; + o.root_directory = mihomo.profilesDir; + o.write = function (section_id, formvalue) { + return true; + }; + + s = m.section(form.GridSection, 'subscription', _('Subscription')); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + s.modaltitle = _('Edit Subscription'); + + o = s.option(form.Value, 'name', _('Subscription Name')); + o.rmempty = false; + + o = s.option(form.Value, 'used', _('Used')); + o.modalonly = false; + o.optional = true; + o.readonly = true; + + o = s.option(form.Value, 'total', _('Total')); + o.modalonly = false; + o.optional = true; + o.readonly = true; + + o = s.option(form.Value, 'expire', _('Expire At')); + o.modalonly = false; + o.optional = true; + o.readonly = true; + + o = s.option(form.Value, 'update', _('Update At')); + o.modalonly = false; + o.optional = true; + o.readonly = true; + + o = s.option(form.Button, 'update_subscription'); + o.editable = true; + o.inputstyle = 'positive'; + o.inputtitle = _('Update'); + o.modalonly = false; + o.onclick = function (_, section_id) { + return mihomo.updateSubscription(section_id); + }; + + o = s.option(form.Value, 'url', _('Subscription Url')); + o.modalonly = true; + o.rmempty = false; + + o = s.option(form.Value, 'user_agent', _('User Agent')); + o.default = 'clash'; + o.modalonly = true; + o.rmempty = false; + o.value('mihomo'); + o.value('clash.meta'); + o.value('clash'); + + o = s.option(form.ListValue, 'prefer', _('Prefer')); + o.default = 'remote'; + o.modalonly = true; + o.value('remote', _('Remote')); + o.value('local', _('Local')); + + return m.render(); + } +}); diff --git a/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js new file mode 100644 index 0000000000..6264ef3d76 --- /dev/null +++ b/small/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js @@ -0,0 +1,145 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require network'; +'require tools.widgets as widgets'; +'require tools.mihomo as mihomo'; + +return view.extend({ + load: function () { + return Promise.all([ + uci.load('mihomo'), + network.getHostHints(), + mihomo.getUsers(), + mihomo.getGroups() + ]); + }, + render: function (data) { + const hosts = data[1].hosts; + const users = data[2]; + const groups = data[3]; + + let m, s, o; + + m = new form.Map('mihomo'); + + s = m.section(form.NamedSection, 'proxy', 'proxy', _('Proxy Config')); + + s.tab('transparent_proxy', _('Transparent Proxy')); + + o = s.taboption('transparent_proxy', form.Flag, 'transparent_proxy', _('Enable')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.ListValue, 'tcp_transparent_proxy_mode', _('TCP Proxy Mode')); + o.value('redirect', _('Redirect Mode')); + o.value('tproxy', _('TPROXY Mode')); + o.value('tun', _('TUN Mode')); + + o = s.taboption('transparent_proxy', form.ListValue, 'udp_transparent_proxy_mode', _('UDP Proxy Mode')); + o.value('tproxy', _('TPROXY Mode')); + o.value('tun', _('TUN Mode')); + + o = s.taboption('transparent_proxy', form.Flag, 'ipv4_dns_hijack', _('IPv4 DNS Hijack')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.Flag, 'ipv6_dns_hijack', _('IPv6 DNS Hijack')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.Flag, 'ipv4_proxy', _('IPv4 Proxy')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.Flag, 'ipv6_proxy', _('IPv6 Proxy')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.Flag, 'router_proxy', _('Router Proxy')); + o.rmempty = false; + + o = s.taboption('transparent_proxy', form.Flag, 'lan_proxy', _('Lan Proxy')); + o.rmempty = false; + + s.tab('access_control', _('Access Control')); + + o = s.taboption('access_control', form.ListValue, 'access_control_mode', _('Mode')); + o.value('all', _('All Mode')); + o.value('allow', _('Allow Mode')); + o.value('block', _('Block Mode')); + + o = s.taboption('access_control', form.DynamicList, 'acl_ip', 'IP'); + o.datatype = 'ipmask4'; + o.retain = true; + o.depends('access_control_mode', 'allow'); + o.depends('access_control_mode', 'block'); + + for (const mac in hosts) { + const host = hosts[mac]; + for (const ip of host.ipaddrs) { + const hint = host.name || mac; + o.value(ip, hint ? '%s (%s)'.format(ip, hint) : ip); + }; + }; + + o = s.taboption('access_control', form.DynamicList, 'acl_ip6', 'IP6'); + o.datatype = 'ipmask6'; + o.retain = true; + o.depends('access_control_mode', 'allow'); + o.depends('access_control_mode', 'block'); + + for (const mac in hosts) { + const host = hosts[mac]; + for (const ip of host.ip6addrs) { + const hint = host.name || mac; + o.value(ip, hint ? '%s (%s)'.format(ip, hint) : ip); + }; + }; + + o = s.taboption('access_control', form.DynamicList, 'acl_mac', 'MAC'); + o.datatype = 'macaddr'; + o.retain = true; + o.depends('access_control_mode', 'allow'); + o.depends('access_control_mode', 'block'); + + for (const mac in hosts) { + const host = hosts[mac]; + const hint = host.name || host.ipaddrs[0]; + o.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); + }; + + o = s.taboption('access_control', widgets.NetworkSelect, 'acl_interface', _('Interface')); + o.multiple = true; + o.optional = true; + o.retain = true; + o.depends('access_control_mode', 'allow'); + o.depends('access_control_mode', 'block'); + + s.tab('bypass', _('Bypass')); + + o = s.taboption('bypass', form.MultiValue, 'bypass_user', _('Bypass User')); + o.create = true; + + for (const user of users) { + o.value(user); + }; + + o = s.taboption('bypass', form.MultiValue, 'bypass_group', _('Bypass Group')); + o.create = true; + + for (const group of groups) { + o.value(group); + }; + + o = s.taboption('bypass', form.Flag, 'bypass_china_mainland_ip', _('Bypass China Mainland IP')); + o.rmempty = false; + + o = s.taboption('bypass', form.Value, 'proxy_tcp_dport', _('Destination TCP Port to Proxy')); + o.rmempty = false; + o.value('0-65535', _('All Port')); + o.value('21 22 80 110 143 194 443 465 853 993 995 8080 8443', _('Commonly Used Port')); + + o = s.taboption('bypass', form.Value, 'proxy_udp_dport', _('Destination UDP Port to Proxy')); + o.rmempty = false; + o.value('0-65535', _('All Port')); + o.value('123 443 8443', _('Commonly Used Port')); + return m.render(); + } +}); diff --git a/small/luci-app-mihomo/po/templates/mihomo.pot b/small/luci-app-mihomo/po/templates/mihomo.pot index 882887472a..a48c21bebf 100644 --- a/small/luci-app-mihomo/po/templates/mihomo.pot +++ b/small/luci-app-mihomo/po/templates/mihomo.pot @@ -1,232 +1,230 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:386 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:72 msgid "API Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:390 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:76 msgid "API Secret" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:200 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:61 msgid "Access Control" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:203 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:64 msgid "All Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:275 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:280 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:136 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:141 msgid "All Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:399 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:85 msgid "Allow Lan" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:204 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:495 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:181 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:65 msgid "Allow Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:106 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:94 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:13 msgid "App Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:27 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:38 msgid "App Log" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:53 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:43 msgid "App Version" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:356 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:43 msgid "Auto" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:104 -msgid "Basic Config" -msgstr "" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:205 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:494 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:180 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:66 msgid "Block Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:254 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:115 msgid "Bypass" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:270 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:131 msgid "Bypass China Mainland IP" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:263 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:124 msgid "Bypass Group" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:256 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:117 msgid "Bypass User" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:111 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:25 +msgid "Choose File" +msgstr "" + +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:99 msgid "Choose Profile" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:31 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:64 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:42 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:75 msgid "Clear Log" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:276 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:281 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:137 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:142 msgid "Commonly Used Port" msgstr "" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:14 -msgid "Config" -msgstr "" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:148 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:128 msgid "Core Environment Variable Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:60 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:71 msgid "Core Log" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:67 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:57 msgid "Core Status" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:60 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:50 msgid "Core Version" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:137 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:117 msgid "Cron Expression" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:466 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:152 msgid "DNS Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:472 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:158 msgid "DNS Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:468 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:154 msgid "DNS Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:273 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:134 msgid "Destination TCP Port to Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:278 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:139 msgid "Destination UDP Port to Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:353 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:40 msgid "Direct Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:358 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:45 msgid "Disable" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:162 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:142 msgid "Disable ECN of quic-go" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:158 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:138 msgid "Disable GSO of quic-go" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:154 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:134 msgid "Disable Loopback Detector" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:150 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:130 msgid "Disable Safe Path Check" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:506 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:192 msgid "DoH Prefer HTTP/3" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:532 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:218 msgid "Domain Name" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:425 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:111 msgid "Edit Authentications" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:488 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:174 msgid "Edit Fake-IP Filters" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:521 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:207 msgid "Edit Hosts" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:563 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:249 msgid "Edit Nameserver Policies" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:540 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:226 msgid "Edit Nameservers" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:287 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:32 msgid "Edit Subscription" msgstr "" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:22 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:23 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:45 msgid "Editor" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:108 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:170 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:357 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:433 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:529 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:548 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:571 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:612 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:96 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:23 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:44 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:119 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:215 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:234 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:257 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:298 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:31 msgid "Enable" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:463 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:149 msgid "Endpoint Independent NAT" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:302 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:47 msgid "Expire At" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:374 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:61 msgid "External Control Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:498 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:184 msgid "Fake-IP Cache" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:492 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:178 msgid "Fake-IP Filter Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:477 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:163 msgid "Fake-IP Range" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:145 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:125 msgid "Fast Reload" msgstr "" @@ -242,60 +240,60 @@ msgstr "" msgid "File for Reserved IP6" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:115 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:103 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:29 msgid "File:" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:454 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:140 msgid "GSO" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:457 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:143 msgid "GSO Max Size" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:341 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:28 msgid "General Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:585 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:271 msgid "GeoData Loader" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:581 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:267 msgid "GeoIP Format" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:598 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:284 msgid "GeoIP(ASN) Url" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:595 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:281 msgid "GeoIP(DAT) Url" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:592 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:278 msgid "GeoIP(MMDB) Url" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:589 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:275 msgid "GeoSite Url" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:601 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:287 msgid "GeoX Auto Update" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:579 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:265 msgid "GeoX Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:604 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:290 msgid "GeoX Update Interval" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:351 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:38 msgid "Global Mode" msgstr "" @@ -303,212 +301,222 @@ msgstr "" msgid "Grant access to mihomo procedures" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:402 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:88 msgid "HTTP Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 msgid "How To Use" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:535 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:221 msgid "IP" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:182 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:43 msgid "IPv4 DNS Hijack" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:188 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:49 msgid "IPv4 Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:363 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:509 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:50 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:195 msgid "IPv6" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:185 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:46 msgid "IPv6 DNS Hijack" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:191 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:52 msgid "IPv6 Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:397 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:83 msgid "Inbound Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:247 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:108 msgid "Interface" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:197 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:58 msgid "Lan Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:337 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:82 msgid "Local" msgstr "" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:30 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:36 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:53 msgid "Log" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:343 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:30 msgid "Log Level" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:450 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:136 msgid "MTU" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:355 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:42 msgid "Match Process" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:574 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:260 msgid "Matcher" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:587 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:273 msgid "Memory Conservative Loader" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 #: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:3 msgid "MihomoTProxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:410 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:96 msgid "Mixed Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:125 -msgid "Mixin" -msgstr "" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:339 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:21 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:29 msgid "Mixin Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:610 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:296 msgid "Mixin File Content" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:202 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:350 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:26 +msgid "Mixin Option" +msgstr "" + +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:37 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:63 msgid "Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:558 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:577 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:244 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:263 msgid "Nameserver" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:19 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:15 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:15 msgid "Not Running" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:99 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:89 msgid "Open Dashboard" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:360 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:47 msgid "Outbound Interface" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:422 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:108 msgid "Overwrite Authentication" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:483 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:169 msgid "Overwrite Fake-IP Filter" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:518 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:204 msgid "Overwrite Hosts" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:537 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:223 msgid "Overwrite Nameserver" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:560 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:246 msgid "Overwrite Nameserver Policy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:439 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:125 msgid "Password" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:612 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:298 msgid "Please go to the editor tab to edit the file for mixin" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:333 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:78 msgid "Prefer" msgstr "" +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:18 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:21 +msgid "Profile" +msgstr "" + #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:37 msgid "Profile for Startup" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:166 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:27 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:37 msgid "Proxy Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:174 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:35 msgid "Redirect Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:414 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:100 msgid "Redirect Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:79 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:69 msgid "Reload Service" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:336 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:81 msgid "Remote" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:503 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:189 msgid "Respect Rules" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:86 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:76 msgid "Restart Service" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:194 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:55 msgid "Router Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:352 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:39 msgid "Rule Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:19 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:15 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:15 msgid "Running" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:406 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:92 msgid "SOCKS Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:394 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:80 msgid "Save Proxy Selection" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:134 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:114 msgid "Scheduled Restart" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:54 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:87 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:65 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:98 msgid "Scroll To Bottom" msgstr "" @@ -517,102 +525,98 @@ msgstr "" msgid "Service is not running." msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:445 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:131 msgid "Stack" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:586 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:272 msgid "Standard Loader" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:130 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:110 msgid "Start Delay" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:128 -msgid "Startup Config" -msgstr "" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:51 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:41 msgid "Status" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:283 -msgid "Subscription Config" +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:28 +msgid "Subscription" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:289 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:34 msgid "Subscription Name" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:321 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:66 msgid "Subscription Url" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:119 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:107 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:33 msgid "Subscription:" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:366 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:53 msgid "TCP Keep Alive Idle" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:370 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:57 msgid "TCP Keep Alive Interval" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:173 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:34 msgid "TCP Proxy Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:175 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:179 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:36 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:40 msgid "TPROXY Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:418 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:104 msgid "TPROXY Port" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:443 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:129 msgid "TUN Config" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:176 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:180 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:37 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:41 msgid "TUN Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:142 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:122 msgid "Test Profile" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:297 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:42 msgid "Total" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:168 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:29 msgid "Transparent Proxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 msgid "Transparent Proxy with Mihomo on OpenWrt." msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:551 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:237 msgid "Type" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:178 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:39 msgid "UDP Proxy Mode" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:376 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:63 msgid "UI Name" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:379 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:65 msgid "UI Url" msgstr "" @@ -621,38 +625,38 @@ msgstr "" msgid "Unknown" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:315 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:60 msgid "Update" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:307 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:52 msgid "Update At" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:93 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:83 msgid "Update Dashboard" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:122 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:20 msgid "Upload Profile" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:515 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:201 msgid "Use Hosts" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:512 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:198 msgid "Use System Hosts" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:292 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:37 msgid "Used" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:325 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:70 msgid "User Agent" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:436 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:122 msgid "Username" msgstr "" diff --git a/small/luci-app-mihomo/po/zh_Hans/mihomo.po b/small/luci-app-mihomo/po/zh_Hans/mihomo.po index b39595661f..be5cadcc8d 100644 --- a/small/luci-app-mihomo/po/zh_Hans/mihomo.po +++ b/small/luci-app-mihomo/po/zh_Hans/mihomo.po @@ -8,232 +8,230 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:386 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:72 msgid "API Port" msgstr "API 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:390 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:76 msgid "API Secret" msgstr "API 密钥" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:200 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:61 msgid "Access Control" msgstr "访问控制" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:203 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:64 msgid "All Mode" msgstr "全部模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:275 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:280 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:136 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:141 msgid "All Port" msgstr "全部端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:399 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:85 msgid "Allow Lan" msgstr "允许局域网访问" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:204 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:495 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:181 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:65 msgid "Allow Mode" msgstr "白名单模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:106 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:94 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:13 msgid "App Config" msgstr "插件配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:27 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:38 msgid "App Log" msgstr "插件日志" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:53 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:43 msgid "App Version" msgstr "插件版本" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:356 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:43 msgid "Auto" msgstr "自动" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:104 -msgid "Basic Config" -msgstr "基础配置" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:205 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:494 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:180 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:66 msgid "Block Mode" msgstr "黑名单模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:254 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:115 msgid "Bypass" msgstr "绕过" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:270 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:131 msgid "Bypass China Mainland IP" msgstr "绕过中国大陆 IP" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:263 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:124 msgid "Bypass Group" msgstr "绕过用户组" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:256 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:117 msgid "Bypass User" msgstr "绕过用户" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:111 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:25 +msgid "Choose File" +msgstr "选择文件" + +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:99 msgid "Choose Profile" msgstr "选择配置文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:31 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:64 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:42 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:75 msgid "Clear Log" msgstr "清空日志" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:276 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:281 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:137 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:142 msgid "Commonly Used Port" msgstr "常用端口" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:14 -msgid "Config" -msgstr "配置" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:148 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:128 msgid "Core Environment Variable Config" msgstr "核心环境变量配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:60 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:71 msgid "Core Log" msgstr "核心日志" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:67 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:57 msgid "Core Status" msgstr "核心状态" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:60 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:50 msgid "Core Version" msgstr "核心版本" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:137 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:117 msgid "Cron Expression" msgstr "Cron 表达式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:466 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:152 msgid "DNS Config" msgstr "DNS 配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:472 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:158 msgid "DNS Mode" msgstr "DNS 模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:468 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:154 msgid "DNS Port" msgstr "DNS 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:273 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:134 msgid "Destination TCP Port to Proxy" msgstr "要代理的 TCP 目标端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:278 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:139 msgid "Destination UDP Port to Proxy" msgstr "要代理的 UDP 目标端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:353 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:40 msgid "Direct Mode" msgstr "直连模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:358 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:45 msgid "Disable" msgstr "禁用" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:162 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:142 msgid "Disable ECN of quic-go" -msgstr "禁用 quic-go 的显式拥塞通告" +msgstr "禁用 quic-go 的显式拥塞通知" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:158 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:138 msgid "Disable GSO of quic-go" msgstr "禁用 quic-go 的通用分段卸载" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:154 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:134 msgid "Disable Loopback Detector" msgstr "禁用回环检测" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:150 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:130 msgid "Disable Safe Path Check" msgstr "禁用安全路径检查" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:506 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:192 msgid "DoH Prefer HTTP/3" msgstr "DoH 优先 HTTP/3" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:532 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:218 msgid "Domain Name" msgstr "域名" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:425 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:111 msgid "Edit Authentications" msgstr "编辑身份验证" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:488 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:174 msgid "Edit Fake-IP Filters" msgstr "编辑 Fake-IP 过滤列表" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:521 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:207 msgid "Edit Hosts" msgstr "编辑 Hosts" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:563 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:249 msgid "Edit Nameserver Policies" msgstr "编辑 DNS 服务器查询策略" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:540 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:226 msgid "Edit Nameservers" msgstr "编辑 DNS 服务器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:287 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:32 msgid "Edit Subscription" msgstr "编辑订阅" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:22 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:23 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:45 msgid "Editor" msgstr "编辑器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:108 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:170 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:357 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:433 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:529 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:548 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:571 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:612 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:96 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:23 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:44 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:119 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:215 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:234 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:257 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:298 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:31 msgid "Enable" msgstr "启用" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:463 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:149 msgid "Endpoint Independent NAT" msgstr "独立于端点的 NAT" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:302 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:47 msgid "Expire At" msgstr "到期时间" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:374 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:61 msgid "External Control Config" msgstr "外部控制配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:498 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:184 msgid "Fake-IP Cache" msgstr "Fake-IP 缓存" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:492 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:178 msgid "Fake-IP Filter Mode" msgstr "Fake-IP 过滤模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:477 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:163 msgid "Fake-IP Range" msgstr "Fake-IP 范围" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:145 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:125 msgid "Fast Reload" msgstr "快速重载" @@ -249,60 +247,60 @@ msgstr "IPv4 保留地址" msgid "File for Reserved IP6" msgstr "IPv6 保留地址" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:115 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:103 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:29 msgid "File:" msgstr "文件:" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:454 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:140 msgid "GSO" msgstr "通用分段卸载" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:457 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:143 msgid "GSO Max Size" msgstr "分段最大长度" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:341 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:28 msgid "General Config" msgstr "全局配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:585 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:271 msgid "GeoData Loader" msgstr "GeoData 加载器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:581 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:267 msgid "GeoIP Format" msgstr "GeoIP 格式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:598 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:284 msgid "GeoIP(ASN) Url" msgstr "GeoIP(ASN) 下载地址" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:595 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:281 msgid "GeoIP(DAT) Url" msgstr "GeoIP(DAT) 下载地址" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:592 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:278 msgid "GeoIP(MMDB) Url" msgstr "GeoIP(MMDB) 下载地址" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:589 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:275 msgid "GeoSite Url" msgstr "GeoSite 下载地址" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:601 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:287 msgid "GeoX Auto Update" msgstr "定时更新GeoX文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:579 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:265 msgid "GeoX Config" msgstr "GeoX 配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:604 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:290 msgid "GeoX Update Interval" msgstr "GeoX 文件更新间隔" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:351 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:38 msgid "Global Mode" msgstr "全局模式" @@ -310,212 +308,222 @@ msgstr "全局模式" msgid "Grant access to mihomo procedures" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:402 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:88 msgid "HTTP Port" msgstr "HTTP 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 msgid "How To Use" msgstr "使用说明" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:535 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:221 msgid "IP" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:182 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:43 msgid "IPv4 DNS Hijack" msgstr "IPv4 DNS 劫持" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:188 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:49 msgid "IPv4 Proxy" msgstr "IPv4 代理" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:363 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:509 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:50 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:195 msgid "IPv6" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:185 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:46 msgid "IPv6 DNS Hijack" msgstr "IPv6 DNS 劫持" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:191 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:52 msgid "IPv6 Proxy" msgstr "IPv6 代理" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:397 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:83 msgid "Inbound Config" msgstr "入站配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:247 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:108 msgid "Interface" msgstr "接口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:197 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:58 msgid "Lan Proxy" msgstr "局域网代理" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:337 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:82 msgid "Local" msgstr "本地" -#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:30 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:36 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:53 msgid "Log" msgstr "日志" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:343 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:30 msgid "Log Level" msgstr "日志级别" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:450 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:136 msgid "MTU" msgstr "最大传输单元" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:355 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:42 msgid "Match Process" msgstr "匹配进程" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:574 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:260 msgid "Matcher" msgstr "匹配" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:587 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:273 msgid "Memory Conservative Loader" msgstr "为内存受限设备优化的加载器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 #: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:3 msgid "MihomoTProxy" msgstr "" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:410 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:96 msgid "Mixed Port" msgstr "混合端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:125 -msgid "Mixin" -msgstr "混入" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:339 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:21 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:29 msgid "Mixin Config" msgstr "混入配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:610 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:296 msgid "Mixin File Content" msgstr "混入文件内容" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:202 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:350 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:26 +msgid "Mixin Option" +msgstr "混入选项" + +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:37 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:63 msgid "Mode" msgstr "模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:558 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:577 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:244 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:263 msgid "Nameserver" msgstr "DNS 服务器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:19 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:15 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:15 msgid "Not Running" msgstr "未在运行" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:99 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:89 msgid "Open Dashboard" msgstr "打开面板" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:360 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:47 msgid "Outbound Interface" msgstr "出站接口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:422 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:108 msgid "Overwrite Authentication" msgstr "覆盖身份验证" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:483 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:169 msgid "Overwrite Fake-IP Filter" msgstr "覆盖 Fake-IP 过滤列表" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:518 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:204 msgid "Overwrite Hosts" msgstr "覆盖 Hosts" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:537 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:223 msgid "Overwrite Nameserver" msgstr "覆盖 DNS 服务器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:560 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:246 msgid "Overwrite Nameserver Policy" msgstr "覆盖 DNS 服务器查询策略" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:439 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:125 msgid "Password" msgstr "密码" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:612 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:298 msgid "Please go to the editor tab to edit the file for mixin" msgstr "请前往编辑器标签编辑用于混入的文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:333 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:78 msgid "Prefer" msgstr "优先" +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:18 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:21 +msgid "Profile" +msgstr "配置文件" + #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:37 msgid "Profile for Startup" msgstr "用于启动的配置文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:166 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:27 +#: applications/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json:37 msgid "Proxy Config" msgstr "代理配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:174 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:35 msgid "Redirect Mode" msgstr "Redirect 模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:414 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:100 msgid "Redirect Port" msgstr "Redirect 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:79 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:69 msgid "Reload Service" msgstr "重载服务" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:336 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:81 msgid "Remote" msgstr "远程" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:503 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:189 msgid "Respect Rules" msgstr "遵循分流规则" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:86 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:76 msgid "Restart Service" msgstr "重启服务" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:194 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:55 msgid "Router Proxy" msgstr "路由器代理" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:352 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:39 msgid "Rule Mode" msgstr "规则模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:19 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:15 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:15 msgid "Running" msgstr "运行中" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:406 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:92 msgid "SOCKS Port" msgstr "SOCKS 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:394 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:80 msgid "Save Proxy Selection" msgstr "保存节点/策略组选择" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:134 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:114 msgid "Scheduled Restart" msgstr "定时重启" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:54 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:87 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:65 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/log.js:98 msgid "Scroll To Bottom" msgstr "滚动到底部" @@ -524,102 +532,98 @@ msgstr "滚动到底部" msgid "Service is not running." msgstr "服务未在运行。" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:445 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:131 msgid "Stack" msgstr "栈" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:586 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:272 msgid "Standard Loader" msgstr "标准加载器" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:130 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:110 msgid "Start Delay" msgstr "启动延迟" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:128 -msgid "Startup Config" -msgstr "启动配置" - -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:51 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:41 msgid "Status" msgstr "状态" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:283 -msgid "Subscription Config" -msgstr "订阅配置" +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:28 +msgid "Subscription" +msgstr "订阅" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:289 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:34 msgid "Subscription Name" msgstr "订阅名称" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:321 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:66 msgid "Subscription Url" msgstr "订阅链接" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:119 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:107 #: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/editor.js:33 msgid "Subscription:" msgstr "订阅:" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:366 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:53 msgid "TCP Keep Alive Idle" msgstr "TCP Keep Alive 空闲" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:370 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:57 msgid "TCP Keep Alive Interval" msgstr "TCP Keep Alive 间隔" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:173 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:34 msgid "TCP Proxy Mode" msgstr "TCP 代理模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:175 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:179 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:36 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:40 msgid "TPROXY Mode" msgstr "TPROXY 模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:418 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:104 msgid "TPROXY Port" msgstr "TPROXY 端口" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:443 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:129 msgid "TUN Config" msgstr "TUN 配置" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:176 -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:180 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:37 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:41 msgid "TUN Mode" msgstr "TUN 模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:142 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:122 msgid "Test Profile" msgstr "检查配置文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:297 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:42 msgid "Total" msgstr "总量" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:168 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:29 msgid "Transparent Proxy" msgstr "透明代理" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:49 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:39 msgid "Transparent Proxy with Mihomo on OpenWrt." msgstr "在 OpenWrt 上使用 Mihomo 进行透明代理。" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:551 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:237 msgid "Type" msgstr "类型" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:178 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/proxy.js:39 msgid "UDP Proxy Mode" msgstr "UDP 代理模式" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:376 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:63 msgid "UI Name" msgstr "UI 名称" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:379 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:65 msgid "UI Url" msgstr "UI 下载地址" @@ -628,38 +632,38 @@ msgstr "UI 下载地址" msgid "Unknown" msgstr "未知" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:315 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:60 msgid "Update" msgstr "更新" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:307 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:52 msgid "Update At" msgstr "更新时间" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:93 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/app.js:83 msgid "Update Dashboard" msgstr "更新面板" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:122 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:20 msgid "Upload Profile" msgstr "上传配置文件" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:515 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:201 msgid "Use Hosts" msgstr "使用 Hosts" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:512 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:198 msgid "Use System Hosts" msgstr "使用系统的 Hosts" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:292 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:37 msgid "Used" msgstr "已使用" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:325 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/profile.js:70 msgid "User Agent" msgstr "用户代理(UA)" -#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/config.js:436 +#: applications/luci-app-mihomo/htdocs/luci-static/resources/view/mihomo/mixin.js:122 msgid "Username" msgstr "用户名" diff --git a/small/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json b/small/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json index 90c6b2ec30..b2860282bb 100644 --- a/small/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json +++ b/small/luci-app-mihomo/root/usr/share/luci/menu.d/luci-app-mihomo.json @@ -2,8 +2,7 @@ "admin/services/mihomo": { "title": "MihomoTProxy", "action": { - "type": "alias", - "path": "admin/services/mihomo/config" + "type": "firstchild" }, "depends": { "acl": [ "luci-app-mihomo" ], @@ -11,16 +10,40 @@ } }, "admin/services/mihomo/config": { - "title": "Config", + "title": "App Config", "order": 10, "action": { "type": "view", - "path": "mihomo/config" + "path": "mihomo/app" + } + }, + "admin/services/mihomo/profile": { + "title": "Profile", + "order": 20, + "action": { + "type": "view", + "path": "mihomo/profile" + } + }, + "admin/services/mihomo/mixin": { + "title": "Mixin Config", + "order": 30, + "action": { + "type": "view", + "path": "mihomo/mixin" + } + }, + "admin/services/mihomo/proxy": { + "title": "Proxy Config", + "order": 40, + "action": { + "type": "view", + "path": "mihomo/proxy" } }, "admin/services/mihomo/editor": { "title": "Editor", - "order": 20, + "order": 50, "action": { "type": "view", "path": "mihomo/editor" @@ -28,7 +51,7 @@ }, "admin/services/mihomo/log": { "title": "Log", - "order": 30, + "order": 60, "action": { "type": "view", "path": "mihomo/log" diff --git a/small/luci-app-passwall/Makefile b/small/luci-app-passwall/Makefile index fa1cd41382..2b724683e3 100644 --- a/small/luci-app-passwall/Makefile +++ b/small/luci-app-passwall/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall -PKG_VERSION:=24.12.08 -PKG_RELEASE:=1 +PKG_VERSION:=24.12.17 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/small/luci-app-passwall/root/usr/share/passwall/app.sh b/small/luci-app-passwall/root/usr/share/passwall/app.sh index 7d1f95afd3..40b657cd68 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1969,7 +1969,7 @@ start() { } [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start set_cache_var "USE_TABLES" "$USE_TABLES" - [ -z $(get_cache_var "ACL_default_dns_port") ] && lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1 + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1 if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) set_cache_var "bak_bridge_nf_ipt" "$bridge_nf_ipt" @@ -1999,7 +1999,7 @@ stop() { source $APP_PATH/helper_smartdns.sh del rm -rf $GLOBAL_DNSMASQ_CONF rm -rf $GLOBAL_DNSMASQ_CONF_PATH - [ -z $(get_cache_var "ACL_default_dns_port") ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 bak_bridge_nf_ipt=$(get_cache_var "bak_bridge_nf_ipt") [ -n "${bak_bridge_nf_ipt}" ] && sysctl -w net.bridge.bridge-nf-call-iptables=${bak_bridge_nf_ipt} >/dev/null 2>&1 bak_bridge_nf_ip6t=$(get_cache_var "bak_bridge_nf_ip6t") diff --git a/small/luci-app-passwall/root/usr/share/passwall/iptables.sh b/small/luci-app-passwall/root/usr/share/passwall/iptables.sh index 9f82a1fb6d..826297bf82 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/iptables.sh @@ -214,11 +214,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -n $(get_cache_var "ACL_${sid}_tcp_node") ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") - [ -n $(get_cache_var "ACL_${sid}_udp_node") ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") - [ -n $(get_cache_var "ACL_${sid}_tcp_port") ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") - [ -n $(get_cache_var "ACL_${sid}_udp_port") ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 diff --git a/small/luci-app-passwall/root/usr/share/passwall/nftables.sh b/small/luci-app-passwall/root/usr/share/passwall/nftables.sh index 3ba40e04e2..27ff6638e2 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -274,11 +274,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -n $(get_cache_var "ACL_${sid}_tcp_node") ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") - [ -n $(get_cache_var "ACL_${sid}_udp_node") ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") - [ -n $(get_cache_var "ACL_${sid}_tcp_port") ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") - [ -n $(get_cache_var "ACL_${sid}_udp_port") ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 @@ -957,7 +957,7 @@ add_firewall_rule() { nft "insert rule $NFTABLE_NAME dstnat ip daddr @${NFTSET_LOCALLIST} jump PSW_DNS" nft "insert rule $NFTABLE_NAME dstnat ip6 daddr @${NFTSET_LOCALLIST6} jump PSW_DNS" else - nft "insert rule $NFTABLE_NAME dstnat jump PSW2_DNS" + nft "insert rule $NFTABLE_NAME dstnat jump PSW_DNS" fi # for ipv4 ipv6 tproxy mark diff --git a/small/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/small/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index f76b368745..a7d403fa7a 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh @@ -82,7 +82,7 @@ test_auto_switch() { local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { - if [ -n $(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") ]; then + if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else #echolog "自动切换检测:未知错误" diff --git a/small/luci-app-passwall2/Makefile b/small/luci-app-passwall2/Makefile index 0f9cb501d6..29fe817222 100644 --- a/small/luci-app-passwall2/Makefile +++ b/small/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=24.12.16 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/small/luci-app-passwall2/root/usr/share/passwall2/iptables.sh b/small/luci-app-passwall2/root/usr/share/passwall2/iptables.sh index 7dc3791683..b81d39288c 100755 --- a/small/luci-app-passwall2/root/usr/share/passwall2/iptables.sh +++ b/small/luci-app-passwall2/root/usr/share/passwall2/iptables.sh @@ -292,9 +292,9 @@ load_acl() { [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS node_remark=$(config_n_get $NODE remarks) - [ -n $(get_cache_var "ACL_${sid}_node") ] && node=$(get_cache_var "ACL_${sid}_node") - [ -n $(get_cache_var "ACL_${sid}_redir_port") ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node") + [ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") [ "$node" = "default" ] && dns_redirect_port=${DNS_REDIRECT_PORT} [ -n "$node" ] && [ "$node" != "default" ] && node_remark=$(config_n_get $node remarks) @@ -806,8 +806,6 @@ add_firewall_rule() { ip -6 rule add fwmark 1 table 100 ip -6 route add local ::/0 dev lo table 100 - filter_direct_node_list - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { local ipt_tmp=$ipt_n [ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m @@ -935,6 +933,8 @@ add_firewall_rule() { # 加载ACLS load_acl + filter_direct_node_list + echolog "防火墙规则加载完成!" } diff --git a/small/luci-app-passwall2/root/usr/share/passwall2/nftables.sh b/small/luci-app-passwall2/root/usr/share/passwall2/nftables.sh index c14c09f960..9473ee1e61 100755 --- a/small/luci-app-passwall2/root/usr/share/passwall2/nftables.sh +++ b/small/luci-app-passwall2/root/usr/share/passwall2/nftables.sh @@ -347,9 +347,9 @@ load_acl() { [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS node_remark=$(config_n_get $NODE remarks) - [ -n $(get_cache_var "ACL_${sid}_node") ] && node=$(get_cache_var "ACL_${sid}_node") - [ -n $(get_cache_var "ACL_${sid}_redir_port") ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") - [ -n $(get_cache_var "ACL_${sid}_dns_port") ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") + [ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node") + [ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") [ "$node" = "default" ] && dns_redirect_port=${DNS_REDIRECT_PORT} [ -n "$node" ] && [ "$node" != "default" ] && node_remark=$(config_n_get $node remarks) @@ -862,8 +862,6 @@ add_firewall_rule() { ip -6 route add local ::/0 dev lo table 100 } - filter_direct_node_list - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { TCP_LOCALHOST_PROXY=$LOCALHOST_PROXY UDP_LOCALHOST_PROXY=$LOCALHOST_PROXY @@ -985,6 +983,8 @@ add_firewall_rule() { # 加载ACLS load_acl + filter_direct_node_list + echolog "防火墙规则加载完成!" } diff --git a/small/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh b/small/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh index ee4e88d8ad..651a473494 100755 --- a/small/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh +++ b/small/luci-app-passwall2/root/usr/share/passwall2/socks_auto_switch.sh @@ -78,7 +78,7 @@ test_auto_switch() { local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { - if [ -n $(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") ]; then + if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else #echolog "自动切换检测:未知错误" diff --git a/small/mihomo/files/mihomo.conf b/small/mihomo/files/mihomo.conf index 4949dbc9c0..68e4095875 100644 --- a/small/mihomo/files/mihomo.conf +++ b/small/mihomo/files/mihomo.conf @@ -3,12 +3,12 @@ config status 'status' config config 'config' option 'init' '1' option 'enabled' '0' + option 'profile' 'subscription:subscription' option 'start_delay' '0' option 'scheduled_restart' '0' option 'cron_expression' '0 3 * * *' - option 'profile' 'subscription:subscription' - option 'mixin' '1' option 'test_profile' '1' + option 'mixin' '1' config proxy 'proxy' option 'transparent_proxy' '1' @@ -57,7 +57,7 @@ config mixin 'mixin' option 'tcp_keep_alive_idle' '600' option 'tcp_keep_alive_interval' '15' option 'ui_name' 'metacubexd' - option 'ui_url' 'https://ghp.ci/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip' + option 'ui_url' 'https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip' option 'api_port' '9090' option 'api_secret' '' option 'selection_cache' '1' @@ -90,10 +90,10 @@ config mixin 'mixin' option 'dns_nameserver_policy' '0' option 'geoip_format' 'dat' option 'geodata_loader' 'memconservative' - option 'geosite_url' 'https://ghp.ci/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat' - option 'geoip_mmdb_url' 'https://ghp.ci/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.metadb' - option 'geoip_dat_url' 'https://ghp.ci/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat' - option 'geoip_asn_url' 'https://ghp.ci/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb' + option 'geosite_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat' + option 'geoip_mmdb_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.metadb' + option 'geoip_dat_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat' + option 'geoip_asn_url' 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb' option 'geox_auto_update' '0' option 'geox_update_interval' '24' option 'mixin_file_content' '0' diff --git a/small/mosdns/Makefile b/small/mosdns/Makefile index b147b33bf1..6eaba528d0 100644 --- a/small/mosdns/Makefile +++ b/small/mosdns/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mosdns PKG_VERSION:=5.3.3 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/IrineSistiana/mosdns/tar.gz/v$(PKG_VERSION)? diff --git a/small/mosdns/patches/200-forward-avoid-picking-same-upstream.patch b/small/mosdns/patches/200-forward-avoid-picking-same-upstream-if-concurrent-2.patch similarity index 58% rename from small/mosdns/patches/200-forward-avoid-picking-same-upstream.patch rename to small/mosdns/patches/200-forward-avoid-picking-same-upstream-if-concurrent-2.patch index a90e1d756f..b03ee0601d 100644 --- a/small/mosdns/patches/200-forward-avoid-picking-same-upstream.patch +++ b/small/mosdns/patches/200-forward-avoid-picking-same-upstream-if-concurrent-2.patch @@ -1,12 +1,12 @@ -From 348bc3f68c676de929e74accc75e62d01ea999be Mon Sep 17 00:00:00 2001 -From: Henry-ZHR -Date: Mon, 16 Sep 2024 10:59:42 +0800 -Subject: [PATCH] forward: avoid picking same upstream +From f5d190ab1542b96688353eeb3d3d5c46fbad8b7c Mon Sep 17 00:00:00 2001 +From: Irine Sistiana <49315432+IrineSistiana@users.noreply.github.com> +Date: Wed, 11 Dec 2024 20:49:42 +0800 +Subject: [PATCH 1/2] forward: avoid picking same upstream if concurrent > 2 --- - plugin/executable/forward/forward.go | 7 ++++++- + plugin/executable/forward/forward.go | 4 +++- plugin/executable/forward/utils.go | 5 ----- - 2 files changed, 6 insertions(+), 6 deletions(-) + 2 files changed, 3 insertions(+), 6 deletions(-) --- a/plugin/executable/forward/forward.go +++ b/plugin/executable/forward/forward.go @@ -14,28 +14,18 @@ Subject: [PATCH] forward: avoid picking same upstream "crypto/tls" "errors" "fmt" -+ "math/rand" ++ "math/rand/v2" "strings" "time" -@@ -251,6 +252,9 @@ func (f *Forward) exchange(ctx context.C - if concurrent > maxConcurrentQueries { - concurrent = maxConcurrentQueries - } -+ if concurrent > len(us) { -+ concurrent = len(us) -+ } - - type res struct { - r *dns.Msg -@@ -261,8 +265,9 @@ func (f *Forward) exchange(ctx context.C +@@ -261,8 +262,9 @@ func (f *Forward) exchange(ctx context.C done := make(chan struct{}) defer close(done) -+ p := rand.Perm(len(us)) ++ r := rand.IntN(len(us)) for i := 0; i < concurrent; i++ { - u := randPick(us) -+ u := us[p[i]] ++ u := us[(r+i)%len(us)] qc := copyPayload(queryPayload) go func(uqid uint32, question dns.Question) { defer pool.ReleaseBuf(qc) diff --git a/small/mosdns/patches/201-upstream-resend-udp-package-every-1s.patch b/small/mosdns/patches/201-upstream-resend-udp-package-every-1s.patch new file mode 100644 index 0000000000..a22ed5f336 --- /dev/null +++ b/small/mosdns/patches/201-upstream-resend-udp-package-every-1s.patch @@ -0,0 +1,36 @@ +From f20baf28be3e18cef0a4695d25db202dbc124300 Mon Sep 17 00:00:00 2001 +From: Irine Sistiana <49315432+IrineSistiana@users.noreply.github.com> +Date: Wed, 11 Dec 2024 20:51:12 +0800 +Subject: [PATCH 2/2] upstream: resend udp package every 1s + +--- + pkg/upstream/transport/conn_traditional.go | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/pkg/upstream/transport/conn_traditional.go ++++ b/pkg/upstream/transport/conn_traditional.go +@@ -124,9 +124,24 @@ func (dc *TraditionalDnsConn) exchange(c + dc.c.SetReadDeadline(time.Now().Add(waitingReplyTimeout)) + } + ++ var resend <-chan time.Time ++ if !dc.isTcp { ++ ticker := time.NewTicker(time.Second) ++ resend = ticker.C ++ defer ticker.Stop() ++ } ++ ++wait: + select { + case <-ctx.Done(): + return nil, context.Cause(ctx) ++ case <-resend: ++ err := dc.writeQuery(q, assignedQid) ++ if err != nil { ++ dc.CloseWithErr(fmt.Errorf("write err, %w", err)) ++ return nil, err ++ } ++ goto wait + case r := <-respChan: + orgId := binary.BigEndian.Uint16(q) + binary.BigEndian.PutUint16(*r, orgId) diff --git a/v2rayn/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs b/v2rayn/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs index 27bc240374..ff50ef64fd 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs @@ -69,7 +69,7 @@ { lstCmd.Add(new CmdItem() { - Cmd = "kwriteconfig5", + Cmd = GetKdeVersion(), Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"] }); } @@ -88,12 +88,13 @@ private static List GetSetCmd4Kde(string type, string host, int port, string configDir) { List lstCmd = []; + var cmd = GetKdeVersion(); if (type.IsNullOrEmpty()) { lstCmd.Add(new() { - Cmd = "kwriteconfig5", + Cmd = cmd, Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"] }); } @@ -101,7 +102,7 @@ { lstCmd.Add(new() { - Cmd = "kwriteconfig5", + Cmd = cmd, Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host] }); } @@ -110,7 +111,7 @@ var type2 = type.Equals("https") ? "http" : type; lstCmd.Add(new CmdItem() { - Cmd = "kwriteconfig5", + Cmd = cmd, Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"] }); } @@ -172,5 +173,14 @@ return isKde; } + private static string GetKdeVersion() + { + var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0"; + return ver switch + { + "6" => "kwriteconfig6", + _ => "kwriteconfig5" + }; + } } } \ No newline at end of file diff --git a/xray-core/infra/conf/transport_internet.go b/xray-core/infra/conf/transport_internet.go index 08f5768e74..e19c145c87 100644 --- a/xray-core/infra/conf/transport_internet.go +++ b/xray-core/infra/conf/transport_internet.go @@ -165,11 +165,13 @@ func (c *WebSocketConfig) Build() (proto.Message, error) { } // Priority (client): host > serverName > address for k, v := range c.Headers { - errors.PrintDeprecatedFeatureWarning(`"host" in "headers"`, `independent "host"`) - if c.Host == "" { - c.Host = v + if strings.ToLower(k) == "host" { + errors.PrintDeprecatedFeatureWarning(`"host" in "headers"`, `independent "host"`) + if c.Host == "" { + c.Host = v + } + delete(c.Headers, k) } - delete(c.Headers, k) } config := &websocket.Config{ Path: path, @@ -436,7 +438,7 @@ func (c *TLSConfig) Build() (proto.Message, error) { config.MaxVersion = c.MaxVersion config.CipherSuites = c.CipherSuites config.Fingerprint = strings.ToLower(c.Fingerprint) - if config.Fingerprint != "" && tls.GetFingerprint(config.Fingerprint) == nil { + if config.Fingerprint != "unsafe" && tls.GetFingerprint(config.Fingerprint) == nil { return nil, errors.New(`unknown fingerprint: `, config.Fingerprint) } config.RejectUnknownSni = c.RejectUnknownSNI @@ -582,15 +584,13 @@ func (c *REALITYConfig) Build() (proto.Message, error) { config.ServerNames = c.ServerNames config.MaxTimeDiff = c.MaxTimeDiff } else { - if c.Fingerprint == "" { - return nil, errors.New(`empty "fingerprint"`) - } - if config.Fingerprint = strings.ToLower(c.Fingerprint); tls.GetFingerprint(config.Fingerprint) == nil { - return nil, errors.New(`unknown "fingerprint": `, config.Fingerprint) - } - if config.Fingerprint == "hellogolang" { + config.Fingerprint = strings.ToLower(c.Fingerprint) + if config.Fingerprint == "unsafe" || config.Fingerprint == "hellogolang" { return nil, errors.New(`invalid "fingerprint": `, config.Fingerprint) } + if tls.GetFingerprint(config.Fingerprint) == nil { + return nil, errors.New(`unknown "fingerprint": `, config.Fingerprint) + } if len(c.ServerNames) != 0 { return nil, errors.New(`non-empty "serverNames", please use "serverName" instead`) } diff --git a/xray-core/transport/internet/tls/tls.go b/xray-core/transport/internet/tls/tls.go index 38b603c02b..4b8fa48652 100644 --- a/xray-core/transport/internet/tls/tls.go +++ b/xray-core/transport/internet/tls/tls.go @@ -165,7 +165,7 @@ func init() { func GetFingerprint(name string) (fingerprint *utls.ClientHelloID) { if name == "" { - return + return &utls.HelloChrome_Auto } if fingerprint = PresetFingerprints[name]; fingerprint != nil { return @@ -191,6 +191,7 @@ var PresetFingerprints = map[string]*utls.ClientHelloID{ "qq": &utls.HelloQQ_Auto, "random": nil, "randomized": nil, + "unsafe": nil, } var ModernFingerprints = map[string]*utls.ClientHelloID{