-
Notifications
You must be signed in to change notification settings - Fork 0
/
sw.js
1 lines (1 loc) · 4.25 KB
/
sw.js
1
"use strict";const OFFLINE_DATA_FILE="offline.json",CACHE_NAME_PREFIX="c3offline",BROADCASTCHANNEL_NAME="offline",CONSOLE_PREFIX="[SW] ",LAZYLOAD_KEYNAME="",broadcastChannel="undefined"==typeof BroadcastChannel?null:new BroadcastChannel("offline");function PostBroadcastMessage(a){broadcastChannel&&setTimeout(()=>broadcastChannel.postMessage(a),3e3)}function Broadcast(a){PostBroadcastMessage({"type":a})}function BroadcastDownloadingUpdate(a){PostBroadcastMessage({"type":"downloading-update","version":a})}function BroadcastUpdateReady(a){PostBroadcastMessage({"type":"update-ready","version":a})}function IsUrlInLazyLoadList(a,b){if(!b)return!1;try{for(const c of b)if(new RegExp(c).test(a))return!0}catch(a){console.error("[SW] Error matching in lazy-load list: ",a)}return!1}function WriteLazyLoadListToStorage(a){return"undefined"==typeof localforage?Promise.resolve():localforage.setItem(LAZYLOAD_KEYNAME,a)}function ReadLazyLoadListFromStorage(){return"undefined"==typeof localforage?Promise.resolve([]):localforage.getItem(LAZYLOAD_KEYNAME)}function GetCacheBaseName(){return"c3offline-"+self.registration.scope}function GetCacheVersionName(a){return GetCacheBaseName()+"-v"+a}async function GetAvailableCacheNames(){const a=await caches.keys(),b=GetCacheBaseName();return a.filter((a)=>a.startsWith(b))}async function IsUpdatePending(){const a=await GetAvailableCacheNames();return 2<=a.length}async function GetMainPageUrl(){const a=await clients.matchAll({includeUncontrolled:!0,type:"window"});for(const b of a){let a=b.url;if(a.startsWith(self.registration.scope)&&(a=a.substring(self.registration.scope.length)),a&&"/"!==a)return a.startsWith("?")&&(a="/"+a),a}return""}function fetchWithBypass(a,b){return"string"==typeof a&&(a=new Request(a)),b?fetch(a.url,{headers:a.headers,mode:a.mode,credentials:a.credentials,redirect:a.redirect,cache:"no-store"}):fetch(a)}async function CreateCacheFromFileList(a,b,c){const d=await Promise.all(b.map((a)=>fetchWithBypass(a,c)));let e=!0;for(const f of d)f.ok||(e=!1,console.error("[SW] Error fetching '"+f.url+"' ("+f.status+" "+f.statusText+")"));if(!e)throw new Error("not all resources were fetched successfully");const f=await caches.open(a);try{return await Promise.all(d.map((a,c)=>f.put(b[c],a)))}catch(b){throw console.error("[SW] Error writing cache entries: ",b),caches.delete(a),b}}async function UpdateCheck(a){try{const b=await fetchWithBypass(OFFLINE_DATA_FILE,!0);if(!b.ok)throw new Error("offline.json responded with "+b.status+" "+b.statusText);const c=await b.json(),d=c.version,e=c.fileList,f=c.lazyLoad,g=GetCacheVersionName(d),h=await caches.has(g);if(h){const a=await IsUpdatePending();return void(a?(console.log("[SW] Update pending"),Broadcast("update-pending")):(console.log("[SW] Up to date"),Broadcast("up-to-date")))}const i=await GetMainPageUrl();e.unshift("./"),i&&-1===e.indexOf(i)&&e.unshift(i),console.log("[SW] Caching "+e.length+" files for offline use"),a?Broadcast("downloading"):BroadcastDownloadingUpdate(d),f&&(await WriteLazyLoadListToStorage(f)),await CreateCacheFromFileList(g,e,!a);const j=await IsUpdatePending();j?(console.log("[SW] All resources saved, update ready"),BroadcastUpdateReady(d)):(console.log("[SW] All resources saved, offline support ready"),Broadcast("offline-ready"))}catch(a){console.warn("[SW] Update check failed: ",a)}}self.addEventListener("install",(a)=>{a.waitUntil(UpdateCheck(!0).catch(()=>null))});async function GetCacheNameToUse(a,b){if(1===a.length||!b)return a[0];const c=await clients.matchAll();if(1<c.length)return a[0];const d=a[a.length-1];return console.log("[SW] Updating to new version"),await Promise.all(a.slice(0,-1).map((a)=>caches.delete(a))),d}async function HandleFetch(a,b){const c=await GetAvailableCacheNames();if(!c.length)return fetch(a.request);const d=await GetCacheNameToUse(c,b),e=await caches.open(d),f=await e.match(a.request);if(f)return f;const g=await Promise.all([fetch(a.request),ReadLazyLoadListFromStorage()]),h=g[0],i=g[1];if(IsUrlInLazyLoadList(a.request.url,i))try{await e.put(a.request,h.clone())}catch(b){console.warn("[SW] Error caching '"+a.request.url+"': ",b)}return h}self.addEventListener("fetch",(a)=>{if(new URL(a.request.url).origin===location.origin){const b="navigate"===a.request.mode,c=HandleFetch(a,b);b&&a.waitUntil(c.then(()=>UpdateCheck(!1))),a.respondWith(c)}});