mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-28 09:12:08 +08:00
5059cdcb9d2f20cec1b1085dcc351f641f5d9b34
511
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
df79ed3efb |
Revert "feat(dns): protect provider DNS from unconfirmed overrides (#7902)"
This reverts commit
|
||
|
|
c599f5547e |
fix(proxy): validate user-entered URLs via isValidUrl
Delay test inputs now reject non-http(s) URLs with a warning toast and fall back to the default URL instead of erroring every node in the core. Subscription import and profile card host parsing reuse the same validator, fixing bare-domain URLs shown as local files and credential-bearing URLs leaking into the card. |
||
|
|
9a879dd8d8 |
fix(service): fall back to elevated sidecar on path permission rejection
Preserve TUN settings and restore proxy operation after fallback. Deliver fallback notices after UI subscription and stop retrying deterministic bundle refusals. Publish fallback state atomically and avoid conflicting service startup notifications. |
||
|
|
35a2b6c75c |
feat(dns): protect provider DNS from unconfirmed overrides (#7902)
Fixes #7292 |
||
|
|
c3ceea6258 | refactor: extract sidebar into standalone component (#7859) | ||
|
|
4ed474706a |
refactor(frontend): consolidate query state ownership
Consolidate ordinary query snapshots on SWR and make Profiles own its query key, cache mutation, and invalidation policy. Impact: - remove the generic synchronous query Map while keeping dedicated Mihomo WebSocket snapshots - eliminate duplicate Profiles refreshes while preserving retries and the 800 ms event throttle - preserve preload-backed Verge updates and system proxy rollback behavior - scope uptime polling to the Home Clash info card instead of the app lifetime - leave RunState, Connections, Traffic, backend, and IPC contracts unchanged - reduce frontend code by 72 net lines without adding dependencies |
||
|
|
d8b94d12dd | perf(core): batch close connections on mode change | ||
|
|
836199cfe2 |
fix: unify font-family usage across GUI
- Remove hardcoded body font-family from index.scss, use MUI theme dt.font_family instead - Extract monospace font stack to shared MONACO_FONT_FAMILY constant in utils/font-family.ts - Add platform check for twemoji mozilla in ip-info-card.tsx - Consolidate 5 Monaco Editor font-family declarations into single constant |
||
|
|
9cb4ce6cb1 |
refactor: simplify side menu layout and drag-and-drop logic (#7838)
* refactor: remove duplicated list wrapper in side menu * refactor: simplify side menu layout and drag drop logic - Always render DragDropProvider and pass disabled prop to menu items - Remove redundant layout branches and unused sortable component |
||
|
|
b6de05ffe4 |
refactor: migrate to @dnd-kit/react and simplify sortable components (#7819)
* refactor: migrate to @dnd-kit/react and simplify sortable components * chore: enable css formatting in biome.json * refactor(profile): simplify icon rendering logic and add alt text * style(profiles): add overflow hidden to profile grid container * refactor(profile): add radix for parseInt and improve type safety in profiles * docs: update changelog with drag-and-drop styling improvements * refactor(profile): move hasValidName function out of ProxiesEditorViewer * refactor(proxy): refactor proxy chain into sortable components * feat(proxy): add drop state styling and arrow animations to proxy chain * style(profiles): reduce horizontal padding in profile grid * feat(profile): add vertical margin to editor viewer items * chore: refresh pnpm lockfile * fix: preserve drag and drop behavior --------- Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com> |
||
|
|
695fadf21e |
fix(security): restrict external URL opening
Close: 7800 |
||
|
|
6eaf65ff0f |
fix(profiles): stabilize drag reorder motion
Close: 7798 |
||
|
|
2717aaadad |
fix: media unlock checking behavior (#7778)
* fix: Gemini test * naming unlock * test type * refactor: deduplicate media unlock checks * fix: run media unlock checks individually * fix(media-unlock): satisfy clippy const lint * fix: stream media unlock test results * fix: streamline media unlock checks * fix: force HTTP/1 for media unlock checks * fix: limit concurrent media unlock checks * feat: allow concurrent media unlock item checks |
||
|
|
9b9feb9a39 | fix: handle proxy cleanup failures during app exit | ||
|
|
e15ddab542 | test: trim redundant test coverage | ||
|
|
807f9a206d | chore: trim excessive comments | ||
|
|
daadb126e0 |
feat: allow manually unfixing proxy nodes (#7756)
* feat(proxy): add ability to clear persisted node selection for groups * feat(hooks): make proxy selection operations asynchronous * chore: update tauri-plugin-mihomo deps * refactor: rename clear_selected_node to forget_selected_node * refactor(hooks): rename isFixed to isFixedProxy in useProxySelection * docs: update changelog with manual node cancellation support * chore(layout): remove dev-only mihomo websocket debugging interval |
||
|
|
22947632c0 |
refactor: Rewrite and improve sysproxy logic (#7744)
* fix(cmd): preserve anyhow context in coded errors Use alternate error formatting so coded failures retain the full anyhow context chain without changing their wire format. * fix(macos): skip redundant proxy disable writes When both proxy modes are off, read macOS state first and skip networksetup if the OS is already clean. Update the guard target only after a successful write. * feat(proxy): classify system proxy failures Attach stable, actionable proxy failure codes to anyhow chains while preserving the original diagnostic causes. * feat(cmd): return structured command failures Replace encoded error strings with serializable code and detail fields, and update frontend notice consumers to handle the structured shape. * fix(scripts): use the js-yaml namespace import Import js-yaml through its ESM namespace so the i18n cleanup script can access load and dump. * feat(proxy): localize classified proxy failures Map privilege and direct-fallback codes to localized explanations, and let mapped causes outrank generic operation keys in notices. * fix(ui): bound notice text and render failure details Limit resolved notice text without truncating clipboard content, and normalize structured failures embedded in translation parameters. * feat(proxy): persist unseen proxy failures Store unresolved classified failures by code, notify the frontend when the table changes, and show each failure sequence once when a visible window can receive it. * feat(proxy): report tray and hotkey toggle failures Record classified failures from tray and hotkey proxy toggles so they appear when a visible window is available. * fix(ui): restore the proxy switch after failed toggles Refresh frontend proxy state after a failed toggle so the switch reflects the rolled-back configuration. * feat(proxy): stop the guard after repeated failures Report guard outcomes, stop after the failure threshold, and persist the classified failure for the frontend. * fix(macos): preserve proxy during service handoff Stop a sidecar being handed to the service without clearing proxy state that the new owner must inherit. * feat(macos): classify misplaced sidecar state Distinguish a refused sidecar proxy write from a machine that still needs the privileged service installed. * feat(ui): recover misplaced sidecar notices Offer a restart action for macOS proxy failures caused by a ready service while the core still runs as a sidecar. * feat(ui): install the service from proxy notices Let privilege notices install the macOS service, restart the core, and report the runtime mode that was actually reached. * feat(cmd): attach requested proxy operations Carry the requested proxy direction with structured command failures when the originating command knows it. * feat(sysproxy): drain guards before OS access Wait for the local proxy guard to stop before OS reads, service handoff, or final writes, and refuse transitions when it does not drain. * feat(sysproxy): recover partial proxy writes Use write progress to choose whether to restore the old guard or compensate with a disabled proxy state, while preserving actionable errors. * feat(sysproxy): skip already-applied proxy writes Compare macOS proxy snapshots with global, PAC, and disabled targets so matching state avoids redundant privileged writes. * feat(proxy): report background proxy failures Persist and surface classified proxy failures from lifecycle paths that have no direct caller awaiting the result. * feat(ui): move proxy recovery into a dialog Guide users through installing or switching to the service after a refused proxy write, and suppress duplicate toast reports. * fix(ui): close proxy dialog after service recovery Dismiss the recovery dialog once the core reaches service mode, even when the original proxy request remains pending. * feat(ui): retry proxy request after service recovery Replay the requested proxy direction after the core reaches service mode, while leaving incidental restores unchanged. * fix(proxy): refresh state after successful apply Publish the proxy refresh from the shared apply path after releasing the lifecycle lock, and remove the tray-specific duplicate. * feat(ui): show proxy recovery progress Display installation, restart, and proxy-apply stages while keeping the primary action spinner visible during recovery. * feat(ui): route unavailable TUN through service recovery Let the TUN switch request service recovery and restore its requested state after the core restarts in service mode. * fix(ui): avoid duplicate TUN recovery errors Roll back deferred TUN toggles without reporting an error, and publish configuration refreshes from the transaction commit path. * chore: update changelog & pinlock * fix(core): resolve platform-specific clippy warnings * fix(core): detect Windows wildcard TCP conflicts Windows permits a specific exclusive bind beside an existing non-exclusive wildcard listener. Consult the system TCP listener table so the probe reports that overlap as a conflict. |
||
|
|
4b3bc54b2d |
fix(ws): assign websocket after onConnected succeeds (#7639)
* feat(layout): add logging of MihomoWebSocket instances in dev mode * refactor(hooks): defer ws assignment in use-mihomo-ws-subscription * chore: update tauri-plugin-mihomo-api dependency source to use github protocol * docs: update changelog with websocket connection fix |
||
|
|
cefcb150c9 |
fix: core runstate review/improve (#7617)
* fix(core): reopen PAC when a start attempt never happens `save_proxy_ports` closes the PAC endpoint before it stages a candidate, because the endpoint resolves the Mixed Port through the draft layer and would otherwise answer with a port nothing is listening on. Most ways out of that function are a rejection, though: the candidate is refused and the Core keeps serving on its old ports, having never been stopped. PAC is re-derived only when the Running Mode changes, and that is exactly what did not happen — so the endpoint stayed shut for the rest of the session, and every browser on PAC silently went direct. Give `core_starting` the counterpart it was missing. `core_start_settled` re-derives PAC from the Running Mode rather than restoring a saved flag, which makes it correct on all three endings — a start that succeeded, one that was abandoned, one that failed and left the Core down — and therefore safe to run from a guard on every path. * fix(config): refuse overlapping draft transactions instead of losing an edit A layer holds exactly one draft, so a second writer's `edit_draft` overwrites the first writer's staged value in place. `DraftTransaction` nonetheless rolled back by calling `discard` on the shared layer, which discarded whatever was staged there — including a change another transaction was about to commit. The other transaction then found no draft, and `apply` on an absent draft does nothing at all. It saved the committed value, returned Ok, and its side effect had already happened: auto-launch registered with the OS while the config that describes it says otherwise, and no log line either way. "Roll back only my edit" cannot be implemented over a single slot, so enforce the exclusivity the type already assumed. Beginning a transaction claims every layer and refuses rather than interleaving, which is the same shape as `try_start_config_update` and `begin_operation` elsewhere. `patch_verge` is the caller that matters: it holds its draft across `process_terminated_flags`, which restarts the Core and can take seconds. The TUN reconciliation runs on every Run State transition and can now lose that race, so it treats a busy layer as "later" rather than as a failure worth telling the user about. * fix(core): reconcile TUN availability when the setting itself changes Moving the TUN availability guard from the frontend into Rust also moved what triggers it. The old effect depended on `enable_tun_mode`; the new reconciliation is spawned from `RealEnv::publish`, so it only runs on a Run State transition. Those two sets are not the same, and the setting itself falls in the gap. Switching TUN on from the global hotkey is the case that reaches it. That path is not gated on availability — unlike the tray item and the settings switch, both of which read `tun_capable` — and the flags a TUN patch raises are answered by a Core reload, which changes no Run State at all. So on a machine with no Service and no elevation the setting stayed on: tray icon, settings switch and `enable_tun_mode` in verge.yaml all reported TUN as enabled while nothing carried its traffic, until some unrelated core lifecycle transition happened to reconcile it. Reconcile after any patch that touched the setting. The reconciliation writes configuration itself, so it goes through the plain apply rather than back through the patch-and-reconcile form; the absence of a cycle is then a property of the call graph rather than of a runtime early-return. `toggle_tun_mode` now reads the setting back instead of returning what it asked for, so the hotkey cannot report TUN as on moments before the notice saying it was turned off. * fix(core): an action already under way is not a decision to put to the user The legacy status could not distinguish a requested privileged operation from one already running, because readers blocked until the operation finished and so never observed the request at all. Run State pushes every transition instead, and `service_needs_attention` treated any pending action as a question for the user. So an install started from the settings page or the home card raised the migration dialog on top of it, and an uninstall raised one offering to reinstall the Service being removed. Both offer a button that can only fail, since the privileged-operation slot is already taken. An operation in flight is a report of progress. The dialog the user is already driving keeps itself open through its own loading state. `tun_should_be_disabled` is unaffected: it already refused to act while an operation was in flight, so the term this adds is redundant there. * fix(core): let the snapshot decide whether the Run State has settled `settled` read the operation slot twice: once to decide whether to wait, then again inside the snapshot it returned. An operation claiming the slot between those two reads was described rather than waited for. `prepare_startup` reads this. A start racing an install would see the requested install, flatten it to `InstallRequired`, and decide `Wait` — leaving the core stopped where waiting for the install to finish would have told it whether the Service came back. Read the slot once, inside the snapshot, so there is no window rather than a second check closing it. The rewrite that introduced this also fixed a lost wakeup here, and that fix stands: the waiter is still registered before the state is read. * fix(ui): re-read the Run State once its listener is live Replacing the poll with a push left a gap. `listen` resolves asynchronously, so between the first `get_runtime_state` and the subscription being registered there is a window, and a transition landing in it is not queued anywhere — it is simply missed. The next event is whenever the backend happens to move again, which during startup can be a long time; the 30-second safety net was all that stood behind it, where the old code polled every two seconds precisely through startup. The Run State is the one thing here that arrives only by event, so it is the one thing a missed event leaves stale. Re-read it once every listener is live, which closes the gap without going back to polling for it. `onSubscribed` fires even when a registration failed, because a resync is most needed when a subscription is missing, and not at all after teardown. * docs(config): state what makes the PAC endpoint's draft read safe `MixedPort::desired` reads the draft layer, so the PAC endpoint can name a port the Core has not moved to yet. That is only safe because the one path staging a listener port closes PAC across the change. Nothing said so at either end, and the two are in different modules. * fix(core): ask again when staging goes silent rather than assume it failed The Service commits the generation before it answers, so a reply that never arrives is not evidence that nothing was written: config.yaml can already hold the new configuration while this side concludes the staging never happened. The Core keeps running the previous configuration, so nothing looks wrong -- until the Core dies and the Service's watchdog restarts it in the same generation from whatever config.yaml says, quietly making live a configuration the app reported as failed. Silence is the one answer that has to be resolved rather than acted on, so ask once more before falling back. It is cheap exactly where it matters: staging plans against the manifest it wrote, so a bundle that already landed copies nothing and answers in milliseconds, and the Service's lifecycle lock makes a second ask wait for a first one still in flight instead of interleaving with it. A deadline keeps that wait off the caller, and a second silence goes where the first one used to. |
||
|
|
c90de1355e |
refactor: core runstate (#7602)
* refactor(core): introduce core::runstate as the owner of Run State
"Is the Service available?" had five caches and three predicates, and
prepare_startup consulted all three within thirty lines. This lands the
foundation for collapsing that, with no behaviour change: the old owners
now delegate into one store.
The state model splits observation from intent. Five of ServiceStatus's
ten variants were never observations — cmd/service.rs passed
ServiceStatus::InstallRequired as the "which operation do you want"
argument — which is why narrowing to ServiceInstallState had to be lossy.
ServiceHealth now records what we saw, PendingAction records what the
session asked for, and ServiceStatus::from_run_state flattens the pair
for call sites that still expect the single slot.
Reads differ only in freshness: state() is cached, settled() waits for an
in-flight privileged operation, probe() forces IPC. What an answer means
lives on the snapshot (service_usable, tun_capable), so callers stop
writing their own formulas — the tray now asks tun_capable() instead of
recomputing "admin or ready".
Effects sit behind RunStateEnv with two adapters, RealEnv and FakeEnv.
That retires the seven tests that hand-built a private ServiceManager
struct literal, and makes the probe and detection paths testable for the
first time.
Two distinctions are now explicit rather than incidental:
- A single failed probe is not an observation and leaves confirmed
health intact; exhausting a poll's whole retry budget is one and
records unavailable. Both are tested, protecting
|
||
|
|
e599a9d02c | fix(service): avoid sticky availability probes | ||
|
|
7796259b03 |
feat: automatic mixed port fallback (#7579)
* feat: automatically select an available mixed proxy port * fix: coordinate listener port changes * fix: detect Windows listener port conflicts |
||
|
|
bce83d5c6f | chore: update i18n | ||
|
|
23dda47641 |
feat: add launch guard and secure multi-user service ownership (#7569)
* feat(service): isolate macOS launch and owner runtime * ci(windows): run owner security tests * chore(deps): use kode-bridge v0.4.1 tag * fix(macos): classify installed service state * fix(macos): classify marked unavailable service * fix(macos): gate core startup on service migration * fix(macos): scope service init to supported platforms * feat(macos): prompt before migrating installed service * fix(macos): shorten sidecar IPC path * build(service): pin helper protocol and artifacts * fix(core): require confirmed service and sidecar readiness * fix(macos): harden launch roots and singleton state * fix(ui): refresh migration state before restart * fix(macos): linearize service migration lifecycle * fix(ui): keep service migration state fresh * feat(service): track authenticated owner sessions * fix(service): preserve newer owner sessions * feat(macos): route service proxy changes through helper * fix(macos): serialize service proxy guard * fix(macos): close service proxy owner lifecycle * fix(macos): close remaining proxy stop races * fix(app): do not cancel controlled service stop * fix(lifecycle): keep controlled updates cancellation-safe * fix(macos): stage dev core for service * test(macos): exercise staged core cleanup * fix(dev): await controlled macOS exit * chore: update changelog * fix(macos): recover sidecar after service install failure Allow the existing sidecar to continue when service installation leaves the manager in InstallRequired, then settle the session state as SidecarAllowed. Show neutral status text while the migration dialog waits for its final state. * fix(macos): stage dev service tools before elevation * fix(macos): localize launch guard prompts * fix(service): address cross-platform integration issues * feat: support seamless service migration * fix: pass Windows service installer path safely * fix(prebuild): derive service release from Cargo dependency * fix(dev): preserve service installation state * fix: resolve clippy warnings in service lifecycle |
||
|
|
444215f8ed | refactor(frontend): simplify home card settings state | ||
|
|
17fe92352e | refactor(frontend): centralize tun availability guard | ||
|
|
304f5bade9 |
perf(proxy): consolidate proxy data into a single IPC (#7542)
* feat(proxy): build deterministic proxy view * feat(proxy): expose ordered proxy view command * feat(proxy): add proxy view client contract * fix(lint): allow Node test files * feat(proxy): switch UI to ordered proxy view * fix(proxy): harden ordered proxy view consumers * fix(proxy): compare chain duplicates by current id * fix(proxy): release mihomo guard after fetch * fix(proxy): preserve semantic selections across refresh * fix(proxy): block global chain without GLOBAL * fix(proxy): handle proxy view edge states |
||
|
|
e63b8e6eb0 | perf(frontend): eliminate navigation loading states | ||
|
|
950e8195fb |
style: refine navigation item styling (#6578)
Co-authored-by: wonfen <eiwonfen@gmail.com> |
||
|
|
bdeaf2a062 | perf: improve drag performance for large profile lists | ||
|
|
d144e78aeb | perf: streamline profile switching | ||
|
|
7ca20fc4ed |
refactor: knip cleanup (#7468)
* chore(frontend): expand Knip reports * chore: remove unused Mihomo changelog sync script * refactor: remove unused value exports * refactor: remove unused type exports * refactor: remove circular route dependencies * chore(frontend): move Knip scope to config * chore(i18n): remove stale portable update message |
||
|
|
ab1e15dceb | refactor(frontend): remove retired test page | ||
|
|
34fee12496 |
fix(frontend): warm lazy routes concurrently after idle
Start all navigation route preloads after a single idle gate and show centered loading fallbacks during cold route loads. |
||
|
|
afbc14840c | fix: warm lazy routes after startup visibility | ||
|
|
1d7462a021 | fix: stop idle mihomo websocket subscriptions | ||
|
|
c4658cff88 | feat: add window resize handles on linux (#7319) | ||
|
|
dd3ef698f5 |
feat: sticky groups (#7195)
* feat(proxy): implement sticky virtual list and group tools - Add new StickyVirtualList component for better performance with sticky headers - Create ProxyGroupTools component for filtering, sorting and testing proxy groups - Enhance proxy groups with improved scrolling and group toggle functionality - Integrate search box with click event handling - Remove redundant ProxyHead component usage * style: remove unused import and update TypeScript types * refactor: convert function component to forwardRef component to fix biome lint error * feat(proxy): extract proxy chain UI to separate component * refactor: remove custom throttle implementation and simplify dependencies * feat(proxy): improve proxy groups UI and scrolling behavior - Add initialOffset prop to StickyVirtualList for better scroll position restoration - Refactor ProxyGroups component to separate chain and normal modes - Implement scroll position persistence for both chain and normal modes - Add sticky shadow effect for expanded proxy groups - Remove unnecessary ScrollTopButton component - Optimize scroll event handling with throttling - Improve code organization with custom hooks and component separation * docs(proxy-groups): Add TODO comment for initial render position issue * feat(proxy): improve scroll position handling and UI display * refactor(proxy): simplify scroll handling logic and remove unused code * fix(sticky-virtual-list): remove duplicate styles and add padding * refactor(proxy): rename scroll offset variables and functions for clarity * refactor: remove unnecessary refs and simplify onClick handlers * fix(proxy-groups): handle initial scroll position state * feat(zed): add biome formatter configuration * refactor(proxy): remove unused headState import and type annotations * style(proxy): improve type imports and conditional rendering * . * feat(proxy): add ProxyHead component to render in global mode * chore: ignore .zed directory * docs: update changelog |
||
|
|
c2ddb5c111 |
refactor: activate selected proxies (#7285)
* feat(profiles): add automatic node activation after profile switch * refactor(use-profiles): simplify patchCurrent logic by always mutating profiles * refactor(use-profiles): remove unused activateSelected function and related imports * refactor: rename worker handle to activate selected task * fix: clippy * refactor(config): replace log statements with structured logging * refactor(config): fix incorrect retry logic in profile activation * feat(profiles): update proxy cache when switching profiles * docs: update changelog with bug fixes and logic improvements * refactor(profiles): remove unused imports and redundant cache update |
||
|
|
9a2f4ff8fb | fix: warm lazy navigation routes after startup | ||
|
|
3ce228ff7a | fix: lazy load i18n sections | ||
|
|
2442634b2a | fix: lazy load non-home routes | ||
|
|
b9da0875cd | refactor: optimize swr data refresh paths | ||
|
|
e71e701fd0 | refactor: migrate query cache to swr | ||
|
|
5a96fdd9a2 |
fix: harden home clash-mode card against /configs read failures
Recover from controller read/switch failures on the mode card instead of showing a bare "communication error": - fall back to the tolerant get_clash_mode command (then runtime config) when the live /configs mode is unavailable, - optimistically reflect the clicked mode and write it through to the getClashConfig cache so a failed refetch can't flash back the old value, - surface patch failures via showNotice on both the home card and the proxies page (patchClashMode can now reject), and - revalidate getClashMode/getRuntimeConfig on refresh-clash-config so a once-empty fallback can recover. |
||
|
|
a00df6c93d | fix: refresh rules data when clash config is reloaded (#7299) | ||
|
|
e5c1c852d7 | fix(logs): simplify scroll reference by removing length tracking (#7270) | ||
|
|
1e57f41190 | fix: use mihomo traffic totals | ||
|
|
45afb1c15a |
fix(frontend): reduce long-running memory pressure in connections (#7227)
* fix(connections): stabilize table memory usage Render the connections table and list from stable row view models, and replace the TanStack row/cell instantiation path with a lightweight virtualized table body. The leak was isolated to the frontend table render path: websocket data without the table stayed flat, while the normal table path kept producing large per-snapshot object graphs under active/closed churn. Introduced-by: |