Migrate the former install-only public/sw.js to a custom (injectManifest)
service worker built from ui/src/sw.ts by vite-plugin-pwa. It precaches the
app shell + hashed assets (Workbox) so an installed web PWA cold-launches with
no network, and falls in-scope navigations back to the precached shell (the
hash router resolves the route client-side). This is the C1 prerequisite for a
usable offline mode: without it a cold offline launch cannot load the bundle.
- ui/src/sw.ts: skipWaiting + clientsClaim + cleanupOutdatedCaches +
precacheAndRoute(__WB_MANIFEST) + a NavigationRoute fallback to index.html,
deny-listing the RPC path and /_gm. The Connect stream and API POSTs are
never precached nor intercepted.
- vite.config.ts: VitePWA(injectManifest); manifest:false (we ship our own),
injectRegister:false (registration stays manual + web-only in pwa.svelte.ts),
disabled in the mock build (Playwright unperturbed); landing + polyfills
excluded from the precache.
- Removed public/sw.js; the registration path (dist/sw.js at /app/) is unchanged.
- New dev deps: vite-plugin-pwa + workbox-{core,precaching,routing}.
Docs: ARCHITECTURE + gateway/README. Offline cold-launch is contour-verified
(the mock e2e harness disables the SW).
Make the web SPA an installable PWA and surface it to users:
- manifest.webmanifest + an install-only service worker + 192/512/maskable
icons (ui/public); PWA head tags in index.html; the .webmanifest MIME type
registered in the gateway (the distroless image has no /etc/mime.types).
- Platform-adaptive install CTA (components/InstallApp.svelte + lib/pwa):
one-tap on Chromium, manual Add-to-Home-Screen instructions on iOS Safari,
hidden elsewhere / once installed / inside a Mini App. Shown under the
logged-out login card and at the bottom of Settings.
- The landing gains a third entry linking /app/ (the brand tile), with a
caption under all three (Telegram / VK / Веб-версия).
The service worker is navigation-only (network-first, cached-shell fallback);
hashed assets and the Connect stream are untouched. It exists to satisfy
Chromium's installability requirement and is the single growth point for a
future opt-in offline mode.
Tests: pwa.ts unit tests; a webui probe (manifest/sw.js content-type + the
SPA-fallback-to-HTML trap); e2e for the one-tap CTA, the iOS instructions
modal and the landing web entry. Docs: ARCHITECTURE §13, FUNCTIONAL (+ru),
gateway README.