From 4d6b4b5b8e9e340b95e496fcfcfe3ffbfcaf4bb9 Mon Sep 17 00:00:00 2001 From: dealerweb Date: Thu, 2 Jul 2026 13:12:38 +0200 Subject: [PATCH] Fix: brand push notifications with the configured PWA icon The service worker hard-coded the notification icon and badge to the bundled /icon-192x192.png, so push notifications always showed the default Bulwark logo even when an admin had configured a custom PWA/favicon icon (which the manifest already honors via /api/pwa-icon). Point both notifications at /api/pwa-icon/192, and make that endpoint fall back to the bundled default icon instead of returning 404 when no custom icon is set - so it always returns an app icon and the service worker (which can't run the custom-vs-default check itself) has a single stable URL. --- app/api/pwa-icon/[size]/route.ts | 10 ++++++---- public/sw.js | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/api/pwa-icon/[size]/route.ts b/app/api/pwa-icon/[size]/route.ts index 52870b18..93a538c5 100644 --- a/app/api/pwa-icon/[size]/route.ts +++ b/app/api/pwa-icon/[size]/route.ts @@ -59,10 +59,12 @@ export async function GET( domainOverrides.pwaIconUrl || domainOverrides.faviconUrl || (sources.pwaIconUrl?.source !== 'default' ? (sources.pwaIconUrl?.value as string) : '') || - (sources.faviconUrl?.source !== 'default' ? (sources.faviconUrl?.value as string) : ''); - if (!iconUrl) { - return new NextResponse('No PWA icon configured', { status: 404 }); - } + (sources.faviconUrl?.source !== 'default' ? (sources.faviconUrl?.value as string) : '') || + // Fall back to the built-in default so this endpoint ALWAYS returns an app + // icon (custom if configured, else the bundled default). This lets callers + // that can't run the custom-vs-default check themselves - notably the + // service worker's notifications - use a single stable URL. + `/icon-${size}x${size}.png`; const pngHeaders = { 'Content-Type': 'image/png', diff --git a/public/sw.js b/public/sw.js index 654ca84b..702404c0 100644 --- a/public/sw.js +++ b/public/sw.js @@ -169,8 +169,10 @@ async function handlePush(event) { await self.registration.showNotification(title, { body, tag, - icon: `${BASE_PATH}/icon-192x192.png`, - badge: `${BASE_PATH}/icon-192x192.png`, + // Branded app icon via the PWA-icon endpoint (admin-configured, else the + // built-in default). The static /icon-192x192.png ignored admin branding. + icon: `${BASE_PATH}/api/pwa-icon/192`, + badge: `${BASE_PATH}/api/pwa-icon/192`, data, renotify: true, }); @@ -281,8 +283,8 @@ async function showMailtoFocusNotification(state) { await self.registration.showNotification(state.focusNotificationTitle || "Bulwark", { body: state.focusNotificationBody || "The request was opened in Bulwark. Click to bring it to the front.", tag: "bulwark-mailto-focus", - icon: `${BASE_PATH}/icon-192x192.png`, - badge: `${BASE_PATH}/icon-192x192.png`, + icon: `${BASE_PATH}/api/pwa-icon/192`, + badge: `${BASE_PATH}/api/pwa-icon/192`, data: { kind: "protocol-mailto-focus" }, renotify: true, });