Fix SW navigation handler and update toast trigger

- Use redirect:manual in the navigation fetch so cross-origin auth
  redirects (e.g. Cloudflare Access session expiry) are passed through
  to the browser instead of silently serving stale cached HTML
- Fix GrampsjsUpdateAvailable: the parent's click listener could not be
  removed (bind() produces a new reference), causing any click on the
  snackbar to trigger skipWaiting; override _postMessage to ignore clicks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
David Straub
2026-04-26 09:24:56 +00:00
parent 2a184a3440
commit c5eb333aa2
2 changed files with 27 additions and 11 deletions
+7 -1
View File
@@ -6,9 +6,15 @@ import '@material/mwc-button'
export class GrampsjsUpdateAvailable extends PwaUpdateAvailable {
async connectedCallback() {
super.connectedCallback()
this.removeEventListener('click', this._postMessage.bind(this))
this.addEventListener('update:reload', this._postMessage.bind(this))
}
// The parent attaches a click listener via .bind(), so it can't be removed (new
// reference each time). Ignore clicks; only 'update:reload' should trigger an update.
_postMessage(e) {
if (e?.type === 'click') return
super._postMessage(e)
}
}
window.customElements.define(
+20 -10
View File
@@ -1,4 +1,4 @@
import {precacheAndRoute, createHandlerBoundToURL} from 'workbox-precaching'
import {precacheAndRoute, matchPrecache} from 'workbox-precaching'
import {registerRoute, NavigationRoute} from 'workbox-routing'
import {CacheFirst} from 'workbox-strategies'
import {CacheableResponsePlugin} from 'workbox-cacheable-response'
@@ -12,18 +12,28 @@ self.addEventListener('message', event => {
precacheAndRoute(self.__WB_MANIFEST)
// Handle navigation requests (SPA routing) by serving the precached index.html,
// except for API routes which should always go to the network.
// Try the network first with redirect:manual so cross-origin auth redirects
// (e.g. Cloudflare Access) are passed through to the browser. Falls back to
// precached index.html for SPA routing and offline use.
registerRoute(
new NavigationRoute(createHandlerBoundToURL('index.html'), {
denylist: [/^\/api.*/],
})
new NavigationRoute(
async ({request}) => {
try {
const response = await fetch(request, {redirect: 'manual'})
if (response.type === 'opaqueredirect') {
return response
}
} catch {
// offline
}
return matchPrecache('/index.html')
},
{denylist: [/^\/api.*/]}
)
)
// Cache thumbnails with a stable cache key:
// - strip `jwt` so token rotation doesn't bust the cache
// - keep `checksum` in the cache key for content-addressed invalidation
// - strip `checksum` before the network request so the backend doesn't reject it
// Cache thumbnails: strip `jwt` from cache key (token rotation), strip `checksum`
// before fetching (backend rejects it; kept in cache key for invalidation).
const thumbnailPlugin = {
cacheKeyWillBeUsed: async ({request}) => {
const url = new URL(request.url)