-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsw.js
More file actions
126 lines (115 loc) · 4.47 KB
/
Copy pathsw.js
File metadata and controls
126 lines (115 loc) · 4.47 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
/* ===========================================================================
* sw.js — the service worker: shell offline, indexes cached once.
*
* Three kinds of request:
* the app itself → network first, the cached copy answers when the
* network is slow or gone. While the app is being
* developed, a cached copy of index.js must never
* win over the file that was just edited.
* HadithData/** → cache first: the corpus only changes when the
* data is rebuilt, and the indexes are 3 MB and
* 10 MB, so they are worth keeping
* jsdelivr (transformers.js)→ stale-while-revalidate, because that runtime
* must load for meaning search to work offline
*
* The embedding model itself is cached by transformers.js in its own cache, so
* it is deliberately left alone here.
* =========================================================================== */
'use strict';
const VERSION = 'v2';
const SHELL_CACHE = `hadith-shell-${VERSION}`;
const DATA_CACHE = 'hadith-data';
const RUNTIME_CACHE = 'hadith-runtime';
const SHELL_FILES = [
'./',
'index.html',
'index.js',
'search.js',
'hadith-core.js',
'hadith-index.js',
'hadith-search.js',
'embed-worker.js',
'manifest.webmanifest',
'icons/icon.svg'
];
self.addEventListener('install', event => {
event.waitUntil((async () => {
const cache = await caches.open(SHELL_CACHE);
for (const file of SHELL_FILES) {
try {
await cache.add(new Request(file, { cache: 'reload' }));
} catch (error) {
/* one missing file must not stop the install */
}
}
await self.skipWaiting();
})());
});
self.addEventListener('activate', event => {
event.waitUntil((async () => {
const keep = new Set([SHELL_CACHE, DATA_CACHE, RUNTIME_CACHE]);
for (const name of await caches.keys()) {
if (name.startsWith('hadith-') && !keep.has(name)) await caches.delete(name);
}
await self.clients.claim();
})());
});
async function cacheFirst(request, cacheName) {
const cache = await caches.open(cacheName);
const hit = await cache.match(request, { ignoreSearch: true });
if (hit) return hit;
const response = await fetch(request);
if (response.ok) await cache.put(request, response.clone());
return response;
}
async function staleWhileRevalidate(request, cacheName) {
const cache = await caches.open(cacheName);
const hit = await cache.match(request, { ignoreSearch: true });
const network = fetch(request).then(response => {
if (response.ok) cache.put(request, response.clone());
return response;
}).catch(() => null);
return hit || (await network) || Response.error();
}
async function networkFirst(request) {
const cache = await caches.open(SHELL_CACHE);
try {
const response = await fetch(request);
if (response.ok) cache.put(request, response.clone());
return response;
} catch (error) {
const hit = await cache.match(request, { ignoreSearch: true })
|| await cache.match('index.html')
|| await cache.match('./');
if (hit) return hit;
throw error;
}
}
self.addEventListener('fetch', event => {
const request = event.request;
if (request.method !== 'GET') return;
const url = new URL(request.url);
if (url.origin === location.origin) {
if (url.pathname.includes('/HadithData/index/')) {
event.respondWith(cacheFirst(request, DATA_CACHE));
return;
}
if (url.pathname.includes('/HadithData/')) {
event.respondWith(staleWhileRevalidate(request, DATA_CACHE));
return;
}
if (request.mode === 'navigate' || url.pathname.endsWith('/')) {
event.respondWith(networkFirst(request));
return;
}
/* Everything else that belongs to the app: network first as well, with
the cache as the fallback that makes it work offline. */
event.respondWith(networkFirst(request));
return;
}
if (url.hostname === 'cdn.jsdelivr.net') {
event.respondWith(staleWhileRevalidate(request, RUNTIME_CACHE));
}
/* everything else (the model files on huggingface.co) is left to the
library's own cache */
});