PageSourceSearch

https://www.siamdive.com/sw.js

js siamdive.com collected 2026-10-05 21:53:51 UTC 2,870 bytes, 71 lines download raw bytes

1// Minimal service worker for installability + an offline fallback for the app shell.
2// Network-first for navigations (so chat/data stay fresh), cache-first for static icons.
3const CACHE = "sd2-v4";
4const SHELL = ["/icon-192.png", "/ai-mask.png"];
5
6self.addEventListener("install", (e) => {
7  e.waitUntil(caches.open(CACHE).then((c) => c.addAll(SHELL)).then(() => self.skipWaiting()));
8});
9
10self.addEventListener("activate", (e) => {
11  e.waitUntil(
12    caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))).then(() => self.clients.claim()),
13  );
14});
15
16self.addEventListener("fetch", (e) => {
17  const req = e.request;
18  if (req.method !== "GET") return;
19  const url = new URL(req.url);
20  // Never cache API or auth — always go to network.
21  if (url.pathname.includes("/api/")) return;
22
23  if (req.mode === "navigate") {
24    // Network-first; keep a copy of the LAST GOOD shell at runtime so a flaky
25    // network / post-crash reload gets the app back instead of the browser's
26    // "This page couldn't load" (we no longer pre-cache "/" — it masked deploys).
27    e.respondWith(
28      fetch(req)
29        .then((res) => {
30          if (res.ok) {
31            const copy = res.clone();
32            caches.open(CACHE).then((c) => c.put("/", copy));
33          }
34          return res;
35        })
36        .catch(() => caches.match("/").then((r) => r || Response.error())),
37    );
38    return;
39  }
40  e.respondWith(
41    caches.match(req).then((cached) => cached || fetch(req).then((res) => {
42      if (res.ok && (url.pathname.endsWith(".png") || url.pathname.endsWith(".svg"))) {
43        const copy = res.clone();
44        caches.open(CACHE).then((c) => c.put(req, copy));
45      }
46      return res;
47    })),
48  );
49});
50
51// ── Web Push: แจ้งเตือนสถานะการจอง (admin เปลี่ยนสถานะ → server ยิง push มาที่นี่) ──
52self.addEventListener("push", (e) => {
53  let d = {};
54  try { d = e.data ? e.data.json() : {}; } catch { d = { body: e.data && e.data.text() }; }
55  e.waitUntil(self.registration.showNotification(d.title || "SiamDive", {
56    body: d.body || "",
57    icon: "/icon-192.png",
58    badge: "/icon-192.png",
59    tag: d.tag || "siamdive-booking", // แจ้งเตือนสถานะเดิมซ้ำ → แทนที่อันเก่า ไม่กองซ้อน
60    data: { url: d.url || "/" },
61  }));
62});
63
64self.addEventListener("notificationclick", (e) => {
65  e.notification.close();
66  const url = (e.notification.data && e.notification.data.url) || "/";
67  e.waitUntil(self.clients.matchAll({ type: "window", includeUncontrolled: true }).then((list) => {
68    for (const c of list) { if (c.url.includes(url.split("?")[0]) && "focus" in c) return c.focus(); }
69    return self.clients.openWindow(url);
70  }));
71});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.