aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/public/pwa-worker.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/public/pwa-worker.js')
-rw-r--r--src/frontend/public/pwa-worker.js147
1 files changed, 43 insertions, 104 deletions
diff --git a/src/frontend/public/pwa-worker.js b/src/frontend/public/pwa-worker.js
index f47ede0..ef696fe 100644
--- a/src/frontend/public/pwa-worker.js
+++ b/src/frontend/public/pwa-worker.js
@@ -1,49 +1,45 @@
-const CACHE_VERSION = "2025-0806a";
-const API_CACHE_NAME = `api-cache-${CACHE_VERSION}`;
+const CACHE_VERSION = "2025-0907a";
const STATIC_CACHE_NAME = `static-cache-${CACHE_VERSION}`;
+const STATIC_CACHE_ASSETS = [
+ "/favicon.ico",
+ "/logo-256.png",
+ "/logo-512.jpg",
+ "/stops.json"
+];
+
+const EXPR_CACHE_AFTER_FIRST_VIEW = /(\/assets\/.*)|(\/api\/GetStopTimetable.*)/;
-const API_URL_PATTERN = /\/api\/(GetStopList|GetStopEstimates|GetStopTimetable)/;
-const API_MAX_AGE = 24 * 60 * 60 * 1000; // 24h
const ESTIMATES_MIN_AGE = 15 * 1000;
const ESTIMATES_MAX_AGE = 30 * 1000;
self.addEventListener("install", (event) => {
- console.log("SW: Installing new version");
+ console.log("SW: Install event in progress. Cache version: ", CACHE_VERSION);
event.waitUntil(
caches.open(STATIC_CACHE_NAME).then((cache) =>
- cache.addAll([
- "/favicon.ico",
- "/logo-256.png",
- "/logo-512.jpg",
- "/stops.json"
- ])
+ cache.addAll(STATIC_CACHE_ASSETS)
).then(() => self.skipWaiting())
);
});
self.addEventListener("activate", (event) => {
- console.log("SW: Activating new version");
- event.waitUntil(
- (async () => {
- const cacheNames = await caches.keys();
- await Promise.all(
- cacheNames.map((name) => {
- if (name !== API_CACHE_NAME && name !== STATIC_CACHE_NAME) {
- console.log("SW: Deleting old cache:", name);
- return caches.delete(name);
- }
- })
- );
- await self.clients.claim();
- const clients = await self.clients.matchAll();
- clients.forEach((client) =>
- client.postMessage({ type: "SW_UPDATED" })
- );
- })()
- );
+ const doCleanup = async () => {
+ // Cleans the old caches
+ const cacheNames = await caches.keys();
+ await Promise.all(
+ cacheNames.map((name) => {
+ if (name !== STATIC_CACHE_NAME) {
+ return caches.delete(name);
+ }
+ })
+ );
+
+ await self.clients.claim();
+ }
+
+ event.waitUntil(doCleanup());
});
-self.addEventListener("fetch", (event) => {
+self.addEventListener("fetch", async (event) => {
const request = event.request;
const url = new URL(request.url);
@@ -52,94 +48,37 @@ self.addEventListener("fetch", (event) => {
return;
}
- // API
- if (request.method === "GET" && API_URL_PATTERN.test(url.pathname)) {
- event.respondWith(handleApiRequest(request));
- return;
- }
-
- // Navegación -> network first
+ // Navigating => we don't intercept anything, if it fails, good luck
if (request.mode === "navigate") {
- event.respondWith(handleNavigationRequest(request));
return;
}
- // Estáticos -> cache first
- if (request.method === "GET") {
- event.respondWith(handleStaticRequest(request));
- }
-});
-
-async function handleApiRequest(request) {
- const url = new URL(request.url);
- const isEstimates = url.pathname.includes("GetStopEstimates");
- const maxAge = isEstimates
- ? ESTIMATES_MIN_AGE + Math.random() * (ESTIMATES_MAX_AGE - ESTIMATES_MIN_AGE)
- : API_MAX_AGE;
-
- const cache = await caches.open(API_CACHE_NAME);
- const cachedResponse = await cache.match(request);
-
- if (cachedResponse) {
- const dateHeader = cachedResponse.headers.get("date");
- const age = dateHeader ? Date.now() - new Date(dateHeader).getTime() : 0;
- if (age && age < maxAge) {
- console.debug("SW: Cache HIT", request.url);
- return cachedResponse;
+ // Static => cache first, if not, network; if not, fallback
+ const isAssetCacheable = STATIC_CACHE_ASSETS.includes(url.pathname) || EXPR_CACHE_AFTER_FIRST_VIEW.test(url.pathname);
+ if (request.method === "GET" && isAssetCacheable) {
+ const response = handleStaticRequest(request);
+ if (response !== null) {
+ event.respondWith(response);
}
- cache.delete(request);
- }
-
- try {
- const netResponse = await fetch(request);
- if (netResponse.ok) cache.put(request, netResponse.clone());
- return netResponse;
- } catch (error) {
- if (cachedResponse) return cachedResponse;
- throw error;
+ return;
}
-}
+});
async function handleStaticRequest(request) {
const cache = await caches.open(STATIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
- if (cachedResponse) return cachedResponse;
-
- try {
- const netResponse = await fetch(request);
- if (netResponse.ok) cache.put(request, netResponse.clone());
- return netResponse;
- } catch (err) {
- return new Response("Offline asset not available", {
- status: 503,
- headers: { "Content-Type": "text/plain" }
- });
+ if (cachedResponse){
+ console.log("SW handleStaticRequest: HIT for ", request.url);
+ return cachedResponse;
}
-}
-async function handleNavigationRequest(request) {
try {
const netResponse = await fetch(request);
+ if (netResponse.ok) cache.put(request, netResponse.clone());
+ console.log("SW handleStaticRequest: MISS for ", request.url);
return netResponse;
} catch (err) {
- // Si no hay red, intenta fallback con caché estática
- const cache = await caches.open(STATIC_CACHE_NAME);
- const offline = await cache.match("/stops.json");
- return (
- offline ||
- new Response("App offline", {
- status: 503,
- headers: { "Content-Type": "text/plain" }
- })
- );
+ console.error("SW handleStaticRequest: FAIL for ", request.url, err);
+ return null;
}
}
-
-self.addEventListener("message", (event) => {
- if (event.data?.type === "SKIP_WAITING") self.skipWaiting();
- if (event.data?.type === "CLEAR_CACHE") {
- event.waitUntil(
- caches.keys().then((names) => Promise.all(names.map((n) => caches.delete(n))))
- );
- }
-});