-
Notifications
You must be signed in to change notification settings - Fork 12
/
swopr.js
71 lines (50 loc) · 2.8 KB
/
swopr.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
self.importScripts('./swopr-responses.js');
const handleInstall = () => {
console.log('[SWOPR] service worker installed');
self.skipWaiting();
};
const handleActivate = () => {
console.log('[SWOPR] service worker activated');
return self.clients.claim();
};
const delayResponse = (time, response) => new Promise(resolve => setTimeout(() => resolve(response), time));
const compose = (...fns) => x => fns.reduce((res, f) => res || f(x), false);
const getResponseFor = ({url: reqUrl, method: reqMethod}) => {
const exactUrlMatch = ({url, method}) => url === reqUrl && method === reqMethod;
const patternUrlMatch = ({url, method}) => {
return url.includes('*') && new RegExp(url.replace('*', '(.+)')).test(reqUrl) && method === reqMethod;
};
const paramsUrlMatch = ({url, method}) => {
return url.includes(':') && new RegExp(`${url.replaceAll(/(:[a-z-A-Z0-9]+)/g, '([0-9]+)')}$`).test(reqUrl) && method === reqMethod;
};
const exactOrPatternMatch = compose(exactUrlMatch, patternUrlMatch, paramsUrlMatch);
/* eslint-disable no-undef */
return responses.find(exactOrPatternMatch);
/* eslint-enable no-undef */
};
const getRequestParams = (matchedUrl, reqUrl) => {
const params = [...matchedUrl.matchAll(/(:[a-z-A-Z0-9]+)/g)].map(([m]) => m);
const values = [...reqUrl.matchAll(/(?<=\/)[0-9]+/g)].map(([m]) => m);
return params.reduce((acc, key, index) => ({...acc, [key.substring(1)]: values[index]}), {});
};
const getResponseBody = (response, params) => typeof response.body === 'function' ? response.body(params) : response.body;
const handleFetch = async (e) => {
const {request} = e;
const {method: reqMethod, url: reqUrl} = request;
const response = getResponseFor(request);
if(response) {
const {headers, status, statusText, delay, resMethod, url: matchedUrl} = response;
const params = matchedUrl.includes(':') ? getRequestParams(matchedUrl, reqUrl) : null;
const redirectUrl = matchedUrl.includes('*') ? reqUrl.replace(new RegExp(matchedUrl.replace('*', '(.+)')), response.redirectUrl) : response.redirectUrl;
const init = {headers, status, statusText, url: reqUrl, method: resMethod ? resMethod : reqMethod};
const proxyResponse = response.file ? fetch(`${self.origin}/${response.file}`) :
redirectUrl ? fetch(redirectUrl, init) :
Promise.resolve(new Response(JSON.stringify(getResponseBody(response, params)), init));
const msg = `[SWOPR] proxying request ${reqMethod}: ${reqUrl}`;
console.log(`${msg} ${redirectUrl ? `-> ${redirectUrl}` : ``} ${response.file ? `-> serving: ${response.file}` : ``}`);
e.waitUntil(e.respondWith(delay ? delayResponse(delay, proxyResponse) : proxyResponse));
}
};
self.addEventListener('install', handleInstall);
self.addEventListener('activate', handleActivate);
self.addEventListener('fetch', handleFetch);