Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
c8f89d1d59
chore(deps): update npm dependencies 2026-03-28 17:42:27 +00:00
11 changed files with 107 additions and 76 deletions

14
pnpm-lock.yaml generated
View File

@ -88,7 +88,7 @@ importers:
version: 5.3.0
i18next:
specifier: ^26.0.0
version: 26.0.2(typescript@6.0.2)
version: 26.0.1(typescript@6.0.2)
js-yaml:
specifier: ^4.1.1
version: 4.1.1
@ -121,7 +121,7 @@ importers:
version: 7.72.0(react@19.2.4)
react-i18next:
specifier: 17.0.1
version: 17.0.1(i18next@26.0.2(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
version: 17.0.1(i18next@26.0.1(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
react-markdown:
specifier: 10.1.0
version: 10.1.0(@types/react@19.2.14)(react@19.2.4)
@ -2491,8 +2491,8 @@ packages:
engines: {node: '>=18'}
hasBin: true
i18next@26.0.2:
resolution: {integrity: sha512-WsK0SdP+7tGzsxpT+Us1s2nvOyx657DatBodaNZe4KcPTPYzkVfRKUygN69mB+sCbbnifRuKz+Ya5JRzd8DNHw==}
i18next@26.0.1:
resolution: {integrity: sha512-vtz5sXU4+nkCm8yEU+JJ6yYIx0mkg9e68W0G0PXpnOsmzLajNsW5o28DJMqbajxfsfq0gV3XdrBudsDQnwxfsQ==}
peerDependencies:
typescript: ^5 || ^6
peerDependenciesMeta:
@ -6016,7 +6016,7 @@ snapshots:
husky@9.1.7: {}
i18next@26.0.2(typescript@6.0.2):
i18next@26.0.1(typescript@6.0.2):
dependencies:
'@babel/runtime': 7.29.2
optionalDependencies:
@ -6656,11 +6656,11 @@ snapshots:
dependencies:
react: 19.2.4
react-i18next@17.0.1(i18next@26.0.2(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2):
react-i18next@17.0.1(i18next@26.0.1(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2):
dependencies:
'@babel/runtime': 7.29.2
html-parse-stringify: 3.0.1
i18next: 26.0.2(typescript@6.0.2)
i18next: 26.0.1(typescript@6.0.2)
react: 19.2.4
use-sync-external-store: 1.6.0(react@19.2.4)
optionalDependencies:

View File

@ -100,7 +100,8 @@ async function resolveUpdater() {
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url = 'https://update.hwdns.net/' + value.url
updateDataNew.platforms[key].url =
'https://download.clashverge.dev/' + value.url
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`)
}

View File

@ -204,7 +204,7 @@ async function processRelease(github, options, tag, isAlpha) {
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
'https://update.hwdns.net/' + value.url
'https://download.clashverge.dev/' + value.url
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`)
}

View File

@ -32,8 +32,8 @@
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK",
"endpoints": [
"https://update.hwdns.net/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://gh-proxy.org/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://gh-proxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update.json"
],
"windows": {

View File

@ -25,7 +25,7 @@
"active": true,
"dialog": false,
"endpoints": [
"https://update.hwdns.net/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"

View File

@ -25,7 +25,7 @@
"active": true,
"dialog": false,
"endpoints": [
"https://update.hwdns.net/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"

View File

@ -25,7 +25,7 @@
"active": true,
"dialog": false,
"endpoints": [
"https://update.hwdns.net/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"

View File

@ -7,17 +7,13 @@ import {
} from '@mui/icons-material'
import { Typography, Stack, Divider, Chip, IconButton } from '@mui/material'
import { useLockFn } from 'ahooks'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useReducer } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
import { useServiceInstaller } from '@/hooks/use-service-installer'
import { useSystemState } from '@/hooks/use-system-state'
import {
useUpdate,
updateLastCheckTime,
readLastCheckTime,
} from '@/hooks/use-update'
import { useUpdate } from '@/hooks/use-update'
import { useVerge } from '@/hooks/use-verge'
import { getSystemInfo } from '@/services/cmds'
import { showNotice } from '@/services/notice-service'
@ -25,6 +21,29 @@ import { version as appVersion } from '@root/package.json'
import { EnhancedCard } from './enhanced-card'
interface SystemState {
osInfo: string
lastCheckUpdate: string
}
type SystemStateAction =
| { type: 'set-os-info'; payload: string }
| { type: 'set-last-check-update'; payload: string }
const systemStateReducer = (
state: SystemState,
action: SystemStateAction,
): SystemState => {
switch (action.type) {
case 'set-os-info':
return { ...state, osInfo: action.payload }
case 'set-last-check-update':
return { ...state, lastCheckUpdate: action.payload }
default:
return state
}
}
export const SystemInfoCard = () => {
const { t } = useTranslation()
const { verge, patchVerge } = useVerge()
@ -32,18 +51,28 @@ export const SystemInfoCard = () => {
const { isAdminMode, isSidecarMode } = useSystemState()
const { installServiceAndRestartCore } = useServiceInstaller()
// 自动检查更新逻辑lastCheckUpdate 由 useUpdate 统一管理)
const { checkUpdate: triggerCheckUpdate, lastCheckUpdate } = useUpdate(true)
// 自动检查更新逻辑
const { checkUpdate: triggerCheckUpdate } = useUpdate(true, {
onSuccess: () => {
const now = Date.now()
localStorage.setItem('last_check_update', now.toString())
dispatchSystemState({
type: 'set-last-check-update',
payload: new Date(now).toLocaleString(),
})
},
})
const [osInfo, setOsInfo] = useState('')
const lastCheckUpdateText = useMemo(
() => (lastCheckUpdate ? new Date(lastCheckUpdate).toLocaleString() : '-'),
[lastCheckUpdate],
)
// 系统信息状态
const [systemState, dispatchSystemState] = useReducer(systemStateReducer, {
osInfo: '',
lastCheckUpdate: '-',
})
// 初始化系统信息
useEffect(() => {
let timeoutId: number | undefined
getSystemInfo()
.then((info) => {
const lines = info.split('\n')
@ -58,23 +87,49 @@ export const SystemInfoCard = () => {
sysVersion = sysVersion.substring(sysName.length).trim()
}
setOsInfo(`${sysName} ${sysVersion}`)
dispatchSystemState({
type: 'set-os-info',
payload: `${sysName} ${sysVersion}`,
})
}
})
.catch(console.error)
}, [])
// 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
useEffect(() => {
if (!verge?.auto_check_update) return
if (readLastCheckTime() !== null) return
// 获取最后检查更新时间
const lastCheck = localStorage.getItem('last_check_update')
if (lastCheck) {
try {
const timestamp = parseInt(lastCheck, 10)
if (!isNaN(timestamp)) {
dispatchSystemState({
type: 'set-last-check-update',
payload: new Date(timestamp).toLocaleString(),
})
}
} catch (e) {
console.error('Error parsing last check update time', e)
}
} else if (verge?.auto_check_update) {
// 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
const now = Date.now()
localStorage.setItem('last_check_update', now.toString())
dispatchSystemState({
type: 'set-last-check-update',
payload: new Date(now).toLocaleString(),
})
updateLastCheckTime()
const timeoutId = window.setTimeout(() => {
triggerCheckUpdate().catch(console.error)
}, 5000)
return () => window.clearTimeout(timeoutId)
}, [verge?.auto_check_update, triggerCheckUpdate])
timeoutId = window.setTimeout(() => {
if (verge?.auto_check_update) {
triggerCheckUpdate().catch(console.error)
}
}, 5000)
}
return () => {
if (timeoutId !== undefined) {
window.clearTimeout(timeoutId)
}
}
}, [verge?.auto_check_update, dispatchSystemState, triggerCheckUpdate])
// 导航到设置页面
const goToSettings = useCallback(() => {
@ -102,6 +157,12 @@ export const SystemInfoCard = () => {
const onCheckUpdate = useLockFn(async () => {
try {
const info = await triggerCheckUpdate()
const now = Date.now()
localStorage.setItem('last_check_update', now.toString())
dispatchSystemState({
type: 'set-last-check-update',
payload: new Date(now).toLocaleString(),
})
if (!info?.available) {
showNotice.success(
'settings.components.verge.advanced.notifications.latestVersion',
@ -219,7 +280,7 @@ export const SystemInfoCard = () => {
{t('home.components.systemInfo.fields.osInfo')}
</Typography>
<Typography variant="body2" fontWeight="medium">
{osInfo}
{systemState.osInfo}
</Typography>
</Stack>
<Divider />
@ -280,7 +341,7 @@ export const SystemInfoCard = () => {
'&:hover': { opacity: 0.7 },
}}
>
{lastCheckUpdateText}
{systemState.lastCheckUpdate}
</Typography>
</Stack>
<Divider />

View File

@ -78,6 +78,7 @@ const SettingClash = ({ onError }: Props) => {
const handleDnsToggle = useLockFn(async (enable: boolean) => {
try {
setDnsSettingsEnabled(enable)
localStorage.setItem('dns_settings_enabled', String(enable))
await patchVerge({ enable_dns_settings: enable })
await invoke('apply_dns_config', { apply: enable })
setTimeout(() => {
@ -85,6 +86,7 @@ const SettingClash = ({ onError }: Props) => {
}, 500)
} catch (err: any) {
setDnsSettingsEnabled(!enable)
localStorage.setItem('dns_settings_enabled', String(!enable))
showNotice.error(err)
await patchVerge({ enable_dns_settings: !enable }).catch(() => {})
throw err

View File

@ -4,7 +4,6 @@ import { useCallback, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { DialogRef, TooltipIcon } from '@/components/base'
import { updateLastCheckTime } from '@/hooks/use-update'
import {
exitApp,
exportDiagnosticInfo,
@ -46,7 +45,6 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
const onCheckUpdate = async () => {
try {
const info = await checkUpdate()
updateLastCheckTime()
if (!info?.available) {
showNotice.success(
'settings.components.verge.advanced.notifications.latestVersion',

View File

@ -1,4 +1,4 @@
import useSWR, { mutate as globalMutate, SWRConfiguration } from 'swr'
import useSWR, { SWRConfiguration } from 'swr'
import { checkUpdateSafe } from '@/services/update'
@ -12,26 +12,6 @@ export interface UpdateInfo {
downloadAndInstall: (onEvent?: any) => Promise<void>
}
// --- Last check timestamp (shared via SWR + localStorage) ---
const LAST_CHECK_KEY = 'last_check_update'
export const readLastCheckTime = (): number | null => {
const stored = localStorage.getItem(LAST_CHECK_KEY)
if (!stored) return null
const ts = parseInt(stored, 10)
return isNaN(ts) ? null : ts
}
export const updateLastCheckTime = (timestamp?: number): number => {
const now = timestamp ?? Date.now()
localStorage.setItem(LAST_CHECK_KEY, now.toString())
globalMutate(LAST_CHECK_KEY, now, false)
return now
}
// --- useUpdate hook ---
export const useUpdate = (
enabled: boolean = true,
options?: SWRConfiguration,
@ -56,22 +36,11 @@ export const useUpdate = (
refreshInterval: 24 * 60 * 60 * 1000, // 24 hours
dedupingInterval: 60 * 60 * 1000, // 1 hour
...options,
onSuccess: (...args) => {
updateLastCheckTime()
options?.onSuccess?.(...args)
},
})
// Shared last check timestamp
const { data: lastCheckUpdate } = useSWR(LAST_CHECK_KEY, readLastCheckTime, {
revalidateOnFocus: false,
revalidateOnReconnect: false,
})
return {
updateInfo,
checkUpdate,
loading: isValidating,
lastCheckUpdate: lastCheckUpdate ?? null,
}
}