microsite
Version:
<br /> <br />
125 lines (124 loc) • 4.97 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import fetch, { Request } from "node-fetch";
import CachePolicy from "http-cache-semantics";
import { promises as fsp } from "fs";
import { join } from "path";
import { createHash } from "crypto";
export function createPrefetch(previousKey) {
return async function prefetch(info, init = {}) {
// file mode
if (typeof info === "string" && !info.startsWith("http")) {
const key = await createFileKey(info);
return Buffer.from(JSON.stringify({ type: "fs", key })).toString("base64");
}
// fetch mode
let req = new Request(info, Object.assign(Object.assign({}, init), { method: "HEAD" }));
let previousPolicy = null;
let previousRes = null;
if (previousKey) {
const { policy, response } = JSON.parse(Buffer.from(previousKey, "base64").toString("utf8"));
previousPolicy = CachePolicy.fromObject(policy);
previousRes = response;
}
if (previousPolicy && previousPolicy.satisfiesWithoutRevalidation(req)) {
previousRes.headers = previousPolicy.responseHeaders();
const response = !previousPolicy.storable()
? null
: serializeRes(previousRes);
return Buffer.from(JSON.stringify({
type: "network",
policy: previousPolicy.toObject(),
response,
})).toString("base64");
}
if (previousPolicy) {
req = new Request(info, Object.assign(Object.assign({}, init), { method: "HEAD", headers: Object.assign(Object.assign({}, req.headers), previousPolicy.revalidationHeaders(serializeReq(req))) }));
const res = await fetch(req);
const { policy, modified } = previousPolicy.revalidatedPolicy(req, res);
const response = !policy.storable() ? null : serializeRes(res);
if (modified) {
return Buffer.from(JSON.stringify({
type: "network",
policy: policy.toObject(),
response,
})).toString("base64");
}
return Buffer.from(JSON.stringify({
type: "network",
policy: previousPolicy.toObject(),
response,
})).toString("base64");
}
const res = await fetch(req);
const policy = createPolicy(req, res);
const response = !policy.storable() ? null : serializeRes(res);
return Buffer.from(JSON.stringify({ policy: policy.toObject(), response })).toString("base64");
};
}
export const isKeyValid = (previousKey, key) => {
if (!previousKey || !key)
return false;
const { type } = JSON.parse(Buffer.from(previousKey, "base64").toString("utf8"));
if (type === "fs")
return previousKey === key;
const _a = JSON.parse(Buffer.from(key, "base64").toString("utf8")), { type: _type } = _a, current = __rest(_a, ["type"]);
return current.response.status === 200 || current.response.status === 304;
};
const serializeReq = (req) => ({
url: req.url,
method: req.method,
headers: iterableToObject(req.headers),
});
const serializeRes = (res) => ({
status: res.status,
headers: iterableToObject(res.headers),
});
const iterableToObject = (iter) => {
if (typeof iter.keys !== "function")
return iter;
let obj = {};
for (const key of iter.keys()) {
obj[key] = iter.get(key);
}
return obj;
};
const createPolicy = (req, res) => new CachePolicy(serializeReq(req), serializeRes(res), { shared: false });
async function createFileKey(p) {
const hash = createHash("sha1");
const stat = await fsp.stat(p);
if (stat.isDirectory()) {
for (const ent of await addDir(p, { mode: "dir" })) {
hash.update(ent);
}
}
else {
hash.update(await addFile(p, { mode: "file" }));
}
return hash.digest("base64");
}
const addDir = async (p, { mode }) => {
const ents = await fsp.readdir(p, { withFileTypes: true });
const results = await Promise.all(ents.map((ent) => ent.isDirectory()
? addDir(join(p, ent.name), { mode })
: addFile(join(p, ent.name), { mode })));
return [].concat(...results);
};
const addFile = async (p, { mode }) => {
if (mode === "dir") {
return p;
}
else if (mode === "file") {
const content = await fsp.readFile(p);
return content;
}
};