@fly/edge
Version:
Fly's TypeScript Edge
94 lines • 10.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.webpAllowed = exports.autoWebp = void 0;
/** @module Middleware */
const image_1 = require("@fly/v8env/lib/fly/image");
const response_1 = require("@fly/v8env/lib/fly/cache/response");
/**
* Automatically encodes images as webp for supported clients.
* This would apply to requests with 'image/webp' in the accept header
* and 'image/jpeg' or 'image/png' in the response type from origin.
*
* Example:
*
* ```typescript
* import { origin } from "./src/backends";
* import { autoWebp } from "./src/middleware/auto-webp";
*
* const backend = origin({
* origin: "https://fly.io/",
* headers: {host: "fly.io"}
* })
*
* const images = autoWebp(backend);
*
* fly.http.respondWith(images);
* ```
*/
function autoWebp(fetch) {
return async function imageConversions(req, init) {
if (typeof req === "string") {
req = new Request(req, init);
init = undefined;
}
// pass through if client doesn't support webp
if (!webpAllowed(req)) {
return fetch(req, init);
}
// generate a cache key
const key = `webp:${req.url}`;
// get response from responseCache and serve it (if available)
let resp = await response_1.default.get(key);
if (resp) {
resp.headers.set("Fly-Image-Cache", "HIT");
return resp;
}
resp = await fetch(req, init);
// check if the req is a png or jpeg image
if (!isImage(resp)) {
return resp;
}
if (req.method === "GET") {
let img = await loadImage(resp);
img = img.webp({ force: true, quality: 60 });
resp.headers.set("content-type", "image/webp");
const body = await img.toBuffer();
resp = new Response(body.data, resp);
resp.headers.set("content-length", body.data.byteLength.toString());
let etag = resp.headers.get("etag");
if (etag) {
etag = etag.replace(/^("?)([^"]+)("?)$/, "$1$2-webp$3");
resp.headers.set("etag", etag);
}
// put webp in responseCache for an hour
await response_1.default.set(key, resp, { tags: [req.url], ttl: 3600 });
resp.headers.set("Fly-Image-Cache", "MISS");
}
return resp;
};
}
exports.autoWebp = autoWebp;
async function loadImage(resp) {
if (!isImage(resp)) {
throw new Error("Response wasn't an image");
}
const raw = await resp.arrayBuffer();
const img = new image_1.Image(raw);
return img;
}
function isImage(resp) {
const contentType = resp.headers.get("Content-Type") || "";
if (contentType.includes("image/png") || contentType.includes("image/jpeg")) {
return true;
}
return false;
}
function webpAllowed(req) {
const accept = req.headers.get("accept") || "";
if (accept.includes("image/webp")) {
return true;
}
return false;
}
exports.webpAllowed = webpAllowed;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0by13ZWJwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21pZGRsZXdhcmUvYXV0by13ZWJwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlCQUF5QjtBQUN6QixvREFBaUQ7QUFDakQsZ0VBQThEO0FBRzlEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUVILFNBQWdCLFFBQVEsQ0FBQyxLQUFvQjtJQUMzQyxPQUFPLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxHQUFnQixFQUFFLElBQWtCO1FBQ3pFLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFDO1lBQzFCLEdBQUcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDN0IsSUFBSSxHQUFHLFNBQVMsQ0FBQztTQUNsQjtRQUVELDhDQUE4QztRQUM5QyxJQUFHLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxFQUFDO1lBQ25CLE9BQU8sS0FBSyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztTQUN6QjtRQUVELHVCQUF1QjtRQUN2QixNQUFNLEdBQUcsR0FBRyxRQUFRLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUU5Qiw4REFBOEQ7UUFDOUQsSUFBSSxJQUFJLEdBQWEsTUFBTSxrQkFBYSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNqRCxJQUFHLElBQUksRUFBQztZQUNOLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxDQUFBO1lBQzFDLE9BQU8sSUFBSSxDQUFBO1NBQ1o7UUFFRCxJQUFJLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBRTlCLDBDQUEwQztRQUMxQyxJQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sSUFBSSxDQUFBO1NBQ1o7UUFFRCxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssS0FBSyxFQUFDO1lBQ3ZCLElBQUksR0FBRyxHQUFHLE1BQU0sU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQy9CLEdBQUcsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFFL0MsTUFBTSxJQUFJLEdBQUcsTUFBTSxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUE7WUFDakMsSUFBSSxHQUFHLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUE7WUFDcEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtZQUNuRSxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQTtZQUNuQyxJQUFHLElBQUksRUFBQztnQkFDTixJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxhQUFhLENBQUMsQ0FBQTtnQkFDdkQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFBO2FBQy9CO1lBRUQsd0NBQXdDO1lBQ3hDLE1BQU0sa0JBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtZQUNsRSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQTtTQUM1QztRQUNELE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQyxDQUFBO0FBQ0gsQ0FBQztBQWpERCw0QkFpREM7QUFFRCxLQUFLLFVBQVUsU0FBUyxDQUFDLElBQWM7SUFDckMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUE7S0FDNUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUNwQyxNQUFNLEdBQUcsR0FBRyxJQUFJLGFBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUUxQixPQUFPLEdBQUcsQ0FBQTtBQUNaLENBQUM7QUFFRCxTQUFTLE9BQU8sQ0FBQyxJQUFjO0lBQzdCLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtJQUMxRCxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsRUFBRTtRQUMzRSxPQUFPLElBQUksQ0FBQTtLQUNaO0lBQ0QsT0FBTyxLQUFLLENBQUE7QUFDZCxDQUFDO0FBRUQsU0FBZ0IsV0FBVyxDQUFDLEdBQVk7SUFDdEMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFBO0lBQzlDLElBQ0UsTUFBTSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsRUFDOUI7UUFDQyxPQUFPLElBQUksQ0FBQTtLQUNaO0lBQ0QsT0FBTyxLQUFLLENBQUE7QUFDZCxDQUFDO0FBUkQsa0NBUUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiogQG1vZHVsZSBNaWRkbGV3YXJlICovXG5pbXBvcnQgeyBJbWFnZSB9IGZyb20gXCJAZmx5L3Y4ZW52L2xpYi9mbHkvaW1hZ2VcIjtcbmltcG9ydCByZXNwb25zZUNhY2hlIGZyb20gXCJAZmx5L3Y4ZW52L2xpYi9mbHkvY2FjaGUvcmVzcG9uc2VcIjtcbmltcG9ydCB7IEZldGNoRnVuY3Rpb24gfSBmcm9tIFwiLi4vZmV0Y2hcIjtcblxuLyoqXG4gKiBBdXRvbWF0aWNhbGx5IGVuY29kZXMgaW1hZ2VzIGFzIHdlYnAgZm9yIHN1cHBvcnRlZCBjbGllbnRzLlxuICogVGhpcyB3b3VsZCBhcHBseSB0byByZXF1ZXN0cyB3aXRoICdpbWFnZS93ZWJwJyBpbiB0aGUgYWNjZXB0IGhlYWRlciBcbiAqIGFuZCAnaW1hZ2UvanBlZycgb3IgJ2ltYWdlL3BuZycgaW4gdGhlIHJlc3BvbnNlIHR5cGUgZnJvbSBvcmlnaW4uXG4gKiBcbiAqIEV4YW1wbGU6IFxuICogXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBvcmlnaW4gfSBmcm9tIFwiLi9zcmMvYmFja2VuZHNcIjtcbiAqIGltcG9ydCB7IGF1dG9XZWJwIH0gZnJvbSBcIi4vc3JjL21pZGRsZXdhcmUvYXV0by13ZWJwXCI7XG4gKiBcbiAqIGNvbnN0IGJhY2tlbmQgPSBvcmlnaW4oe1xuICogIG9yaWdpbjogXCJodHRwczovL2ZseS5pby9cIixcbiAqICBoZWFkZXJzOiB7aG9zdDogXCJmbHkuaW9cIn1cbiAqIH0pXG4gKiBcbiAqIGNvbnN0IGltYWdlcyA9IGF1dG9XZWJwKGJhY2tlbmQpO1xuICogXG4gKiBmbHkuaHR0cC5yZXNwb25kV2l0aChpbWFnZXMpO1xuICogYGBgXG4gKi9cblxuZXhwb3J0IGZ1bmN0aW9uIGF1dG9XZWJwKGZldGNoOiBGZXRjaEZ1bmN0aW9uKTogRmV0Y2hGdW5jdGlvbiB7XG4gIHJldHVybiBhc3luYyBmdW5jdGlvbiBpbWFnZUNvbnZlcnNpb25zKHJlcTogUmVxdWVzdEluZm8sIGluaXQ/OiBSZXF1ZXN0SW5pdCkge1xuICAgIGlmICh0eXBlb2YgcmVxID09PSBcInN0cmluZ1wiKXtcbiAgICAgIHJlcSA9IG5ldyBSZXF1ZXN0KHJlcSwgaW5pdCk7XG4gICAgICBpbml0ID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8vIHBhc3MgdGhyb3VnaCBpZiBjbGllbnQgZG9lc24ndCBzdXBwb3J0IHdlYnBcbiAgICBpZighd2VicEFsbG93ZWQocmVxKSl7XG4gICAgICByZXR1cm4gZmV0Y2gocmVxLCBpbml0KTtcbiAgICB9XG5cbiAgICAvLyBnZW5lcmF0ZSBhIGNhY2hlIGtleVxuICAgIGNvbnN0IGtleSA9IGB3ZWJwOiR7cmVxLnVybH1gO1xuXG4gICAgLy8gZ2V0IHJlc3BvbnNlIGZyb20gcmVzcG9uc2VDYWNoZSBhbmQgc2VydmUgaXQgKGlmIGF2YWlsYWJsZSlcbiAgICBsZXQgcmVzcDogUmVzcG9uc2UgPSBhd2FpdCByZXNwb25zZUNhY2hlLmdldChrZXkpXG4gICAgaWYocmVzcCl7XG4gICAgICByZXNwLmhlYWRlcnMuc2V0KFwiRmx5LUltYWdlLUNhY2hlXCIsIFwiSElUXCIpXG4gICAgICByZXR1cm4gcmVzcFxuICAgIH1cblxuICAgIHJlc3AgPSBhd2FpdCBmZXRjaChyZXEsIGluaXQpO1xuXG4gICAgLy8gY2hlY2sgaWYgdGhlIHJlcSBpcyBhIHBuZyBvciBqcGVnIGltYWdlXG4gICAgaWYoIWlzSW1hZ2UocmVzcCkpIHtcbiAgICAgIHJldHVybiByZXNwXG4gICAgfVxuXG4gICAgaWYgKHJlcS5tZXRob2QgPT09IFwiR0VUXCIpe1xuICAgICAgbGV0IGltZyA9IGF3YWl0IGxvYWRJbWFnZShyZXNwKVxuICAgICAgaW1nID0gaW1nLndlYnAoeyBmb3JjZTogdHJ1ZSwgcXVhbGl0eTogNjAgfSk7XG4gICAgICByZXNwLmhlYWRlcnMuc2V0KFwiY29udGVudC10eXBlXCIsIFwiaW1hZ2Uvd2VicFwiKTtcblxuICAgICAgY29uc3QgYm9keSA9IGF3YWl0IGltZy50b0J1ZmZlcigpXG4gICAgICByZXNwID0gbmV3IFJlc3BvbnNlKGJvZHkuZGF0YSwgcmVzcClcbiAgICAgIHJlc3AuaGVhZGVycy5zZXQoXCJjb250ZW50LWxlbmd0aFwiLCBib2R5LmRhdGEuYnl0ZUxlbmd0aC50b1N0cmluZygpKVxuICAgICAgbGV0IGV0YWcgPSByZXNwLmhlYWRlcnMuZ2V0KFwiZXRhZ1wiKVxuICAgICAgaWYoZXRhZyl7XG4gICAgICAgIGV0YWcgPSBldGFnLnJlcGxhY2UoL14oXCI/KShbXlwiXSspKFwiPykkLywgXCIkMSQyLXdlYnAkM1wiKVxuICAgICAgICByZXNwLmhlYWRlcnMuc2V0KFwiZXRhZ1wiLCBldGFnKVxuICAgICAgfVxuXG4gICAgICAvLyBwdXQgd2VicCBpbiByZXNwb25zZUNhY2hlIGZvciBhbiBob3VyXG4gICAgICBhd2FpdCByZXNwb25zZUNhY2hlLnNldChrZXksIHJlc3AsIHsgdGFnczogW3JlcS51cmxdLCB0dGw6IDM2MDAgfSlcbiAgICAgIHJlc3AuaGVhZGVycy5zZXQoXCJGbHktSW1hZ2UtQ2FjaGVcIiwgXCJNSVNTXCIpXG4gICAgfVxuICAgIHJldHVybiByZXNwXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbG9hZEltYWdlKHJlc3A6IFJlc3BvbnNlKTogUHJvbWlzZTxJbWFnZT4ge1xuICBpZiAoIWlzSW1hZ2UocmVzcCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZXNwb25zZSB3YXNuJ3QgYW4gaW1hZ2VcIilcbiAgfVxuICBjb25zdCByYXcgPSBhd2FpdCByZXNwLmFycmF5QnVmZmVyKClcbiAgY29uc3QgaW1nID0gbmV3IEltYWdlKHJhdylcblxuICByZXR1cm4gaW1nXG59XG5cbmZ1bmN0aW9uIGlzSW1hZ2UocmVzcDogUmVzcG9uc2UpOiBib29sZWFue1xuICBjb25zdCBjb250ZW50VHlwZSA9IHJlc3AuaGVhZGVycy5nZXQoXCJDb250ZW50LVR5cGVcIikgfHwgXCJcIlxuICBpZiAoY29udGVudFR5cGUuaW5jbHVkZXMoXCJpbWFnZS9wbmdcIikgfHwgY29udGVudFR5cGUuaW5jbHVkZXMoXCJpbWFnZS9qcGVnXCIpKSB7XG4gICAgcmV0dXJuIHRydWVcbiAgfVxuICByZXR1cm4gZmFsc2Vcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHdlYnBBbGxvd2VkKHJlcTogUmVxdWVzdCl7XG4gIGNvbnN0IGFjY2VwdCA9IHJlcS5oZWFkZXJzLmdldChcImFjY2VwdFwiKSB8fCBcIlwiXG4gIGlmKFxuICAgIGFjY2VwdC5pbmNsdWRlcyhcImltYWdlL3dlYnBcIilcbiAgKXtcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG4gIHJldHVybiBmYWxzZVxufSJdfQ==