supersam/public/service-worker.js

142 lines
4.4 KiB
JavaScript

const isLocalhost = self.location.hostname === "localhost" || self.location.hostname === "127.0.0.1";
if (!isLocalhost) {
const STATIC_CACHE = "construction-delivery-static-v109";
const RUNTIME_CACHE = "construction-delivery-runtime-v109";
const APP_SHELL_URLS = ["/", "/client", "/index.html", "/manifest.webmanifest", "/icons/icon-192.png", "/icons/icon-512.png"];
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(STATIC_CACHE).then((cache) => cache.addAll(APP_SHELL_URLS)).then(() => self.skipWaiting()),
);
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches
.keys()
.then((keys) =>
Promise.all(
keys
.filter((key) => ![STATIC_CACHE, RUNTIME_CACHE].includes(key))
.map((key) => caches.delete(key)),
),
)
.then(() => self.clients.claim())
.then(async () => {
const clients = await self.clients.matchAll({ includeUncontrolled: true });
clients.forEach((client) => client.postMessage({ type: "PWA_OFFLINE_READY" }));
}),
);
});
self.addEventListener("fetch", (event) => {
if (event.request.method !== "GET") {
return;
}
const requestUrl = new URL(event.request.url);
const isSameOrigin = requestUrl.origin === self.location.origin;
if (event.request.mode === "navigate") {
event.respondWith(
fetch(event.request)
.then((response) => {
const responseClone = response.clone();
caches.open(RUNTIME_CACHE).then((cache) => cache.put(event.request, responseClone));
return response;
})
.catch(async () => {
const cachedPage = await caches.match(event.request);
return cachedPage || caches.match("/index.html");
}),
);
return;
}
if (!isSameOrigin) {
return;
}
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request).then((response) => {
if (!response || response.status !== 200) {
return response;
}
const responseClone = response.clone();
caches.open(RUNTIME_CACHE).then((cache) => cache.put(event.request, responseClone));
return response;
});
}),
);
});
} else {
self.addEventListener("install", (event) => self.skipWaiting());
self.addEventListener("activate", (event) => self.clients.claim());
}
// Push notification handler
self.addEventListener("push", (event) => {
let data = {};
try {
data = event.data ? event.data.json() : {};
} catch {
data = { title: "Уведомление", body: "" };
}
const { title, body, url } = data;
const targetUrl = (() => {
if (!url) return "/client";
try {
const parsed = new URL(url, self.location.origin);
if (parsed.origin !== self.location.origin) return "/client";
const legacyMatch = parsed.pathname.match(/^\/delivery\/([^/]+)$/);
if (legacyMatch) return `/client/${legacyMatch[1]}${parsed.search}${parsed.hash}`;
return parsed.pathname.startsWith("/client")
? `${parsed.pathname}${parsed.search}${parsed.hash}`
: "/client";
} catch {
return "/client";
}
})();
event.waitUntil(
self.registration.showNotification(title || "Уведомление", {
body: body || "",
icon: "/icons/icon-512.png",
data: { url: targetUrl },
}),
);
});
// Notification click handler
self.addEventListener("notificationclick", (event) => {
event.notification.close();
const targetPath = (event.notification.data && event.notification.data.url) || "/client";
const targetUrl = new URL(targetPath, self.location.origin).href;
event.waitUntil(
self.clients.matchAll({ type: "window", includeUncontrolled: true }).then(async (clientList) => {
const sameOriginClient = clientList.find((client) => {
try {
return new URL(client.url).origin === self.location.origin;
} catch {
return false;
}
});
if (sameOriginClient) {
if ("navigate" in sameOriginClient) await sameOriginClient.navigate(targetUrl);
return "focus" in sameOriginClient ? sameOriginClient.focus() : undefined;
}
return self.clients.openWindow(targetUrl);
}),
);
});