fix(boot): native offline-first launch is silent and fast (Android 10)

Two native offline-first boot glitches (seen on Android 10):
- bootOffline forced offlineNoNetwork, so its first successful reconcile healed to online with a
  spurious "back online" toast on a first launch that actually had connectivity. The boot-assumed
  offline is now PROVISIONAL: the first probe confirms it — a success heals silently (nothing to
  come back from), a failure turns it into a real offline whose later recovery does toast.
- A native launch with a cached guest session (no email) skipped the offline short-circuit and hung
  ~25 s on adoptSession's retrying profile fetch in airplane mode. The native channel is offline-first,
  so it now takes the same reachability-gated fallback (~3 s bound) as an installed email PWA.
This commit is contained in:
Ilia Denisov
2026-07-15 02:17:13 +02:00
parent 74026223ee
commit 3429dbec5f
4 changed files with 55 additions and 5 deletions
+18 -3
View File
@@ -74,6 +74,14 @@ export interface NetSnapshot {
* it (0 while not `connecting`).
*/
connectingSince: number;
/**
* provisional marks an `offlineNoNetwork` that was ASSUMED at boot (bootOffline), not observed from
* a real online→offline transition. The first probe confirms it: a success means we were reachable
* all along, so the machine heals to online SILENTLY (no "back online" toast — there was nothing to
* come back from); a failure clears the flag, turning it into a confirmed offline whose later
* recovery does toast. Absent/false in every non-boot snapshot.
*/
provisional?: boolean;
}
/** NetInput is an event stamped with the wall-clock time it occurred at; only the debounce branch
@@ -198,13 +206,20 @@ export function reduce(prev: NetSnapshot, ev: NetInput, cfg: NetConfig): NetResu
switch (ev.type) {
case 'callOk':
case 'probeOk':
// The probe (or a reconcile call) won — self-heal to online with a "back online" toast.
return { next: onlineSnapshot(), effects: [{ kind: 'toast', toast: 'online' }] };
// The probe (or a reconcile call) won — heal to online. A boot-assumed (provisional) offline
// that is reachable on its very first probe was never really offline, so heal SILENTLY; a
// confirmed offline gets the "back online" toast.
return { next: onlineSnapshot(), effects: prev.provisional ? [] : [{ kind: 'toast', toast: 'online' }] };
case 'callFailed':
case 'probeFailed':
// A failed probe confirms a boot-assumed offline as real (its eventual recovery will then
// toast); a non-provisional offline is unchanged.
return prev.provisional ? { next: { ...prev, provisional: false }, effects: [] } : { next: prev, effects: [] };
case 'osOnline':
// Trigger a probe; stay offline until it actually wins (a captive portal can report online).
return { next: prev, effects: [{ kind: 'startProbe' }] };
default:
// callFailed / probeFailed / osOffline (still offline), versionRecommended (no nudge): no-op.
// osOffline (still offline), versionRecommended (no nudge): no-op.
return { next: prev, effects: [] };
}
}