ramp to values to avoid audio glitches
[nanofun.git] / service-worker.js
1 /* global self, caches, fetch, URL, Response */
2 'use strict';
3
4 var config = {
5   version: 'v1',
6   staticCacheItems: [
7     'index.html',
8     'jquery.min.js',
9     'nanofun.js',
10     'nanofun.css'
11   ]
12 };
13
14 function cacheName (key, opts) {
15   return `${opts.version}-${key}`;
16 }
17
18 function addToCache (cacheKey, request, response) {
19   if (response.ok) {
20     var copy = response.clone();
21     caches.open(cacheKey).then( cache => {
22       cache.put(request, copy);
23     });
24   }
25   return response;
26 }
27
28 function fetchFromCache (event) {
29   return caches.match(event.request).then(response => {
30     if (!response) {
31       throw Error(`${event.request.url} not found in cache`);
32     }
33     return response;
34   });
35 }
36
37 function offlineResponse (resourceType, opts) {
38   return undefined;
39 }
40
41 self.addEventListener('install', event => {
42   function onInstall (event, opts) {
43     var cacheKey = cacheName('static', opts);
44     return caches.open(cacheKey)
45       .then(cache => cache.addAll(opts.staticCacheItems));
46   }
47
48   event.waitUntil(
49     onInstall(event, config).then( () => self.skipWaiting() )
50   );
51 });
52
53 self.addEventListener('activate', event => {
54   function onActivate (event, opts) {
55     return caches.keys()
56       .then(cacheKeys => {
57         var oldCacheKeys = cacheKeys.filter(key => key.indexOf(opts.version) !== 0);
58         var deletePromises = oldCacheKeys.map(oldKey => caches.delete(oldKey));
59         return Promise.all(deletePromises);
60       });
61   }
62
63   event.waitUntil(
64     onActivate(event, config)
65       .then( () => self.clients.claim() )
66   );
67 });
68
69 self.addEventListener('fetch', event => {
70
71   function shouldHandleFetch (event, opts) {
72     var request            = event.request;
73     var url                = new URL(request.url);
74     var criteria           = {
75       isGETRequest      : request.method === 'GET',
76       isFromMyOrigin    : url.origin === self.location.origin
77     };
78     var failingCriteria    = Object.keys(criteria)
79       .filter(criteriaKey => !criteria[criteriaKey]);
80     return !failingCriteria.length;
81   }
82
83   function onFetch (event, opts) {
84     var request = event.request;
85     var acceptHeader = request.headers.get('Accept');
86     var resourceType = 'static';
87     var cacheKey;
88
89     if (acceptHeader.indexOf('text/html') !== -1) {
90       resourceType = 'content';
91     } else if (acceptHeader.indexOf('image') !== -1) {
92       resourceType = 'image';
93     }
94
95     resourceType = 'content'; // always force network first for now
96
97     cacheKey = cacheName(resourceType, opts);
98
99     if (resourceType === 'content') {
100       event.respondWith(
101         fetch(request)
102           .then(response => addToCache(cacheKey, request, response))
103           .catch(() => fetchFromCache(event))
104           .catch(() => offlineResponse(resourceType, opts))
105       );
106     } else {
107       event.respondWith(
108         fetchFromCache(event)
109           .catch(() => fetch(request))
110             .then(response => addToCache(cacheKey, request, response))
111           .catch(() => offlineResponse(resourceType, opts))
112       );
113     }
114   }
115   if (shouldHandleFetch(event, config)) {
116     onFetch(event, config);
117   }
118
119 });