Merge branch 'modularize-alt-fetch-as-an-example' into 'master'

Draft: modularize alt fetch plugin as an example

See merge request rysiekpl/libresilient!23
merge-requests/23/merge
Declan Rek 2024-02-26 10:51:59 +00:00
commit 1a4edee18b
5 zmienionych plików z 585 dodań i 145 usunięć

3
.gitignore vendored
Wyświetl plik

@ -1,2 +1,5 @@
coverage/
junit.xml
dist
node_modules

422
package-lock.json wygenerowano 100644
Wyświetl plik

@ -0,0 +1,422 @@
{
"name": "libresilient",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "libresilient",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"esbuild": "0.19.10"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz",
"integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz",
"integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz",
"integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz",
"integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz",
"integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz",
"integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz",
"integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz",
"integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz",
"integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz",
"integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz",
"integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz",
"integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz",
"integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz",
"integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz",
"integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz",
"integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz",
"integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz",
"integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz",
"integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz",
"integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz",
"integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz",
"integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz",
"integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild": {
"version": "0.19.10",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz",
"integrity": "sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.10",
"@esbuild/android-arm": "0.19.10",
"@esbuild/android-arm64": "0.19.10",
"@esbuild/android-x64": "0.19.10",
"@esbuild/darwin-arm64": "0.19.10",
"@esbuild/darwin-x64": "0.19.10",
"@esbuild/freebsd-arm64": "0.19.10",
"@esbuild/freebsd-x64": "0.19.10",
"@esbuild/linux-arm": "0.19.10",
"@esbuild/linux-arm64": "0.19.10",
"@esbuild/linux-ia32": "0.19.10",
"@esbuild/linux-loong64": "0.19.10",
"@esbuild/linux-mips64el": "0.19.10",
"@esbuild/linux-ppc64": "0.19.10",
"@esbuild/linux-riscv64": "0.19.10",
"@esbuild/linux-s390x": "0.19.10",
"@esbuild/linux-x64": "0.19.10",
"@esbuild/netbsd-x64": "0.19.10",
"@esbuild/openbsd-x64": "0.19.10",
"@esbuild/sunos-x64": "0.19.10",
"@esbuild/win32-arm64": "0.19.10",
"@esbuild/win32-ia32": "0.19.10",
"@esbuild/win32-x64": "0.19.10"
}
}
}
}

27
package.json 100644
Wyświetl plik

@ -0,0 +1,27 @@
{
"name": "libresilient",
"version": "1.0.0",
"description": "A browser-based decentralized content delivery network, implemented as a JavaScript library to be deployed easily on any website. LibResilient uses [ServiceWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) and a suite of unconventional in-browser delivery mechanisms, with a strong focus on decentralized tools like [IPFS](https://ipfs.io/).",
"main": "libresilient.js",
"directories": {
"doc": "docs",
"lib": "lib"
},
"scripts": {
"prebuild": "rm -rf dist && mkdir -p dist/plugins/alt-fetch",
"build": "cp -r plugins/alt-fetch/lib dist/plugins/alt-fetch/lib && esbuild plugins/alt-fetch/index.js --bundle --outfile=dist/plugins/alt-fetch/index.js"
},
"repository": {
"type": "git",
"url": "git+https://gitlab.com/Zamaneh-Media/libresilient.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://gitlab.com/Zamaneh-Media/libresilient/issues"
},
"homepage": "https://gitlab.com/Zamaneh-Media/libresilient#readme",
"devDependencies": {
"esbuild": "0.19.10"
}
}

Wyświetl plik

@ -1,161 +1,63 @@
import { fetchContentFromAlternativeEndpoints } from "./lib/fetchContentFromAlternativeEndpoints";
/* ========================================================================= *\
|* === HTTP(S) fetch() from alternative endpoints === *|
\* ========================================================================= */
/**
* this plugin does not implement any push method
*
*
* NOTICE: this plugin uses Promise.any()
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
* the polyfill is implemented in LibResilient's service-worker.js
*/
// no polluting of the global namespace please
(function(LRPC){
// this never changes
const pluginName = "alt-fetch"
LRPC.set(pluginName, (LR, init={})=>{
export const PLUGIN_NAME = 'alt-fetch';
/*
* plugin config settings
*/
// sane defaults
let defaultConfig = {
// endpoints to use
//
// they have to respond to requests formatted like:
// <endpoint-url>/<path>
//
// let's say the endpoint is:
// https://example.com/api/endpoint/
// ...and that we are trying to get:
// <original-domain>/some/path/img.png
//
// the endpoint is supposed to return the expected image
// when this URL is requested:
// https://example.com/api/endpoint/some/path/img.png
//
// this has to be explicitly configured by the website admin
endpoints: [],
// how many simultaneous connections to different endpoints do we want
//
// more concurrency means higher chance of a request succeeding
// but uses more bandwidth and other resources;
//
// 3 seems to be a reasonable default
concurrency: 3
}
const LRPC = self.libResilientPluginConstructors;
// merge the defaults with settings from the init var
let config = {...defaultConfig, ...init}
let config = {};
LRPC.set(PLUGIN_NAME, (LR, init={})=> {
// sane defaults
let defaultConfig = {
// endpoints to use
//
// they have to respond to requests formatted like:
// <endpoint-url>/<path>
//
// let's say the endpoint is:
// https://example.com/api/endpoint/
// ...and that we are trying to get:
// <original-domain>/some/path/img.png
//
// the endpoint is supposed to return the expected image
// when this URL is requested:
// https://example.com/api/endpoint/some/path/img.png
//
// this has to be explicitly configured by the website admin
endpoints: [],
// reality check: endpoints need to be set to an array of non-empty strings
if (typeof(config.endpoints) !== "object" || !Array.isArray(config.endpoints)) {
let err = new Error("endpoints not confgured")
console.error(err)
throw err
}
// how many simultaneous connections to different endpoints do we want
//
// more concurrency means higher chance of a request succeeding
// but uses more bandwidth and other resources;
//
// 3 seems to be a reasonable default
concurrency: 3
};
/**
* getting content using regular HTTP(S) fetch()
*/
let fetchContentFromAlternativeEndpoints = (url, init={}) => {
// remove the https://original.domain/ bit to get the relative path
// TODO: this assumes that URLs we handle are always relative to the root
// TODO: of the original domain, this needs to be documented
var path = url.replace(/https?:\/\/[^/]+\//, '')
// we really want to make fetch happen, Regina!
// TODO: this change should *probably* be handled on the Service Worker level
init.cache = 'reload'
// we don't want to modify the original endpoints array
var sourceEndpoints = [...config.endpoints]
// if we have fewer than the configured concurrency or just as many, use all of them
if (sourceEndpoints.length <= config.concurrency) {
var useEndpoints = sourceEndpoints
// otherwise get `config.concurrency` endpoints at random
} else {
var useEndpoints = new Array()
while (useEndpoints.length < config.concurrency) {
useEndpoints.push(
sourceEndpoints
.splice(Math.floor(Math.random() * sourceEndpoints.length), 1)[0]
)
}
}
// add the rest of the path to each endpoint
useEndpoints.forEach((endpoint, index) => {
useEndpoints[index] = endpoint + path;
});
// debug log
LR.log(pluginName, `fetching from alternative endpoints:\n ${useEndpoints.join('\n ')}`)
return Promise.any(
useEndpoints.map(
u=>fetch(u, init)
))
.then((response) => {
// 4xx? 5xx? that's a paddlin'
if (response.status >= 400) {
// throw an Error to fall back to other plugins:
throw new Error('HTTP Error: ' + response.status + ' ' + response.statusText);
}
// all good, it seems
LR.log(pluginName, "fetched:", response.url);
// we need to create a new Response object
// with all the headers added explicitly,
// since response.headers is immutable
var responseInit = {
status: response.status,
statusText: response.statusText,
headers: {},
url: url
};
response.headers.forEach(function(val, header){
responseInit.headers[header] = val;
});
// add the X-LibResilient-* headers to the mix
responseInit.headers['X-LibResilient-Method'] = pluginName
// we will not have it most of the time, due to CORS rules:
// https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header
responseInit.headers['X-LibResilient-ETag'] = response.headers.get('ETag')
if (responseInit.headers['X-LibResilient-ETag'] === null) {
// far from perfect, but what are we going to do, eh?
responseInit.headers['X-LibResilient-ETag'] = response.headers.get('last-modified')
}
// return the new response, using the Blob from the original one
return response
.blob()
.then((blob) => {
return new Response(
blob,
responseInit
)
})
})
}
config = { ...defaultConfig, ...init };
// reality check: endpoints need to be set to an array of non-empty strings
if (typeof (config.endpoints) !== 'object' || !Array.isArray(config.endpoints)) {
let err = new Error('endpoints not confgured');
console.error(err);
throw err;
}
// return the plugin data structure
return {
name: pluginName,
description: 'HTTP(S) fetch() using preconfigured alternative endpoints',
version: 'COMMIT_UNKNOWN',
fetch: fetchContentFromAlternativeEndpoints
}
})
// done with not polluting the global namespace
})(LibResilientPluginConstructors)
return {
name: PLUGIN_NAME,
description: 'HTTP(S) fetch() using preconfigured alternative endpoints',
version: 'COMMIT_UNKNOWN',
fetch: (url, init) => fetchContentFromAlternativeEndpoints(url, init, config)
};
});

Wyświetl plik

@ -0,0 +1,86 @@
import { PLUGIN_NAME } from "../index";
export function fetchContentFromAlternativeEndpoints (url, init = {}, config) {
// remove the https://original.domain/ bit to get the relative path
// TODO: this assumes that URLs we handle are always relative to the root
// TODO: of the original domain, this needs to be documented
var path = url.replace(/https?:\/\/[^/]+\//, '');
// we really want to make fetch happen, Regina!
// TODO: this change should *probably* be handled on the Service Worker level
// init.cache = 'reload';
// we don't want to modify the original endpoints array
var sourceEndpoints = [...config.endpoints];
let useEndpoints = [];
// if we have fewer than the configured concurrency or just as many, use all of them
if (sourceEndpoints.length <= config.concurrency) {
useEndpoints = sourceEndpoints;
// otherwise get `config.concurrency` endpoints at random
} else {
while (useEndpoints.length < config.concurrency) {
useEndpoints.push(
sourceEndpoints
.splice(Math.floor(Math.random() * sourceEndpoints.length), 1)[0]
);
}
}
// add the rest of the path to each endpoint
useEndpoints.forEach((endpoint, index) => {
useEndpoints[index] = endpoint + path;
});
// debug log
console.log(PLUGIN_NAME, `fetching from alternative endpoints:\n ${useEndpoints.join('\n ')}`);
return Promise.any(
useEndpoints.map(
u=>fetch(u, init)
))
.then((response) => {
// 4xx? 5xx? that's a paddlin'
if (response.status >= 400) {
// throw an Error to fall back to other plugins:
throw new Error('HTTP Error: ' + response.status + ' ' + response.statusText);
}
// all good, it seems
console.log(PLUGIN_NAME, 'fetched:', response.url);
// we need to create a new Response object
// with all the headers added explicitly,
// since response.headers is immutable
var responseInit = {
status: response.status,
statusText: response.statusText,
headers: {},
url: url
};
response.headers.forEach(function (val, header){
responseInit.headers[header] = val;
});
// add the X-LibResilient-* headers to the mix
responseInit.headers['X-LibResilient-Method'] = PLUGIN_NAME;
// we will not have it most of the time, due to CORS rules:
// https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header
responseInit.headers['X-LibResilient-ETag'] = response.headers.get('ETag');
if (responseInit.headers['X-LibResilient-ETag'] === null) {
// far from perfect, but what are we going to do, eh?
responseInit.headers['X-LibResilient-ETag'] = response.headers.get('last-modified');
}
// return the new response, using the Blob from the original one
return response
.blob()
.then((blob) => {
return new Response(
blob,
responseInit
);
});
});
}