From cb1d8c61413d961ac84b8596bea12217fb474ba8 Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Fri, 2 Aug 2024 19:07:39 +0800 Subject: [PATCH] support pac mode --- package.json | 2 + pnpm-lock.yaml | 102 ++++++++++++++++++ src/main/config/app.ts | 5 + src/main/core/tray.ts | 14 ++- src/main/index.ts | 6 ++ src/main/resolve/init.ts | 6 ++ src/main/resolve/server.ts | 49 +++++++++ src/main/resolve/sysproxy.ts | 68 +++++++++++- .../base-setting-card.tsx} | 0 .../base-setting-item.tsx} | 0 .../components/sider/sysproxy-switcher.tsx | 8 +- .../src/components/sider/tun-switcher.tsx | 1 - .../components/sysproxy/pac-editor-modal.tsx | 63 +++++++++++ src/renderer/src/pages/settings.tsx | 4 +- src/renderer/src/pages/syspeoxy.tsx | 92 +++++++++++++++- src/shared/types.d.ts | 5 +- 16 files changed, 410 insertions(+), 15 deletions(-) create mode 100644 src/main/resolve/server.ts rename src/renderer/src/components/{settings/setting-card.tsx => base/base-setting-card.tsx} (100%) rename src/renderer/src/components/{settings/setting-item.tsx => base/base-setting-item.tsx} (100%) create mode 100644 src/renderer/src/components/sysproxy/pac-editor-modal.tsx diff --git a/package.json b/package.json index eb6e44f..c50436d 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,14 @@ "dependencies": { "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^3.0.0", + "@mihomo-party/sysproxy": "^1.0.1", "@nextui-org/react": "^2.4.6", "axios": "^1.7.2", "electron-updater": "^6.2.1", "framer-motion": "^11.3.19", "next-themes": "^0.3.0", "react-icons": "^5.2.1", + "react-monaco-editor": "^0.55.0", "react-router-dom": "^6.25.1", "swr": "^2.2.5", "ws": "^8.18.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b1dca6..aabe947 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@electron-toolkit/utils': specifier: ^3.0.0 version: 3.0.0(electron@31.3.1) + '@mihomo-party/sysproxy': + specifier: ^1.0.1 + version: 1.0.1 '@nextui-org/react': specifier: ^2.4.6 version: 2.4.6(@types/react@18.3.3)(framer-motion@11.3.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7) @@ -32,6 +35,9 @@ importers: react-icons: specifier: ^5.2.1 version: 5.2.1(react@18.3.1) + react-monaco-editor: + specifier: ^0.55.0 + version: 0.55.0(@types/react@18.3.3)(monaco-editor@0.44.0)(react@18.3.1) react-router-dom: specifier: ^6.25.1 version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -522,6 +528,52 @@ packages: resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} engines: {node: '>= 10.0.0'} + '@mihomo-party/sysproxy-darwin-arm64@1.0.1': + resolution: {integrity: sha512-VNrJLIXpgQBesNw9Ng3IgHK8L9JS4hHIXe/cn3ODHjq2kDXar1Q1qcXAHpi8ZRiw6Q1H5pewRl+EBb+ZCAHInQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@mihomo-party/sysproxy-darwin-x64@1.0.1': + resolution: {integrity: sha512-OdkcgjXscnos4hQ6YmFtxyTJZde0QjNJpgyCW826JYyjPzWPTtjftCnLWFVnSIU6U0jAfW+iSF8B1qmj3+db+w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@mihomo-party/sysproxy-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-NHzw7lI4oqANuYoU+QmwmEwntYDakkgYBZ1xf8JF48eIKoff48Nw0c3+lF57U0NNVy+s1xdPlZwmPABHe9fmhg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@mihomo-party/sysproxy-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-BYKTHGMxxxCMjaeUV5VH/Ikq1QMC0vJrQ9dX/LXnYN2++wL/bz8cKs3K2FgzUN2rczDj/7yQGmlhLqUgEQ6Wqg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@mihomo-party/sysproxy-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-d467s+fpXYUafJ1rEiqeCpbEC3iL25+3SXIReTg3264irq9H439+S/BBqENAoenq30UTp58r8f2Cr93LcsqLSQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@mihomo-party/sysproxy-win32-ia32-msvc@1.0.1': + resolution: {integrity: sha512-ZXtNYV+egkb0DdQrAfsEwUH25S4PRyuh9ziSW9TuqQW9d+La8SOMxPut9jbMmyFnKnbvXtcibqXxKpxDHPspoQ==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@mihomo-party/sysproxy-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-lJR8sIN3ciFdKs5A2oy+nKhiFMseDxPiP1tFDhFYwnzgqTCkZBTadH6km+TMP1VWseYT1QG/sDG6U2jVz126bg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@mihomo-party/sysproxy@1.0.1': + resolution: {integrity: sha512-VLuplU5WEsexJJZWcHut8zO/l8o1vZFpyisMhL1PwAaYwsTEOt4NGtkXrTB1HkNTvmsdhAFPk7EU7XTbs3QPmA==} + engines: {node: '>= 10'} + '@nextui-org/accordion@2.0.38': resolution: {integrity: sha512-kFCZU1VaKkUI295Fg3NxuQR2+kZ5vTH4ftIs0oByrOs0+l14dVQGFOd9ZV402fHNykZJt7Sk6oWjTp4Qwl83JA==} peerDependencies: @@ -3258,6 +3310,9 @@ packages: engines: {node: '>=10'} hasBin: true + monaco-editor@0.44.0: + resolution: {integrity: sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==} + ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -3554,6 +3609,13 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-monaco-editor@0.55.0: + resolution: {integrity: sha512-GdEP0Q3Rn1dczfKEEyY08Nes5plWwIYU4sWRBQO0+jsQWQsKMHKCC6+hPRwR7G/4aA3V/iU9jSmWPzVJYMVFSQ==} + peerDependencies: + '@types/react': '>=16 <= 18' + monaco-editor: ^0.44.0 + react: '>=16 <= 18' + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -4674,6 +4736,37 @@ snapshots: transitivePeerDependencies: - supports-color + '@mihomo-party/sysproxy-darwin-arm64@1.0.1': + optional: true + + '@mihomo-party/sysproxy-darwin-x64@1.0.1': + optional: true + + '@mihomo-party/sysproxy-linux-arm64-gnu@1.0.1': + optional: true + + '@mihomo-party/sysproxy-linux-x64-gnu@1.0.1': + optional: true + + '@mihomo-party/sysproxy-win32-arm64-msvc@1.0.1': + optional: true + + '@mihomo-party/sysproxy-win32-ia32-msvc@1.0.1': + optional: true + + '@mihomo-party/sysproxy-win32-x64-msvc@1.0.1': + optional: true + + '@mihomo-party/sysproxy@1.0.1': + optionalDependencies: + '@mihomo-party/sysproxy-darwin-arm64': 1.0.1 + '@mihomo-party/sysproxy-darwin-x64': 1.0.1 + '@mihomo-party/sysproxy-linux-arm64-gnu': 1.0.1 + '@mihomo-party/sysproxy-linux-x64-gnu': 1.0.1 + '@mihomo-party/sysproxy-win32-arm64-msvc': 1.0.1 + '@mihomo-party/sysproxy-win32-ia32-msvc': 1.0.1 + '@mihomo-party/sysproxy-win32-x64-msvc': 1.0.1 + '@nextui-org/accordion@2.0.38(@nextui-org/system@2.2.5(@nextui-org/theme@2.2.9(tailwindcss@3.4.7))(framer-motion@11.3.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@nextui-org/theme@2.2.9(tailwindcss@3.4.7))(framer-motion@11.3.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@nextui-org/aria-utils': 2.0.24(@nextui-org/theme@2.2.9(tailwindcss@3.4.7))(framer-motion@11.3.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8574,6 +8667,8 @@ snapshots: mkdirp@3.0.1: {} + monaco-editor@0.44.0: {} + ms@2.1.2: {} ms@2.1.3: {} @@ -8847,6 +8942,13 @@ snapshots: react-is@16.13.1: {} + react-monaco-editor@0.55.0(@types/react@18.3.3)(monaco-editor@0.44.0)(react@18.3.1): + dependencies: + '@types/react': 18.3.3 + monaco-editor: 0.44.0 + prop-types: 15.8.1 + react: 18.3.1 + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): diff --git a/src/main/config/app.ts b/src/main/config/app.ts index 748579b..c6d9c67 100644 --- a/src/main/config/app.ts +++ b/src/main/config/app.ts @@ -12,6 +12,11 @@ export function getAppConfig(force = false): IAppConfig { } export function setAppConfig(patch: Partial): void { + if (patch.sysProxy) { + const oldSysProxy = appConfig.sysProxy || {} + const newSysProxy = Object.assign(oldSysProxy, patch.sysProxy) + patch.sysProxy = newSysProxy + } appConfig = Object.assign(appConfig, patch) fs.writeFileSync(appConfigPath(), yaml.stringify(appConfig)) } diff --git a/src/main/core/tray.ts b/src/main/core/tray.ts index e786219..1a9dbde 100644 --- a/src/main/core/tray.ts +++ b/src/main/core/tray.ts @@ -68,10 +68,16 @@ const buildContextMenu = (): Menu => { checked: getAppConfig().sysProxy?.enable ?? false, click: (item): void => { const enable = item.checked - setAppConfig({ sysProxy: { enable } }) - triggerSysProxy(enable) - window?.webContents.send('appConfigUpdated') - updateTrayMenu() + try { + triggerSysProxy(enable) + setAppConfig({ sysProxy: { enable } }) + window?.webContents.send('appConfigUpdated') + } catch (e) { + setAppConfig({ sysProxy: { enable: !enable } }) + console.error(e) + } finally { + updateTrayMenu() + } } }, { diff --git a/src/main/index.ts b/src/main/index.ts index 007eef7..e05bdde 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -2,6 +2,7 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { registerIpcMainHandlers } from './utils/cmds' import { app, shell, BrowserWindow } from 'electron' import { stopCore, startCore } from './core/manager' +import { triggerSysProxy } from './resolve/sysproxy' import icon from '../../resources/icon.png?asset' import { mihomoTraffic } from './core/mihomoApi' import { createTray } from './core/tray' @@ -35,6 +36,7 @@ if (!gotTheLock) { app.on('before-quit', () => { stopCore() + triggerSysProxy(false) app.exit() }) @@ -86,6 +88,10 @@ function createWindow(): void { } }) + window.on('resize', () => { + window?.webContents.send('resize') + }) + window.on('close', (event) => { event.preventDefault() window?.hide() diff --git a/src/main/resolve/init.ts b/src/main/resolve/init.ts index 9e42dc6..d77dc57 100644 --- a/src/main/resolve/init.ts +++ b/src/main/resolve/init.ts @@ -18,6 +18,9 @@ import { import yaml from 'yaml' import fs from 'fs' import path from 'path' +import { startPacServer } from './server' +import { triggerSysProxy } from './sysproxy' +import { getAppConfig } from '../config' function initDirs(): void { if (!fs.existsSync(dataDir)) { @@ -64,4 +67,7 @@ export function init(): void { initDirs() initConfig() initFiles() + startPacServer().then(() => { + triggerSysProxy(getAppConfig().sysProxy.enable) + }) } diff --git a/src/main/resolve/server.ts b/src/main/resolve/server.ts new file mode 100644 index 0000000..8cc958a --- /dev/null +++ b/src/main/resolve/server.ts @@ -0,0 +1,49 @@ +import { getAppConfig, getControledMihomoConfig } from '../config' +import http from 'http' +import net from 'net' + +export let pacPort: number + +const defaultPacScript = ` +function FindProxyForURL(url, host) { + return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"; +} +` + +function findAvailablePort(startPort: number): Promise { + return new Promise((resolve, reject) => { + const server = net.createServer() + server.unref() + server.on('error', (err) => { + if (startPort <= 65535) { + resolve(findAvailablePort(startPort + 1)) + } else { + reject(err) + } + }) + + server.listen(startPort, () => { + // 端口可用 + server.close(() => { + resolve(startPort) + }) + }) + }) +} + +export async function startPacServer(): Promise { + pacPort = await findAvailablePort(10000) + const server = http + .createServer((_req, res) => { + const { + sysProxy: { pacScript } + } = getAppConfig() + const { 'mixed-port': port = 7890 } = getControledMihomoConfig() + let script = pacScript || defaultPacScript + script = script.replaceAll('%mixed-port%', port.toString()) + res.writeHead(200, { 'Content-Type': 'application/x-ns-proxy-autoconfig' }) + res.end(script) + }) + .listen(pacPort) + server.unref() +} diff --git a/src/main/resolve/sysproxy.ts b/src/main/resolve/sysproxy.ts index 8296b48..50f1f0b 100644 --- a/src/main/resolve/sysproxy.ts +++ b/src/main/resolve/sysproxy.ts @@ -1,7 +1,49 @@ -import { getControledMihomoConfig } from '../config' +import { triggerAutoProxy, triggerManualProxy } from '@mihomo-party/sysproxy' +import { getAppConfig, getControledMihomoConfig } from '../config' +import { pacPort } from './server' + +let defaultBypass: string[] +if (process.platform === 'linux') + defaultBypass = ['localhost', '127.0.0.1', '192.168.0.0/16', '10.0.0.0/8', '172.16.0.0/12', '::1'] +if (process.platform === 'darwin') + defaultBypass = [ + '127.0.0.1', + '192.168.0.0/16', + '10.0.0.0/8', + '172.16.0.0/12', + 'localhost', + '*.local', + '*.crashlytics.com', + '' + ] +if (process.platform === 'win32') + defaultBypass = [ + 'localhost', + '127.*', + '192.168.*', + '10.*', + '172.16.*', + '172.17.*', + '172.18.*', + '172.19.*', + '172.20.*', + '172.21.*', + '172.22.*', + '172.23.*', + '172.24.*', + '172.25.*', + '172.26.*', + '172.27.*', + '172.28.*', + '172.29.*', + '172.30.*', + '172.31.*', + '' + ] export function triggerSysProxy(enable: boolean): void { if (enable) { + disableSysProxy() enableSysProxy() } else { disableSysProxy() @@ -9,9 +51,29 @@ export function triggerSysProxy(enable: boolean): void { } export function enableSysProxy(): void { - console.log('enableSysProxy', getControledMihomoConfig()['mixed-port']) + const { sysProxy } = getAppConfig() + const { mode, host, bypass = defaultBypass } = sysProxy + const { 'mixed-port': port = 7890 } = getControledMihomoConfig() + + switch (mode || 'manual') { + case 'auto': { + triggerAutoProxy(true, `http://${host || '127.0.0.1'}:${pacPort}/pac`) + break + } + + case 'manual': { + triggerManualProxy( + true, + host || '127.0.0.1', + port, + bypass.join(process.platform === 'win32' ? ';' : ',') + ) + break + } + } } export function disableSysProxy(): void { - console.log('disableSysProxy') + triggerAutoProxy(false, '') + triggerManualProxy(false, '', 0, '') } diff --git a/src/renderer/src/components/settings/setting-card.tsx b/src/renderer/src/components/base/base-setting-card.tsx similarity index 100% rename from src/renderer/src/components/settings/setting-card.tsx rename to src/renderer/src/components/base/base-setting-card.tsx diff --git a/src/renderer/src/components/settings/setting-item.tsx b/src/renderer/src/components/base/base-setting-item.tsx similarity index 100% rename from src/renderer/src/components/settings/setting-item.tsx rename to src/renderer/src/components/base/base-setting-item.tsx diff --git a/src/renderer/src/components/sider/sysproxy-switcher.tsx b/src/renderer/src/components/sider/sysproxy-switcher.tsx index 6f5e1e3..6959a28 100644 --- a/src/renderer/src/components/sider/sysproxy-switcher.tsx +++ b/src/renderer/src/components/sider/sysproxy-switcher.tsx @@ -15,8 +15,12 @@ const SysproxySwitcher: React.FC = () => { const { enable } = sysProxy || {} const onChange = async (enable: boolean): Promise => { - await patchAppConfig({ sysProxy: { enable } }) - await triggerSysProxy(enable) + try { + await triggerSysProxy(enable) + await patchAppConfig({ sysProxy: { enable } }) + } catch (e) { + console.log(e) + } } return ( diff --git a/src/renderer/src/components/sider/tun-switcher.tsx b/src/renderer/src/components/sider/tun-switcher.tsx index 2796936..2e97015 100644 --- a/src/renderer/src/components/sider/tun-switcher.tsx +++ b/src/renderer/src/components/sider/tun-switcher.tsx @@ -15,7 +15,6 @@ const TunSwitcher: React.FC = () => { const { tun } = controledMihomoConfig || {} const { enable } = tun || {} - console.log('controledMihomoConfig', controledMihomoConfig) const onChange = async (enable: boolean): Promise => { await patchControledMihomoConfig({ tun: { enable } }) await patchMihomoConfig({ tun: { enable } }) diff --git a/src/renderer/src/components/sysproxy/pac-editor-modal.tsx b/src/renderer/src/components/sysproxy/pac-editor-modal.tsx new file mode 100644 index 0000000..16eca5e --- /dev/null +++ b/src/renderer/src/components/sysproxy/pac-editor-modal.tsx @@ -0,0 +1,63 @@ +import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react' +import React, { useState } from 'react' +import MonacoEditor, { monaco } from 'react-monaco-editor' +import { useTheme } from 'next-themes' +interface Props { + script: string + onCancel: () => void + onConfirm: (script: string) => void +} +const PacEditorViewer: React.FC = (props) => { + const { script, onCancel, onConfirm } = props + const [currData, setCurrData] = useState(script) + const { theme } = useTheme() + + const editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor): void => { + window.electron.ipcRenderer.on('resize', () => { + editor.layout() + }) + } + + const editorWillUnmount = (editor: monaco.editor.IStandaloneCodeEditor): void => { + window.electron.ipcRenderer.removeAllListeners('resize') + editor.dispose() + } + + return ( + + + 编辑PAC脚本 + + setCurrData(value)} + /> + + + + + + + + ) +} + +export default PacEditorViewer diff --git a/src/renderer/src/pages/settings.tsx b/src/renderer/src/pages/settings.tsx index 6581a78..ed3b57e 100644 --- a/src/renderer/src/pages/settings.tsx +++ b/src/renderer/src/pages/settings.tsx @@ -1,7 +1,7 @@ import { Button, Switch } from '@nextui-org/react' import BasePage from '@renderer/components/base/base-page' -import SettingCard from '@renderer/components/settings/setting-card' -import SettingItem from '@renderer/components/settings/setting-item' +import SettingCard from '@renderer/components/base/base-setting-card' +import SettingItem from '@renderer/components/base/base-setting-item' import { useAppConfig } from '@renderer/hooks/use-config' import { checkAutoRun, enableAutoRun, disableAutoRun } from '@renderer/utils/ipc' import { IoLogoGithub } from 'react-icons/io5' diff --git a/src/renderer/src/pages/syspeoxy.tsx b/src/renderer/src/pages/syspeoxy.tsx index 533d080..7c217a1 100644 --- a/src/renderer/src/pages/syspeoxy.tsx +++ b/src/renderer/src/pages/syspeoxy.tsx @@ -1,5 +1,95 @@ +import { Button, Input, Tab, Tabs } from '@nextui-org/react' +import BasePage from '@renderer/components/base/base-page' +import SettingCard from '@renderer/components/base/base-setting-card' +import SettingItem from '@renderer/components/base/base-setting-item' +import PacEditorViewer from '@renderer/components/sysproxy/pac-editor-modal' +import { useAppConfig } from '@renderer/hooks/use-config' +import { triggerSysProxy } from '@renderer/utils/ipc' +import { Key, useState } from 'react' +import React from 'react' + +const defaultPacScript = ` +function FindProxyForURL(url, host) { + return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"; +} +` + const Sysproxy: React.FC = () => { - return
Sysproxy
+ const { appConfig, patchAppConfig } = useAppConfig() + const { sysProxy } = appConfig || { sysProxy: { enable: false } } + + const [values, setValues] = useState(sysProxy) + const [openPacEditor, setOpenPacEditor] = useState(false) + const onSave = async (): Promise => { + // check valid TODO + await patchAppConfig({ sysProxy: values }) + try { + await triggerSysProxy(true) + await patchAppConfig({ sysProxy: { enable: true } }) + } catch (e) { + await patchAppConfig({ sysProxy: { enable: false } }) + console.error(e) + } + } + + return ( + + 保存 + + } + > + {openPacEditor && ( + setOpenPacEditor(false)} + onConfirm={(script: string) => { + setValues({ ...values, pacScript: script }) + setOpenPacEditor(false) + }} + /> + )} + + + { + setValues({ ...values, host: v }) + }} + /> + + + setValues({ ...values, mode: key as SysProxyMode })} + > + + + + + + + + + + ) } export default Sysproxy diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 2e02b11..ddf87f6 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -1,6 +1,6 @@ type OutboundMode = 'rule' | 'global' | 'direct' type LogLevel = 'info' | 'debug' | 'warn' | 'error' | 'silent' - +type SysProxyMode = 'auto' | 'manual' interface IMihomoVersion { version: string meta: boolean @@ -65,7 +65,8 @@ interface IMihomoConnectionDetail { interface ISysProxyConfig { enable: boolean - mode?: 'auto' | 'manual' + host?: string + mode?: SysProxyMode bypass?: string[] pacScript?: string }