diff --git a/src/components/GrampsjsUpdateAvailable.js b/src/components/GrampsjsUpdateAvailable.js index 0edfce6e..ed10de09 100644 --- a/src/components/GrampsjsUpdateAvailable.js +++ b/src/components/GrampsjsUpdateAvailable.js @@ -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( diff --git a/src/sw.js b/src/sw.js index 45241ab5..c3342a36 100644 --- a/src/sw.js +++ b/src/sw.js @@ -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)