You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.6 KiB
JavaScript
92 lines
2.6 KiB
JavaScript
/**
|
|
* Service Worker — Italiano Vivo
|
|
* Estratégia:
|
|
* - Shell (HTML/CSS/JS do app): cache-first
|
|
* - /content/* e /audio/*: cache-first com network fallback + runtime caching
|
|
* - /api/*: network-only (nunca cachear)
|
|
*
|
|
* Objetivo: modo resgate offline — frases + áudio já baixados funcionam no avião.
|
|
*/
|
|
|
|
const CACHE_NAME = "italiano-vivo-v1";
|
|
const SHELL_ASSETS = ["/", "/index.html"];
|
|
|
|
// ─── Install: pré-cache do shell ───
|
|
self.addEventListener("install", (event) => {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then((cache) => cache.addAll(SHELL_ASSETS)),
|
|
);
|
|
self.skipWaiting();
|
|
});
|
|
|
|
// ─── Activate: limpar caches antigos ───
|
|
self.addEventListener("activate", (event) => {
|
|
event.waitUntil(
|
|
caches.keys().then((keys) =>
|
|
Promise.all(
|
|
keys
|
|
.filter((k) => k !== CACHE_NAME)
|
|
.map((k) => caches.delete(k)),
|
|
),
|
|
),
|
|
);
|
|
self.clients.claim();
|
|
});
|
|
|
|
// ─── Fetch: roteamento por padrão de URL ───
|
|
self.addEventListener("fetch", (event) => {
|
|
const url = new URL(event.request.url);
|
|
const pathname = url.pathname;
|
|
|
|
// API: sempre network-only
|
|
if (pathname.startsWith("/api/")) {
|
|
return; // deixa o browser fazer o fetch normal
|
|
}
|
|
|
|
// Content e Audio: cache-first com network fallback + runtime caching
|
|
if (pathname.startsWith("/content/") || pathname.startsWith("/audio/")) {
|
|
event.respondWith(cacheFirstWithRuntimeCache(event.request));
|
|
return;
|
|
}
|
|
|
|
// Shell e demais assets: cache-first
|
|
event.respondWith(cacheFirst(event.request));
|
|
});
|
|
|
|
/**
|
|
* Cache-first: tenta cache, se não achar vai na rede (sem salvar no cache).
|
|
* Usado para shell/assets que são pré-cachados no install.
|
|
*/
|
|
async function cacheFirst(request) {
|
|
const cached = await caches.match(request);
|
|
if (cached) return cached;
|
|
return fetch(request);
|
|
}
|
|
|
|
/**
|
|
* Cache-first com runtime caching: tenta cache, se não achar vai na rede
|
|
* e salva a resposta no cache para uso offline futuro.
|
|
* Usado para /content/* e /audio/* que são baixados sob demanda.
|
|
*/
|
|
async function cacheFirstWithRuntimeCache(request) {
|
|
const cached = await caches.match(request);
|
|
if (cached) return cached;
|
|
|
|
try {
|
|
const response = await fetch(request);
|
|
// Só cachear respostas OK (não cachear 404/500)
|
|
if (response.ok) {
|
|
const cache = await caches.open(CACHE_NAME);
|
|
cache.put(request, response.clone());
|
|
}
|
|
return response;
|
|
} catch (_err) {
|
|
// Offline e sem cache: retorna erro genérico
|
|
return new Response("Offline — Italiano Vivo", {
|
|
status: 503,
|
|
statusText: "Service Unavailable",
|
|
headers: { "Content-Type": "text/plain" },
|
|
});
|
|
}
|
|
}
|