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.