fix(offline): set the auto flag in setOfflineMode; remove temp diagnostic
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m10s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m51s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m10s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m51s
The auto-offline -> online return was dead because setOfflineMode never set the 'auto' flag: I added the state + getter but forgot the assignment, so it stayed false. So scheduleRecovery bailed immediately (no poll ran) and the online event's 'if (active && auto)' was false. The contour diagnostic confirmed offline.auto stayed false after an auto-offline. Add 'auto = on && !persist'. Also remove the temporary network diagnostic panel (netdiag + the lobby strip) -- it did its job of pinpointing this.
This commit is contained in:
@@ -57,7 +57,6 @@ import {
|
|||||||
import type { CoachSeries } from './coachmark';
|
import type { CoachSeries } from './coachmark';
|
||||||
import { connection, reportOffline, reportOnline, resetConnection, checkReachable } from './connection.svelte';
|
import { connection, reportOffline, reportOnline, resetConnection, checkReachable } from './connection.svelte';
|
||||||
import { offlineMode, setOfflineMode } from './offline.svelte';
|
import { offlineMode, setOfflineMode } from './offline.svelte';
|
||||||
import { netlog } from './netdiag.svelte'; // TEMP diagnostic
|
|
||||||
import { shouldBootOffline } from './offline';
|
import { shouldBootOffline } from './offline';
|
||||||
import { isConnectionCode } from './retry';
|
import { isConnectionCode } from './retry';
|
||||||
import { clearGameCache, getCachedGame, setCachedGame } from './gamecache';
|
import { clearGameCache, getCachedGame, setCachedGame } from './gamecache';
|
||||||
@@ -604,15 +603,9 @@ export function scheduleRecovery(delayMs: number): void {
|
|||||||
recoveryTimer = null;
|
recoveryTimer = null;
|
||||||
if (!offlineMode.active || !offlineMode.auto) return;
|
if (!offlineMode.active || !offlineMode.auto) return;
|
||||||
const interfaceUp = typeof navigator === 'undefined' || navigator.onLine;
|
const interfaceUp = typeof navigator === 'undefined' || navigator.onLine;
|
||||||
netlog(`poll tick: navOnline=${interfaceUp}`); // TEMP diagnostic
|
if (interfaceUp && (await checkReachable(BOOT_REACHABILITY_TIMEOUT_MS))) {
|
||||||
if (interfaceUp) {
|
if (offlineMode.active && offlineMode.auto) setOfflineMode(false);
|
||||||
const reachable = await checkReachable(BOOT_REACHABILITY_TIMEOUT_MS);
|
return;
|
||||||
netlog(`checkReachable=${reachable}`); // TEMP diagnostic
|
|
||||||
if (reachable && offlineMode.active && offlineMode.auto) {
|
|
||||||
setOfflineMode(false);
|
|
||||||
netlog('-> RETURNED ONLINE'); // TEMP diagnostic
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scheduleRecovery(4000);
|
scheduleRecovery(4000);
|
||||||
}, delayMs);
|
}, delayMs);
|
||||||
@@ -621,17 +614,14 @@ export function scheduleRecovery(delayMs: number): void {
|
|||||||
export function initNetworkReactivity(): void {
|
export function initNetworkReactivity(): void {
|
||||||
if (typeof window === 'undefined' || import.meta.env.MODE === 'mock') return;
|
if (typeof window === 'undefined' || import.meta.env.MODE === 'mock') return;
|
||||||
window.addEventListener('offline', () => {
|
window.addEventListener('offline', () => {
|
||||||
netlog(`offline EVENT (active=${offlineMode.active})`); // TEMP diagnostic
|
|
||||||
if (!offlineMode.active) {
|
if (!offlineMode.active) {
|
||||||
setOfflineMode(true, false); // auto (session)
|
setOfflineMode(true, false); // auto (session)
|
||||||
netlog('-> auto-offline; poll started'); // TEMP diagnostic
|
|
||||||
scheduleRecovery(4000); // poll for the network to return
|
scheduleRecovery(4000); // poll for the network to return
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// The online event, when it fires, just kicks an immediate reachability check; the poll above is
|
// The online event, when it fires, just kicks an immediate reachability check; the poll above is
|
||||||
// the reliable fallback for platforms where it does not fire.
|
// the reliable fallback for platforms where it does not fire.
|
||||||
window.addEventListener('online', () => {
|
window.addEventListener('online', () => {
|
||||||
netlog(`online EVENT (active=${offlineMode.active} auto=${offlineMode.auto})`); // TEMP diagnostic
|
|
||||||
if (offlineMode.active && offlineMode.auto) scheduleRecovery(0);
|
if (offlineMode.active && offlineMode.auto) scheduleRecovery(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
// TEMPORARY network diagnostic — REMOVE before release. A live view of the online/offline signals so
|
|
||||||
// we can pinpoint where the auto-offline -> online transition breaks. Rendered by a panel in
|
|
||||||
// Lobby.svelte. Skipped in the mock build.
|
|
||||||
|
|
||||||
let entries = $state<string[]>([]);
|
|
||||||
let navOnline = $state(typeof navigator !== 'undefined' ? navigator.onLine : true);
|
|
||||||
|
|
||||||
export const netdiag = {
|
|
||||||
/** entries is the newest-first ring buffer of timestamped diagnostic lines. */
|
|
||||||
get entries(): string[] {
|
|
||||||
return entries;
|
|
||||||
},
|
|
||||||
/** navOnline is the live navigator.onLine value (the property itself is not reactive). */
|
|
||||||
get navOnline(): boolean {
|
|
||||||
return navOnline;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/** netlog appends a timestamped diagnostic line (kept to the last 24). */
|
|
||||||
export function netlog(msg: string): void {
|
|
||||||
const t = new Date().toLocaleTimeString();
|
|
||||||
entries = [`${t} ${msg}`, ...entries].slice(0, 24);
|
|
||||||
if (typeof navigator !== 'undefined') navOnline = navigator.onLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A 1 s heartbeat keeps navigator.onLine live in the panel and logs when it flips — so a flight-mode
|
|
||||||
// toggle is visible even if the online/offline events never fire (the exact thing we are chasing).
|
|
||||||
if (typeof window !== 'undefined' && import.meta.env.MODE !== 'mock') {
|
|
||||||
let last = typeof navigator !== 'undefined' ? navigator.onLine : true;
|
|
||||||
setInterval(() => {
|
|
||||||
const now = typeof navigator !== 'undefined' ? navigator.onLine : true;
|
|
||||||
navOnline = now;
|
|
||||||
if (now !== last) {
|
|
||||||
last = now;
|
|
||||||
netlog(`navigator.onLine -> ${now}`);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
@@ -36,6 +36,7 @@ export const offlineMode = {
|
|||||||
*/
|
*/
|
||||||
export function setOfflineMode(on: boolean, persist = true): void {
|
export function setOfflineMode(on: boolean, persist = true): void {
|
||||||
active = on;
|
active = on;
|
||||||
|
auto = on && !persist; // a non-persisted offline is auto-detected; a persisted one is deliberate
|
||||||
if (persist) saveOfflinePref(on);
|
if (persist) saveOfflinePref(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
import Modal from '../components/Modal.svelte';
|
import Modal from '../components/Modal.svelte';
|
||||||
import { app, handleError, refreshFeedbackBadge, seedChatUnread } from '../lib/app.svelte';
|
import { app, handleError, refreshFeedbackBadge, seedChatUnread } from '../lib/app.svelte';
|
||||||
import { connection } from '../lib/connection.svelte';
|
import { connection } from '../lib/connection.svelte';
|
||||||
import { netdiag } from '../lib/netdiag.svelte'; // TEMP diagnostic
|
|
||||||
import { gateway } from '../lib/gateway';
|
import { gateway } from '../lib/gateway';
|
||||||
import { navigate } from '../lib/router.svelte';
|
import { navigate } from '../lib/router.svelte';
|
||||||
import { t } from '../lib/i18n/index.svelte';
|
import { t } from '../lib/i18n/index.svelte';
|
||||||
@@ -259,15 +258,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- TEMP network diagnostic — REMOVE before release. Fixed strip showing the live online/offline
|
|
||||||
signals + an event log, to pinpoint where the auto-offline -> online transition breaks. -->
|
|
||||||
<div style="position:fixed;top:0;left:0;right:0;z-index:9999;background:rgba(0,0,0,0.88);color:#0f0;font:10px/1.35 monospace;padding:4px 6px;max-height:45vh;overflow-y:auto;pointer-events:none">
|
|
||||||
<div style="color:#fff;margin-bottom:3px">
|
|
||||||
nav.onLine={String(netdiag.navOnline)} · offline={String(offlineMode.active)} · auto={String(offlineMode.auto)} · conn.online={String(connection.online)}
|
|
||||||
</div>
|
|
||||||
{#each netdiag.entries as e, i (i)}<div style="white-space:nowrap">{e}</div>{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Screen title={app.profile?.displayName ?? t('app.title')}>
|
<Screen title={app.profile?.displayName ?? t('app.title')}>
|
||||||
<div class="lobby">
|
<div class="lobby">
|
||||||
{#if invitations.length}
|
{#if invitations.length}
|
||||||
|
|||||||
Reference in New Issue
Block a user