From 0c8723ef84903125270e4516151d28cc7f706b26 Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Wed, 13 May 2026 20:45:03 -0400 Subject: [PATCH] Fix sw.js: exclude /hubs/ and PollSession from SW interception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SW fetch() wraps SSE responses in a buffered Response, preventing SignalR streaming — handshakes time out after 15s as a result. Exclude /hubs/ and /Kiosk/PollSession so the browser handles them directly without SW wrapping. Co-Authored-By: Claude Sonnet 4.6 --- src/PowderCoating.Web/wwwroot/sw.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/PowderCoating.Web/wwwroot/sw.js b/src/PowderCoating.Web/wwwroot/sw.js index 17140e7..2ce4a66 100644 --- a/src/PowderCoating.Web/wwwroot/sw.js +++ b/src/PowderCoating.Web/wwwroot/sw.js @@ -1,11 +1,26 @@ // Minimal service worker — required for PWA installability. -// No caching: all requests pass through to the network normally. -// This exists solely so browsers recognize the site as installable, -// which causes iOS/Android to persist camera permissions after "Add to Home Screen." +// No caching: all requests pass through to the network. +// Exists solely so browsers recognize the site as installable +// (iOS/Android persist camera permissions after "Add to Home Screen"). +// +// IMPORTANT: /hubs/ (SignalR) requests are excluded from interception entirely. +// Service worker fetch() wraps SSE/WebSocket responses in a buffered Response, +// which prevents real-time streaming — SignalR handshakes time out as a result. + +const SKIP_PREFIXES = ['/hubs/', '/Kiosk/PollSession']; self.addEventListener('install', () => self.skipWaiting()); self.addEventListener('activate', e => e.waitUntil(self.clients.claim())); + self.addEventListener('fetch', e => { - if (new URL(e.request.url).origin !== self.location.origin) return; + const url = new URL(e.request.url); + + // Always skip cross-origin requests + if (url.origin !== self.location.origin) return; + + // Skip SignalR hubs and kiosk polling — let the browser handle these directly + if (SKIP_PREFIXES.some(p => url.pathname.startsWith(p))) return; + + // Passthrough: no caching, no modification e.respondWith(fetch(e.request)); });