fix: prevent service worker from caching external resources

The service worker was causing issues by trying to cache external resources:
- CDN images (cdn.nhcarrigan.com)
- Analytics scripts
- External fonts
- Ad scripts

This violated CSP policies and caused 429 rate limit errors.

Fixes:
- Only cache same-origin images
- Only cache same-origin static assets (JS/CSS/fonts)
- External resources bypass the service worker entirely
- Added origin checks before caching
- Added response.ok checks before caching

This prevents CSP violations and eliminates the freezing/429 errors.
This commit is contained in:
2026-02-20 01:04:15 -08:00
committed by Naomi Carrigan
parent e1fbbd4d7c
commit a0f6362c1b
+24 -10
View File
@@ -92,18 +92,25 @@ self.addEventListener('fetch', (event) => {
return; return;
} }
// Images - Cache first, network fallback // Images - Cache first, network fallback (only for same-origin)
if (request.destination === 'image' || url.pathname.match(/\.(jpg|jpeg|png|gif|webp|svg)$/)) { if (request.destination === 'image' || url.pathname.match(/\.(jpg|jpeg|png|gif|webp|svg)$/)) {
// Don't cache external images
if (url.origin !== self.location.origin) {
return;
}
event.respondWith( event.respondWith(
caches.match(request).then((cachedResponse) => { caches.match(request).then((cachedResponse) => {
if (cachedResponse) { if (cachedResponse) {
return cachedResponse; return cachedResponse;
} }
return fetch(request).then((response) => { return fetch(request).then((response) => {
const responseClone = response.clone(); if (response.ok) {
caches.open(IMAGE_CACHE).then((cache) => { const responseClone = response.clone();
cache.put(request, responseClone); caches.open(IMAGE_CACHE).then((cache) => {
}); cache.put(request, responseClone);
});
}
return response; return response;
}); });
}) })
@@ -111,18 +118,25 @@ self.addEventListener('fetch', (event) => {
return; return;
} }
// Static assets - Cache first, network fallback // Static assets - Cache first, network fallback (only for same-origin)
if (url.pathname.match(/\.(js|css|woff|woff2|ttf|eot)$/)) { if (url.pathname.match(/\.(js|css|woff|woff2|ttf|eot)$/)) {
// Don't cache external scripts/styles (CDN resources, analytics, etc.)
if (url.origin !== self.location.origin) {
return;
}
event.respondWith( event.respondWith(
caches.match(request).then((cachedResponse) => { caches.match(request).then((cachedResponse) => {
if (cachedResponse) { if (cachedResponse) {
return cachedResponse; return cachedResponse;
} }
return fetch(request).then((response) => { return fetch(request).then((response) => {
const responseClone = response.clone(); if (response.ok) {
caches.open(STATIC_CACHE).then((cache) => { const responseClone = response.clone();
cache.put(request, responseClone); caches.open(STATIC_CACHE).then((cache) => {
}); cache.put(request, responseClone);
});
}
return response; return response;
}); });
}) })