diff --git a/index.html b/index.html
index 567df9b..436d1c6 100644
--- a/index.html
+++ b/index.html
@@ -9850,6 +9850,23 @@
.then(registration => {
console.log('Service Worker registered:', registration.scope);
+ // Check for updates on every page load
+ registration.update();
+
+ // Handle service worker updates
+ registration.addEventListener('updatefound', () => {
+ const newWorker = registration.installing;
+ console.log('New service worker installing...');
+
+ newWorker.addEventListener('statechange', () => {
+ if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
+ // New version available - skip waiting and reload
+ console.log('New version available, activating...');
+ newWorker.postMessage({ type: 'SKIP_WAITING' });
+ }
+ });
+ });
+
// Check for updates periodically
setInterval(() => {
registration.update();
@@ -9860,6 +9877,12 @@
});
});
+ // Reload page when new service worker takes control
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
+ console.log('New service worker activated, reloading...');
+ window.location.reload();
+ });
+
// Listen for app install prompt
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
diff --git a/server.js b/server.js
index abd28ec..1dbe250 100644
--- a/server.js
+++ b/server.js
@@ -64,6 +64,20 @@ app.use('/api', (req, res, next) => {
next();
});
+// Serve service-worker.js with no-cache (critical for updates)
+app.get('/service-worker.js', (req, res) => {
+ res.set('Cache-Control', 'no-store, no-cache, must-revalidate');
+ res.set('Pragma', 'no-cache');
+ res.sendFile(path.join(__dirname, 'service-worker.js'));
+});
+
+// Serve HTML files with no-cache to ensure fresh content
+app.get(['/', '/index.html', '/admin.html'], (req, res, next) => {
+ res.set('Cache-Control', 'no-store, no-cache, must-revalidate');
+ res.set('Pragma', 'no-cache');
+ next();
+});
+
// Serve static files - prioritize data directory for default.kml
app.get('/default.kml', async (req, res) => {
try {
diff --git a/service-worker.js b/service-worker.js
index e3679b4..0f94a22 100644
--- a/service-worker.js
+++ b/service-worker.js
@@ -1,5 +1,6 @@
// HikeMap Service Worker
-const CACHE_NAME = 'hikemap-v1.0.0';
+// Increment version to force cache refresh
+const CACHE_NAME = 'hikemap-v1.0.1';
const urlsToCache = [
'/',
'/index.html',
@@ -78,13 +79,51 @@ self.addEventListener('fetch', event => {
return;
}
- // Handle API calls with network-first strategy
+ // Handle ALL API calls with network-first strategy
+ if (url.pathname.startsWith('/api/')) {
+ event.respondWith(
+ fetch(event.request)
+ .then(response => {
+ return response;
+ })
+ .catch(() => {
+ // Fall back to cache for API calls if offline
+ return caches.match(event.request);
+ })
+ );
+ return;
+ }
+
+ // Handle HTML files with network-first strategy (always get fresh version)
+ if (event.request.destination === 'document' ||
+ url.pathname === '/' ||
+ url.pathname.endsWith('.html')) {
+ event.respondWith(
+ fetch(event.request)
+ .then(response => {
+ // Cache the fresh version
+ if (response.status === 200) {
+ const responseToCache = response.clone();
+ caches.open(CACHE_NAME).then(cache => {
+ cache.put(event.request, responseToCache);
+ });
+ }
+ return response;
+ })
+ .catch(() => {
+ // Fall back to cache only if network fails
+ return caches.match(event.request);
+ })
+ );
+ return;
+ }
+
+ // Handle geocache/KML data with network-first
if (url.pathname.includes('/save-kml') ||
url.pathname.includes('/geocaches')) {
event.respondWith(
fetch(event.request)
.then(response => {
- // Cache successful API responses
if (response.status === 200) {
const responseToCache = response.clone();
caches.open(GEOCACHE_CACHE).then(cache => {
@@ -94,14 +133,13 @@ self.addEventListener('fetch', event => {
return response;
})
.catch(() => {
- // Fall back to cache for API calls
return caches.match(event.request);
})
);
return;
}
- // Default strategy: cache-first for assets
+ // Default strategy: cache-first for static assets (CSS, JS libraries, images)
event.respondWith(
caches.match(event.request)
.then(response => {