-
-
Notifications
You must be signed in to change notification settings - Fork 126
Expand file tree
/
Copy pathservice-worker.js
More file actions
190 lines (166 loc) · 5.21 KB
/
service-worker.js
File metadata and controls
190 lines (166 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
'use strict';
// The name of your game, no spaces or special characters.
const name = 'Monogatari';
// The version of the cache, changing this will force everything to be cached
// again.
const version = '0.1.0';
const files = [
'/',
// General Files
'manifest.json',
// Engine Files
'engine/core/monogatari.css',
'engine/core/monogatari.js',
// HTML Files
'index.html',
// Style Sheets
'style/main.css',
// JavaScript Files
'js/options.js',
'js/storage.js',
'js/script.js',
'js/main.js',
// App Images
'favicon.ico',
'assets/icons/icon_48x48.png',
'assets/icons/icon_60x60.png',
'assets/icons/icon_70x70.png',
'assets/icons/icon_76x76.png',
'assets/icons/icon_96x96.png',
'assets/icons/icon_120x120.png',
'assets/icons/icon_128x128.png',
'assets/icons/icon_150x150.png',
'assets/icons/icon_152x152.png',
'assets/icons/icon_167x167.png',
'assets/icons/icon_180x180.png',
'assets/icons/icon_192x192.png',
'assets/icons/icon_310x150.png',
'assets/icons/icon_310x310.png',
'assets/icons/icon_512x512.png'
];
self.addEventListener ('install', (event) => {
self.skipWaiting ();
event.waitUntil (
caches.open (`${name}-v${version}`).then ((cache) => {
return cache.addAll (files);
})
);
});
self.addEventListener ('activate', (event) => {
event.waitUntil (
caches.keys ().then ((keyList) => {
return Promise.all (keyList.map ((key) => {
if (key !== `${name}-v${version}`) {
return caches.delete (key);
}
}));
})
);
return self.clients.claim ();
});
self.addEventListener ('fetch', (event) => {
if (event.request.method !== 'GET') {
return;
}
event.respondWith (
caches.match (event.request).then ((cached) => {
function fetchedFromNetwork (response) {
const cacheCopy = response.clone ();
caches.open (`${name}-v${version}`).then (function add (cache) {
cache.put (event.request, cacheCopy);
});
return response;
}
function unableToResolve () {
return new Response (`
<!DOCTYPE html><html lang=en><title>Bad Request</title><meta charset=UTF-8><meta content="width=device-width,initial-scale=1"name=viewport><style>body,html{width:100%;height:100%}body{text-align:center;color:#545454;margin:0;display:flex;justify-content:center;align-items:center;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Open Sans","Fira Sans","Droid Sans","Helvetica Neue",sans-serif}h1,h2{font-weight:lighter}h1{font-size:4em}h2{font-size:2em}</style><div><h1>Service Unavailable</h1><h2>Sorry, the server is currently unavailable or under maintenance, try again later.</h2></div>
`, {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers ({
'Content-Type': 'text/html'
})
});
}
const networked = fetch (event.request)
.then (fetchedFromNetwork, unableToResolve)
.catch (unableToResolve);
return cached || networked;
})
);
});
// Message handlers for communication with main thread
// Message format: { type: string, data: object }
// Response format varies by type
self.addEventListener ('message', async (event) => {
const { type, data } = event.data || {};
const respond = (response, transfer) => {
event.ports[0]?.postMessage (response, transfer);
};
switch (type) {
// Cache multiple assets on demand
// data: { urls: string[] }
// response: { success: boolean, cached?: number, total?: number, error?: string }
case 'CACHE_ASSETS': {
const { urls } = data || {};
if (!Array.isArray (urls)) {
respond ({ success: false, error: 'urls must be an array' });
return;
}
try {
const cache = await caches.open (`${name}-v${version}`);
const results = await Promise.allSettled (
urls.map ((assetUrl) => cache.add (assetUrl))
);
const successCount = results.filter ((r) => r.status === 'fulfilled').length;
respond ({ success: true, cached: successCount, total: urls.length });
} catch (error) {
respond ({ success: false, error: error.message });
}
break;
}
// Check if a single asset is in cache
// data: { url: string }
// response: { cached: boolean, error?: string }
case 'CHECK_CACHE': {
const { url } = data || {};
if (!url) {
respond ({ cached: false, error: 'url is required' });
return;
}
try {
const cache = await caches.open (`${name}-v${version}`);
const response = await cache.match (url);
respond ({ cached: !!response });
} catch (error) {
respond ({ cached: false, error: error.message });
}
break;
}
// Get raw cached response for an asset (for decoding)
// data: { url: string }
// response: { found: boolean, data?: ArrayBuffer, error?: string }
case 'GET_CACHED': {
const { url } = data || {};
if (!url) {
respond ({ found: false, error: 'url is required' });
return;
}
try {
const cache = await caches.open (`${name}-v${version}`);
const response = await cache.match (url);
if (response) {
const arrayBuffer = await response.arrayBuffer ();
respond ({ found: true, data: arrayBuffer }, [arrayBuffer]);
} else {
respond ({ found: false });
}
} catch (error) {
respond ({ found: false, error: error.message });
}
break;
}
default:
respond ({ error: `Unknown message type: ${type}` });
}
});