forked from roxiness/routify
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathworkbox-plugin.js
90 lines (74 loc) · 2.96 KB
/
workbox-plugin.js
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
// @ts-check
const freshCache = {
map: new Map(),
set(req, value) { return this.map.set(reqToStr(req), value) },
get(req) {
const cache = this.map.get(reqToStr(req))
// @ts-ignore
if (cache) cache.validLeft = (new Date(cache.validUntil) - new Date())/1000
return cache
}
}
export const RoutifyPlugin = function (defaultOptions) {
return {
cachedResponseWillBeUsed({ cacheName, request, matchOptions, cachedResponse, event }) {
if (getHeaderOptions(request).writeHeaders !== true)
return cachedResponse;
const headers = new Headers(cachedResponse.headers)
const fetch = freshCache.get(request) || {}
for (const [key, val] of Object.entries(fetch))
headers.set('x-routify-' + kebabify(key), val)
headers.set('x-routify-use-cache', "true")
return cachedResponse.arrayBuffer().then(buffer => new Response(buffer, { ...cachedResponse, headers }))
},
cacheDidUpdate: async ({ cacheName, request, oldResponse, newResponse, event }) => {
// if cached updated we update freshCache
const prefetchOptions = getPrefetchOptions(event.request)
const headerOptions = getHeaderOptions(event.request)
const options = { ...defaultOptions, ...prefetchOptions, ...headerOptions }
const date = Date.now()
freshCache.set(event.request, {
...options,
validUntil: new Date(date + (options.validFor * 1000)).toISOString(),
cachedAt: (new Date(date)).toISOString()
})
}
}
}
export function freshCacheData(event) {
cleanupFreshCache()
return freshCache.get(event.request)
}
/**
*
*/
function cleanupFreshCache() {
freshCache.map.forEach((data, key) => {
if (new Date(data.validUntil) < new Date) {
freshCache.map.delete(key)
}
})
}
/**
* Get options caching options from routify
* @param {Request} request
*/
function getPrefetchOptions({ referrer }) {
referrer = referrer.replace(/\w+:\/\/[^/]+/, '')
const [path, _options] = referrer.split('__[[routify_url_options]]__')
const options = JSON.parse(decodeURIComponent(_options || '') || '{}')
return options
}
function getHeaderOptions({ headers }) {
const routifyHeaders = [...headers.entries()].filter(([key]) => key.startsWith('x-routify-'))
const options = {}
for (const [key, val] of routifyHeaders) {
const name = camelize(key.replace('x-routify-', ''))
options[name] = parse(val)
}
return options
}
function reqToStr({ url, headers, method }) { return JSON.stringify({ url, method, headers: [...headers.entries()], }) }
function kebabify(str) { return str.replace(/[A-Z]/g, x => '-' + x.toLowerCase()) }
function camelize(str) { return str.replace(/-./g, x => x.toUpperCase()[1]) }
function parse(str) { try { return JSON.parse(str) } catch (err) { } }