fix(connection): ignore spurious navigator.onLine offline hint in Tauri (#1234)

This commit is contained in:
cucadmuh
2026-07-04 20:56:31 +03:00
committed by GitHub
parent bf0e73ce6c
commit 5e075b2c36
12 changed files with 159 additions and 12 deletions
+3 -2
View File
@@ -1,4 +1,5 @@
import { isDevOfflineBrowseForced } from '@/store/devOfflineBrowseStore';
import { isNavigatorOfflineHint } from '@/lib/network/navigatorOnlineHint';
export type ConnectionStatus = 'connected' | 'disconnected' | 'checking';
@@ -53,9 +54,9 @@ export function resetActiveServerConnectionSnapshot(): void {
connectionStatus = 'checking';
}
/** True only when the browser is online and the last active-server probe succeeded. */
/** True only when no navigator offline hint applies and the last active-server probe succeeded. */
export function isActiveServerReachable(): boolean {
if (isDevOfflineBrowseForced()) return false;
if (typeof navigator !== 'undefined' && !navigator.onLine) return false;
if (isNavigatorOfflineHint()) return false;
return activeServerReachable === true;
}
@@ -0,0 +1,35 @@
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
const isTauri = vi.fn(() => false);
vi.mock('@tauri-apps/api/core', () => ({
isTauri: () => isTauri(),
}));
import { isNavigatorOfflineHint } from './navigatorOnlineHint';
describe('isNavigatorOfflineHint', () => {
beforeEach(() => {
isTauri.mockReturnValue(false);
});
afterEach(() => {
vi.unstubAllGlobals();
});
it('returns false in Tauri even when navigator.onLine is false', () => {
isTauri.mockReturnValue(true);
vi.stubGlobal('navigator', { onLine: false });
expect(isNavigatorOfflineHint()).toBe(false);
});
it('returns true in non-Tauri when navigator.onLine is false (offline hint applies)', () => {
vi.stubGlobal('navigator', { onLine: false });
expect(isNavigatorOfflineHint()).toBe(true);
});
it('returns false when navigator.onLine is true', () => {
vi.stubGlobal('navigator', { onLine: true });
expect(isNavigatorOfflineHint()).toBe(false);
});
});
+21
View File
@@ -0,0 +1,21 @@
import { isTauri } from '@tauri-apps/api/core';
/**
* Whether callers should treat `navigator.onLine === false` as an offline signal.
*
* Returns `true` only in non-Tauri hosts when `navigator.onLine` is false.
* WebKitGTK inside Tauri often leaves `navigator.onLine === false` even when
* HTTP to the user's Subsonic/Navidrome server works (ping, search, playback).
* Desktop builds must not trust that hint — use Subsonic probes instead.
*
* @see https://github.com/orgs/tauri-apps/discussions/9269
*/
export function isNavigatorOfflineHint(): boolean {
if (typeof navigator === 'undefined') return false;
try {
if (isTauri()) return false;
} catch {
/* isTauri unavailable in some test harnesses — fall through */
}
return !navigator.onLine;
}
+3 -2
View File
@@ -3,6 +3,7 @@ import { hasLocalPlaybackUrl } from '@/store/localPlaybackResolve';
import { isDevOfflineBrowseForced } from '@/store/devOfflineBrowseStore';
import { resolveServerIdForIndexKey } from '@/lib/server/serverLookup';
import { isActiveServerReachable } from '@/lib/network/activeServerReachability';
import { isNavigatorOfflineHint } from '@/lib/network/navigatorOnlineHint';
function isSameServerProfile(a: string, b: string): boolean {
if (!a || !b) return false;
@@ -18,7 +19,7 @@ function isSameServerProfile(a: string, b: string): boolean {
export function isSubsonicServerReachable(serverId: string): boolean {
if (!serverId) return false;
if (isDevOfflineBrowseForced()) return false;
if (typeof navigator !== 'undefined' && !navigator.onLine) return false;
if (isNavigatorOfflineHint()) return false;
const activeId = useAuthStore.getState().activeServerId;
if (!activeId || isSameServerProfile(serverId, activeId)) {
return isActiveServerReachable();
@@ -34,7 +35,7 @@ export function isSubsonicServerReachable(serverId: string): boolean {
export function shouldAttemptSubsonicForServer(serverId: string, trackId?: string): boolean {
if (!serverId) return false;
if (isDevOfflineBrowseForced()) return false;
if (typeof navigator !== 'undefined' && !navigator.onLine) return false;
if (isNavigatorOfflineHint()) return false;
if (trackId && hasLocalPlaybackUrl(trackId, serverId)) return false;
return isSubsonicServerReachable(serverId);
}