Skip to main content

PWA and Service Worker

Cashlytics registers its service worker only in production.

Registration​

src/components/pwa/service-worker-registrar.tsx registers /sw.js with scope / in production. In development, it unregisters existing service workers and removes Cashlytics caches to avoid stale local behavior.

Cache Strategy​

public/sw.js only handles same-origin GET requests and uses:

  • cache-first for /_next/static/ assets
  • no interception for /api/* and other /_next/* paths: API responses are never cached
  • network-first with a per-user offline copy for pages and RSC data, falling back to /~offline

The offline page is pre-cached during service worker install along with favicon and manifest assets. CACHE_VERSION (currently v2) is part of the cache names; on activate, caches from other versions are deleted.

Per-User Offline Copies​

Pages and RSC data are user-specific, so they are stored in a cache named cashlytics-user-<userId>. Only successful, non-redirected responses are stored.

  • The app tells the service worker who is signed in with a SET_USER message and clears everything with CLEAR_USER on logout (src/lib/pwa/offline-cache.ts: setOfflineCacheUser, clearOfflineUserData). Switching users deletes the previous user's caches.
  • Offline, the worker serves that user's copy if it is at most 7 days old (timestamp in the x-sw-cached-at header). Otherwise navigations get /~offline and other requests get a 503.

Known gap: every sidebar prefetch (?_rsc=) ends up in the offline cache for 7 days even though it is never used offline.

Push Events​

The same service worker handles push and notificationclick. Push payloads can include title, body, icon, badge, and url. Notification clicks focus an existing same-origin app window when possible or open a new one.