37ddfb128b
Download htmx.org v1.9.10 into static/htmx.min.js and update all references (layout.html, handlers.go fallback page, sw.js precache list) to use the local copy. This enables the PWA to work fully offline since the service worker can now cache htmx from the same origin. Bump service worker cache version to v2 so existing installations pick up the new asset list. Closes leeworks-agents/gitea-mobile#17 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
87 lines
2.3 KiB
JavaScript
87 lines
2.3 KiB
JavaScript
// Service Worker for Gitea Mobile PWA
|
|
// Caches the app shell for offline/fast loading.
|
|
|
|
const CACHE_NAME = 'gitea-mobile-v2';
|
|
const APP_SHELL = [
|
|
'/',
|
|
'/static/style.css',
|
|
'/static/manifest.json',
|
|
'/static/icon-192.png',
|
|
'/static/icon-512.png',
|
|
'/static/htmx.min.js'
|
|
];
|
|
|
|
// Install: cache app shell resources.
|
|
self.addEventListener('install', (event) => {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then((cache) => {
|
|
return cache.addAll(APP_SHELL);
|
|
})
|
|
);
|
|
// Activate immediately.
|
|
self.skipWaiting();
|
|
});
|
|
|
|
// Activate: clean up old caches.
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil(
|
|
caches.keys().then((cacheNames) => {
|
|
return Promise.all(
|
|
cacheNames
|
|
.filter((name) => name !== CACHE_NAME)
|
|
.map((name) => caches.delete(name))
|
|
);
|
|
})
|
|
);
|
|
// Take control of all clients immediately.
|
|
self.clients.claim();
|
|
});
|
|
|
|
// Fetch: network-first for API/HTML, cache-first for static assets.
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = new URL(event.request.url);
|
|
|
|
// Cache-first for static assets.
|
|
if (url.pathname.startsWith('/static/')) {
|
|
event.respondWith(
|
|
caches.match(event.request).then((cached) => {
|
|
return cached || fetch(event.request).then((response) => {
|
|
// Cache the fetched response for next time.
|
|
const responseClone = response.clone();
|
|
caches.open(CACHE_NAME).then((cache) => {
|
|
cache.put(event.request, responseClone);
|
|
});
|
|
return response;
|
|
});
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Network-first for HTML/API requests.
|
|
if (event.request.headers.get('accept')?.includes('text/html') ||
|
|
event.request.headers.get('HX-Request')) {
|
|
event.respondWith(
|
|
fetch(event.request)
|
|
.then((response) => {
|
|
// Cache successful GET responses.
|
|
if (event.request.method === 'GET' && response.ok) {
|
|
const responseClone = response.clone();
|
|
caches.open(CACHE_NAME).then((cache) => {
|
|
cache.put(event.request, responseClone);
|
|
});
|
|
}
|
|
return response;
|
|
})
|
|
.catch(() => {
|
|
// Fallback to cache if network fails.
|
|
return caches.match(event.request);
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Default: network only.
|
|
event.respondWith(fetch(event.request));
|
|
});
|