PageSourceSearch

https://mywater.world/service-worker.js

js mywater.world collected 2026-10-06 12:16:17 UTC 7,840 bytes, 257 lines download raw bytes

1importScripts("/precache-manifest.4c83f0575b02bef20755ffb53c970b70.js", "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
2
3/**
4 * Welcome to your Workbox-powered service worker!
5 *
6 * You'll need to register this file in your web app and you should
7 * disable HTTP caching for this file too.
8 * See https://goo.gl/nhQhGp
9 */
10
11importScripts(
12  "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js",
13);
14
15// TODO: send an alert to the user when this data is about to expire
16// Ideally, users can look up when their cache is about to expire
17// by storing the date that they successfully performed a sync in the db.
18const TILE_CACHE_EXPIRATION = 24 * 60 * 60 * 90; // 90 days
19const TILE_CACHE_NAME = "tiles-cache";
20
21// This sets the logs level to mimic production level logging
22// Ideally, we should be able to filter out workbox logs in chrome by
23// using group, but there is a bug in chrome that prevents this:
24// https://bugs.chromium.org/p/chromium/issues/detail?id=363796
25// https://github.com/GoogleChrome/workbox/issues/1920
26workbox.setConfig({ debug: false });
27
28workbox.core.skipWaiting();
29workbox.core.clientsClaim();
30
31/**
32 * The workboxSW.precacheAndRoute() method efficiently caches and responds to
33 * requests for URLs in the manifest.
34 * See https://goo.gl/S9QRab
35 */
36self.__precacheManifest = [].concat(self.__precacheManifest || []);
37workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
38
39workbox.loadModule("workbox-strategies");
40workbox.loadModule("workbox-routing");
41
42// background sync for POST requests:
43const bgSyncPlugin = new workbox.backgroundSync.Plugin("mapseedBgQueue", {
44  maxRetentionTime: 72 * 60, // Retry for max of 72 Hours
45});
46
47const flavor = new URL(location).searchParams.get("flavor");
48
49// Set the cache names for our runtime cache and precache
50workbox.core.setCacheNameDetails({
51  prefix: flavor,
52  suffix: "v1",
53});
54
55const apiRoot = new URL(location).searchParams.get("apiRoot");
56// runtime cache for all calls to the local, prod, and dev api's explicitely:
57workbox.routing.registerRoute(
58  new RegExp(apiRoot),
59  new workbox.strategies.NetworkFirst({
60    plugins: [new workbox.cacheableResponse.Plugin({ statuses: [0, 200] })],
61  }),
62  "GET",
63);
64
65// We still need to respond to the request when the app is offline...
66// ...and update the map legend when a request "fails", but is in the cache
67
68self.addEventListener("fetch", event => {
69  if (event.request.method !== "POST") {
70    return;
71  }
72  const url = new URL(event.request.url, location);
73  const placesRegExp = new RegExp(
74    `${apiRoot}[a-zA-Z-]+/datasets/[a-zA-Z-]+/places$`,
75  );
76  if (placesRegExp.exec(url.href.split("?")[0])) {
77    const networkOnly = new workbox.strategies.NetworkOnly({
78      plugins: [bgSyncPlugin],
79    });
80    const getResponse = async () => {
81      let response;
82      try {
83        response = await networkOnly.handle({ event });
84      } catch (err) {
85        // the offline request was successfully cached in indexDB
86        // HACK: we are using the workbox error message here to detect
87        // whether our bgsync plugin performed a FETCH_DID_FAIL
88        // TODO: ideally, we'd query index db here...
89        // https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
90        // https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/offline-analytics/service-worker.js
91        // TODO: query indexdb for cached responses when the app first
92        // loads, allowing us to persist offline responses
93        if (err.name === "no-response") {
94          // Our api client will check for this type of body, and
95          // hydrate a Place model from it:
96          const blob = new Blob(
97            [JSON.stringify({ isOfflineResponse: true }, null, 2)],
98            { type: "application/json" },
99          );
100          return new Response(blob);
101        } else {
102          throw err;
103        }
104      }
105      return response;
106    };
107    event.respondWith(getResponse());
108  }
109});
110
111self.addEventListener("install", function (event) {
112  event.waitUntil(async () => {
113    // Create our tiles-cache:
114    caches.open(TILE_CACHE_NAME);
115  });
116});
117
118// ideally, these should be in our pre-cached bundles:
119const origin = location.origin;
120workbox.routing.registerRoute(
121  new RegExp(`${origin}/legacy-libs/`),
122  new workbox.strategies.NetworkFirst({
123    plugins: [new workbox.cacheableResponse.Plugin({ statuses: [0, 200] })],
124  }),
125  "GET",
126);
127
128workbox.routing.registerRoute(
129  new RegExp(`${origin}/static/`),
130  new workbox.strategies.NetworkFirst({
131    plugins: [new workbox.cacheableResponse.Plugin({ statuses: [0, 200] })],
132  }),
133  "GET",
134);
135
136workbox.routing.registerRoute(
137  /^http[s]?:\/\/cdnjs.cloudflare.com\/ajax\/libs\//,
138  new workbox.strategies.StaleWhileRevalidate(),
139  "GET",
140);
141
142workbox.routing.registerRoute(
143  /^http[s]?:\/\/maxcdn.bootstrapcdn.com\/font-awesome\//,
144  new workbox.strategies.StaleWhileRevalidate(),
145  "GET",
146);
147
148workbox.routing.registerRoute(
149  /^http[s]?:\/\/tile3.f4map.com\/tiles\/f4_2d\//,
150  new workbox.strategies.StaleWhileRevalidate({
151    cacheName: TILE_CACHE_NAME,
152    plugins: [
153      new workbox.expiration.Plugin({
154        maxAgeSeconds: TILE_CACHE_EXPIRATION,
155      }),
156    ],
157  }),
158  "GET",
159);
160
161workbox.routing.registerRoute(
162  /^http[s]?:\/\/api.tiles.mapbox.com\/v4\/smartercleanup.pe3o4gdn\//,
163  new workbox.strategies.StaleWhileRevalidate({
164    cacheName: TILE_CACHE_NAME,
165    plugins: [
166      new workbox.expiration.Plugin({
167        maxAgeSeconds: TILE_CACHE_EXPIRATION,
168      }),
169    ],
170  }),
171  "GET",
172);
173
174workbox.routing.registerRoute(
175  /^http[s]?:\/\/api.mapbox.com\/fonts\//,
176  new workbox.strategies.StaleWhileRevalidate({
177    cacheName: TILE_CACHE_NAME,
178    plugins: [
179      new workbox.expiration.Plugin({
180        maxAgeSeconds: TILE_CACHE_EXPIRATION,
181      }),
182    ],
183  }),
184  "GET",
185);
186
187workbox.routing.registerRoute(
188  /^https:\/\/assets.mapseed.org\/geo\//,
189  new workbox.strategies.StaleWhileRevalidate({
190    cacheName: TILE_CACHE_NAME,
191    plugins: [
192      new workbox.expiration.Plugin({
193        maxAgeSeconds: TILE_CACHE_EXPIRATION,
194      }),
195    ],
196  }),
197  "GET",
198);
199
200workbox.routing.registerRoute(
201  /^https:\/\/vector-tiles.mapseed.org\//,
202  new workbox.strategies.StaleWhileRevalidate({
203    cacheName: TILE_CACHE_NAME,
204    plugins: [
205      new workbox.expiration.Plugin({
206        maxAgeSeconds: TILE_CACHE_EXPIRATION,
207      }),
208    ],
209  }),
210  "GET",
211);
212
213// This plugin strips the `bbox` query param from requests.
214// The bbox param tends to have very high decimal precision, so it resuts in
215// numerous cache misses.
216// Since the bbox param is being stripped, it's important that urls supply an
217// alternative query param(s) to distinguish the request.
218// One option is to supply the `z`, `x`, and `y` params.
219// For example:
220// https://geo.mapseed.org/hydrography/?service=wms&request=getmap&format=image/png&version=1.3.0&crs=EPSG:3857&transparent=false&layers=0&bbox={bbox-epsg-3857}&width=256&height=256&styles=default&z={z}&x={x}&y={y}
221const cacheKeyWillBeUsed = ({ request, mode }) => {
222  const splitUrl = request.url.split("?");
223
224  if (splitUrl[1]) {
225    const parsed = splitUrl[1].split("&").reduce((memo, param) => {
226      const qsItem = param.split("=");
227
228      return {
229        ...memo,
230        [qsItem[0]]: qsItem[1],
231      };
232    }, {});
233    const { bbox, ...keep } = parsed;
234
235    return `${splitUrl[0]}?${Object.entries(keep).reduce(
236      (memo, [key, val]) => `${memo}&${key}=${val}`,
237      "",
238    )}`;
239  }
240
241  return request;
242};
243
244workbox.routing.registerRoute(
245  /^https:\/\/geo.mapseed.org\//,
246  new workbox.strategies.StaleWhileRevalidate({
247    cacheName: TILE_CACHE_NAME,
248    plugins: [
249      { cacheKeyWillBeUsed },
250      new workbox.expiration.Plugin({
251        maxAgeSeconds: TILE_CACHE_EXPIRATION,
252      }),
253    ],
254  }),
255  "GET",
256);
257

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.