Repository navigation
Mobile PWA: secure-context service worker (offline shell) + Tailscale HTTPS for full Android install #192
Description
Summary
Add a secure-context-gated service worker (offline app shell) and a Tailscale HTTPS path so the mobile app becomes a fully installable PWA on Android/Chrome — not just iOS add-to-home-screen.
This is follow-up step 5 of 5 from the "autoconnect to mobile + installable PWA" work. Steps 1–3 have landed (auto-start server, manifest + icons, reconnect screen).
Background: why a manifest alone isn't enough
The remote server serves plain HTTP on a LAN IP (http://192.168.1.x:7777). That is not a secure context, and:
- Service workers won't register over HTTP on a non-localhost origin → no offline shell, and Chrome won't show the "Install app" prompt / generate a WebAPK.
getUserMediais also blocked → in-PWA QR-camera scanning can't work over HTTP either.- iOS Safari is the exception: "Add to Home Screen" works for any page (already shipped via the manifest in step 2), without a service worker.
So full installability requires a real HTTPS origin. The clean way to get one for a localhost service is Tailscale (tailscale serve → https://<machine>.<tailnet>.ts.net, trusted cert), which also gives a stable IP across networks/restarts — ideal for an origin-locked PWA.
Proposed solution
- Minimal service worker in
src/remote/(emitted intodist-remote/):- Pre-cache / cache-first the app shell (HTML, JS, CSS, icons, manifest).
- Never cache
/api/*or/ws(network-only) — these are dynamic and token-scoped. - Register it only when
isSecureContextso it's a no-op over plain HTTP (no console errors on WiFi).
- Server caching headers: the static handler currently serves all non-HTML as
immutable(electron/remote/server.ts). The service-worker file must be servedno-cache(or short max-age) so SW updates propagate; revisit the manifest's caching too. - Tailscale HTTPS guidance / integration: document
tailscale serve(or detect/offer to run it) so users get a secure origin. The app already detects Tailscale IPs and offers a WiFi/Tailscale toggle inConnectPhoneModal.
Acceptance criteria
- Over a secure origin (Tailscale HTTPS / localhost), the service worker registers and the app shell loads offline.
- Over plain HTTP (WiFi), SW registration is skipped cleanly — no errors, app still works as today.
-
/api/*and/wsare never served from cache. - The SW file is served with
no-cache; updates roll out without a year-long immutable cache. - Chrome (Android) shows the install prompt when served over Tailscale HTTPS.
- README/docs describe the Tailscale HTTPS setup for full install.
Touch points
src/remote/— service worker source + registration (guarded byisSecureContext).src/remote/index.html/index.tsx— SW registration entry.electron/remote/server.ts— cache-control for the SW file; ensure SW scope path is served correctly.README.md/PRIVACY.md— Tailscale HTTPS instructions.
Note
iOS already gets a standalone home-screen app over HTTP (shipped in step 2). This issue is specifically about Android/Chrome full install + offline shell, which is a web-platform requirement (secure context), not something we can shortcut in code.
Activity