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.
* fix: improve type safety and remove redundant type casts
- Fix @@ts-expect-error typo (double @) in traffic-diagnostics.ts
- Replace (e.target as any) with (e.target as HTMLElement) in setting-clash.tsx
- Remove redundant (onFormat as any) cast in guard-state.tsx
* fix: format api.ts sort callback to satisfy biome
* fix: remove as any, let @ts-expect-error suppress the non-standard API error
* fix: remove invalid @@ts-expect-error comment, keep as any for non-standard API
* fix: replace toSorted with slice().sort() for macOS 12 compatibility
Array.prototype.toSorted() is ES2023 and not supported in WebKit < 16
(bundled with macOS 12 Monterey). Using slice().sort() is functionally
identical and works on all platforms.
Fixes#7216
* chore: update Changelog
---------
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
- Replace boolean/string validation results with structured ValidationOutcome values across config validation, profile switching, DNS validation, and script validation. Callers can now distinguish valid, invalid, skipped, and busy states, with invalid results carrying an error kind and message.
- Route core config updates through structured outcomes and checked forced updates. Generation and validation failures now discard runtime drafts and surface validation failures instead of relying on empty success messages.
- Preserve existing frontend ergonomics by keeping boolean service wrappers where callers only need success, while direct DNS and script validation consumers receive ValidationOutcome. Failed profile editor saves reload the backend-restored file content and synchronize Monaco models so reopened editors show the restored state.
- Extract shared delay state logic from ProxyItem and ProxyItemMini
into `useProxyDelayState` hook (src/hooks/use-proxy-delay-state.ts);
JSX display thresholds preserved per-component.
- Deduplicate rAF/setTimeout/Promise scheduling in DelayManager via
a private `scheduleOnNextFrame` helper.
- Drop no-op `useMemo(() => MODES, [])` in proxies page.
- Replace `any` on `setClashLog` prev params and layout-traffic sx
objects with proper types (`pre!`, `Pick<BoxProps|...>`).
Replace swr with @tanstack/react-query v5 across all hooks, providers,
and components. Introduce singleton QueryClient, WS subscription pattern
via useQuery+useEffect, and enforce component-layer cache access contract.
Add leading-edge throttle to useMihomoWsSubscription, reduce SWR retry
aggressiveness, and increase WebSocket reconnect delay to prevent event
storms when switching profiles under poor network conditions.
* refactor: replace handle::Handle::get_window() with WindowManager::get_main_window() in multiple files
* refactor: enhance WindowManager to return window state alongside the main window instance
* refactor: update useProfiles and ProfilePage to support profile overrides and improve patchProfilesConfig return type
* refactor: enhance handle_success to check main window existence before notifying profile changes
* refactor: simplify get_main_window_with_state by using pattern matching and improve window state handling
* refactor: fix window activation by removing unnecessary reference in activate_existing_main_window
* refactor: remove redundant macOS conditional for window_manager import
* refactor(ip-info-card): reduce retry, use succeed as lastFetchTs
* refactor(ip-info-card): stop countdown during revalidation
* perf(ip-info-card): avoid aggressive schedule revalidation
* perf(ip-info-card): try stop interval on window minimized
* perf(ip-info-card): only mutate after card scroll into view once
* perf(ip-info-card): interval only when card has been visible
* chore: add more debug information
* Update src/components/home/ip-info-card.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: reset countdown state after mutate finishes
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* perf(ip-info-card): make ip info card much better
* fix(ip-info-card): remove unused useEffect deps
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* refactor(ip-info-card): use `async-retry`, bail out non-2XX resp
* feat(ip-info-card): add new backend
* feat(ip-info-card): only revalidate when window is visible
* perf(ip-info-card): reduce re-renders when window is hidden
* fix(ip-info-card): remove `mutate` from `useEffect` arg
* Update src/components/home/ip-info-card.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: drop AbortSignal.timeout for old safati compat
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix(ui): prevent light flash on dark startup
* fix(window): apply initial dark/light theme to prevent white flash
* refactor(boot): optimize config fetch and theme fallback
* fix: system theme detection
* fix(window): remove black flash before loader by aligning initial paint with theme
* refactor(traffic-monitor): Move traffic sampling/compression to a dedicated Web Worker
* refactor(traffic-monitor): introduce shared sampler, safe fallback, and decoupled range handling
* refactor(traffic-monitor): add optional subscribe flag and fix range handling
* fix(traffic-monitor): age out idle samples and prevent ref-count updates after unmount