PageSourceSearch

https://atchison-golfclub.web.app/sw-register.js

js atchison-golfclub.web.app collected 2026-10-03 12:17:22 UTC 5,255 bytes, 114 lines download raw bytes

1/**
2 * Service worker registration + one-time incident auto-recovery.
3 *
4 * AUTO-RESET (transparent to the user):
5 *   Older builds (v19.x) shipped service workers that intercepted clean-URL
6 *   navigations and cached HTML/JS aggressively. After deploying the v20.0.0
7 *   safe-mode worker, devices that already had the old worker installed can
8 *   still see "wonky" loading because old caches + a fresh SW briefly coexist.
9 *
10 *   To avoid asking 200 members to type "?reset=1", every browser that hasn't
11 *   yet seen the current INCIDENT_RESET_VERSION will, exactly once:
12 *     1. unregister every existing service worker registration on this origin,
13 *     2. delete every Cache Storage entry,
14 *     3. set a localStorage flag so this never runs again on this device,
15 *     4. reload the page so the next paint is a fully clean cold-start.
16 *
17 *   After that one auto-reload the browser is on the safe-mode SW (v20.0.0)
18 *   with no stale caches and behaves like plain HTML over Firebase Hosting.
19 *
20 * Once recovery is complete, this file just (a) registers the SW once per tab
21 * and (b) optionally checks for SW updates at most once every 6 hours per
22 * device. No periodic update polling. No controllerchange auto-reload loops.
23 */
24(function () {
25  if (typeof window === 'undefined') return;
26
27  // Bump this string ONLY when another incident requires a forced device-wide
28  // reset for users who picked up a bad build. Increment the date/suffix.
29  var INCIDENT_RESET_VERSION = '2026-05-14-incident-1';
30  var FLAG_KEY = 'atchison_incident_reset_version';
31  var IN_PROGRESS_FLAG = 'atchison_incident_reset_in_progress';
32
33  function safeLocalGet(k) { try { return localStorage.getItem(k); } catch (e) { return null; } }
34  function safeLocalSet(k, v) { try { localStorage.setItem(k, v); } catch (e) {} }
35  function safeSessionGet(k) { try { return sessionStorage.getItem(k); } catch (e) { return null; } }
36  function safeSessionSet(k, v) { try { sessionStorage.setItem(k, v); } catch (e) {} }
37  function safeSessionRemove(k) { try { sessionStorage.removeItem(k); } catch (e) {} }
38
39  // Belt-and-suspenders: localStorage may be disabled (incognito + extra-strict
40  // tracking protection). Also accept sessionStorage as proof that recovery ran
41  // at least once this session, so we never get stuck in a reload loop.
42  function resetAlreadyRan() {
43    return safeLocalGet(FLAG_KEY) === INCIDENT_RESET_VERSION ||
44           safeSessionGet(FLAG_KEY) === INCIDENT_RESET_VERSION;
45  }
46  function markResetRan() {
47    safeLocalSet(FLAG_KEY, INCIDENT_RESET_VERSION);
48    safeSessionSet(FLAG_KEY, INCIDENT_RESET_VERSION);
49  }
50
51  // If we're mid-reset on this tab, do NOT loop. Clear the in-progress flag
52  // (it only needs to survive one reload) and continue to normal registration.
53  if (safeSessionGet(IN_PROGRESS_FLAG)) {
54    safeSessionRemove(IN_PROGRESS_FLAG);
55    markResetRan();
56  } else if (!resetAlreadyRan()) {
57    // Mark as done BEFORE doing anything so we cannot loop even if the reload
58    // races with another script. Also set a tab-local flag so the post-reload
59    // load doesn't re-trigger when localStorage has just been written.
60    markResetRan();
61    safeSessionSet(IN_PROGRESS_FLAG, '1');
62
63    (async function recoverOnce() {
64      try {
65        if ('serviceWorker' in navigator) {
66          var regs = [];
67          try { regs = await navigator.serviceWorker.getRegistrations(); } catch (_) {}
68          await Promise.all((regs || []).map(function (r) {
69            try { return r.unregister(); } catch (_) { return Promise.resolve(); }
70          }));
71        }
72      } catch (_) {}
73      try {
74        if ('caches' in window) {
75          var names = [];
76          try { names = await caches.keys(); } catch (_) {}
77          await Promise.all((names || []).map(function (n) {
78            try { return caches.delete(n); } catch (_) { return Promise.resolve(); }
79          }));
80        }
81      } catch (_) {}
82      // Hard reload — bypass HTTP cache via cache-buster.
83      try {
84        var u = new URL(window.location.href);
85        u.searchParams.set('_v', Date.now());
86        window.location.replace(u.toString());
87      } catch (_) {
88        try { window.location.reload(); } catch (_) {}
89      }
90    })();
91    return; // Do NOT register a SW on this load; the next load will.
92  }
93
94  // ── Normal SW registration (post-recovery) ──────────────────────────────
95  if (!('serviceWorker' in navigator)) return;
96  if (window.__atchisonSwRegisterDone) return;
97  window.__atchisonSwRegisterDone = true;
98
99  var opts = { updateViaCache: 'none' };
100  navigator.serviceWorker.register('./sw.js', opts).catch(function () {});
101
102  try {
103    var k = 'atchison_sw_update_check_at';
104    var last = parseInt(localStorage.getItem(k) || '0', 10) || 0;
105    var now = Date.now();
106    var sixHours = 6 * 60 * 60 * 1000;
107    if (now - last >= sixHours) {
108      localStorage.setItem(k, String(now));
109      navigator.serviceWorker.getRegistration().then(function (reg) {
110        if (reg) return reg.update();
111      }).catch(function () {});
112    }
113  } catch (e) {}
114})();

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.