@fly/cdn
Version:
Fly's TypeScript CDN
111 lines • 14.2 kB
JavaScript
/**
* @module Backends
*/
import { proxy } from "../proxy";
import { isObject, merge } from "../util";
import * as errors from "../errors";
/**
* Creates a fetch-like proxy function for making requests to GitHub pages
* hosted sites.
*
* Example:
*
* ```typescript
* import { githubPages } from "./src/backends";
* const backend = githubPages({
* owner: "superfly",
* repo: "cdn",
* hostname: "docs.fly.io"
* });
* ```
* @param config The Github repository to proxy to
* @module Backends
*/
export function githubPages(options) {
const config = _normalizeOptions(options);
let ghFetch = buildGithubPagesProxy(config);
let buildTime = 0; // first failure might need a retry
const c = config;
const fn = async function githubPagesFetch(req, init) {
const original = ghFetch;
if (typeof req === "string") {
req = new Request(req, init);
}
console.debug("ghpages starting fetch:", req.url, buildTime);
let resp = await ghFetch(req, init);
console.debug("ghpages resp status:", resp.status);
if (resp.status === 404 && ghFetch.proxyConfig.hostname) {
// hostname might've been cleared
const url = new URL(req.url);
const diff = Date.now() - buildTime;
if ((url.pathname === "/" && diff > 10000) // retry after 10s for root
|| diff > 30000) { // wait 5min for everything else
console.debug("ghpages hostname request got 404:", c.hostname);
c.hostname = undefined;
ghFetch = buildGithubPagesProxy(c);
}
}
if (resp.status === 301 && !ghFetch.proxyConfig.hostname) {
// 301s happen when you request <org>.github.io/<repo> and need a custom domain
let location = resp.headers.get("location");
if (location) {
const url = new URL(location);
c.hostname = url.hostname;
ghFetch = buildGithubPagesProxy(c);
console.debug("ghpages found hostname:", c);
}
}
if (original !== ghFetch) {
// underlying proxy function changed, store it and retry
console.debug("ghpages got a new fetch fn");
self.proxyConfig = ghFetch.proxyConfig;
resp = await ghFetch(req, init);
}
return resp;
};
let self = Object.assign(fn, { proxyConfig: ghFetch.proxyConfig });
return self;
}
githubPages.normalizeOptions = _normalizeOptions;
function _normalizeOptions(input) {
const options = { owner: "", repository: "" };
if (typeof input === "string" && input.includes("/")) {
[options.owner, options.repository] = input.split("/");
}
else if (isObject(input)) {
merge(options, input, ["owner", "repository", "hostname"]);
}
else {
throw errors.invalidInput("options must be a GitHubPagesOptions object or `owner/repo` string");
}
if (!options.owner) {
throw errors.invalidProperty("owner", "is required");
}
if (!options.repository) {
throw errors.invalidProperty("repository", "is required");
}
return options;
}
function buildGithubPagesProxy(options) {
const { owner, repository, hostname } = options;
const ghHost = `${owner}.github.io`;
const headers = {
host: ghHost,
"x-forwarded-host": false
};
let path = `/${repository}/`;
if (hostname) {
path = '/'; // no repo path when hostname exists
headers.host = hostname;
}
console.debug("ghpages creating proxy:", `https://${ghHost}${path}`, {
headers: headers,
stripPath: path
});
const fn = proxy(`https://${ghHost}${path}`, {
headers: headers,
stripPath: path
});
return Object.assign(fn, { proxyConfig: options });
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0aHViX3BhZ2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2JhY2tlbmRzL2dpdGh1Yl9wYWdlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE9BQU8sRUFBRSxLQUFLLEVBQWlCLE1BQU0sVUFBVSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQzFDLE9BQU8sS0FBSyxNQUFNLE1BQU0sV0FBVyxDQUFDO0FBa0JwQzs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsT0FBb0M7SUFDOUQsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFMUMsSUFBSSxPQUFPLEdBQUcscUJBQXFCLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDM0MsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFBLENBQUMsbUNBQW1DO0lBRXJELE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQTtJQUVoQixNQUFNLEVBQUUsR0FBRyxLQUFLLFVBQVUsZ0JBQWdCLENBQUMsR0FBZ0IsRUFBRSxJQUFrQjtRQUM3RSxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUE7UUFDeEIsSUFBRyxPQUFPLEdBQUcsS0FBSyxRQUFRLEVBQUM7WUFDekIsR0FBRyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQTtTQUM3QjtRQUNELE9BQU8sQ0FBQyxLQUFLLENBQUMseUJBQXlCLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQTtRQUM1RCxJQUFJLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDbkMsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDbEQsSUFBRyxJQUFJLENBQUMs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QUFVLEVBQUU7UUFDdkIsTUFBTSxNQUFNLENBQUMsZUFBZSxDQUFDLFlBQVksRUFBRSxhQUFhLENBQUMsQ0FBQztLQUMzRDtJQUVELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxTQUFTLHFCQUFxQixDQUFDLE9BQTJCO0lBQ3hELE1BQU0sRUFBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBQyxHQUFHLE9BQU8sQ0FBQTtJQUM3QyxNQUFNLE1BQU0sR0FBRyxHQUFHLEtBQUssWUFBWSxDQUFBO0lBQ25DLE1BQU0sT0FBTyxHQUFHO1FBQ2QsSUFBSSxFQUFFLE1BQU07UUFDWixrQkFBa0IsRUFBRSxLQUFLO0tBQzFCLENBQUE7SUFDRCxJQUFJLElBQUksR0FBSSxJQUFJLFVBQVUsR0FBRyxDQUFBO0lBRTdCLElBQUcsUUFBUSxFQUFDO1FBQ1YsSUFBSSxHQUFHLEdBQUcsQ0FBQSxDQUFDLG9DQUFvQztRQUMvQyxPQUFPLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQTtLQUN4QjtJQUVELE9BQU8sQ0FBQyxLQUFLLENBQUMseUJBQXlCLEVBQUUsV0FBVyxNQUFNLEdBQUcsSUFBSSxFQUFFLEVBQUU7UUFDbkUsT0FBTyxFQUFFLE9BQU87UUFDaEIsU0FBUyxFQUFFLElBQUk7S0FDaEIsQ0FBQyxDQUFBO0lBQ0YsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsTUFBTSxHQUFHLElBQUksRUFBRSxFQUFFO1FBQzNDLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLFNBQVMsRUFBRSxJQUFJO0tBQ2hCLENBQUMsQ0FBQTtJQUVGLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLENBQUUsQ0FBQTtBQUNyRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbW9kdWxlIEJhY2tlbmRzXG4gKi9cbmltcG9ydCB7IHByb3h5LCBQcm94eUZ1bmN0aW9uIH0gZnJvbSBcIi4uL3Byb3h5XCI7XG5pbXBvcnQgeyBpc09iamVjdCwgbWVyZ2UgfSBmcm9tIFwiLi4vdXRpbFwiO1xuaW1wb3J0ICogYXMgZXJyb3JzIGZyb20gXCIuLi9lcnJvcnNcIjtcblxuXG4vKipcbiAqIEdpdEh1YiBSZXBvc2l0b3J5IGluZm9ybWF0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdpdEh1YlBhZ2VzT3B0aW9ucyB7XG5cbiAgLyoqIFJlcG9zaXRvcnkgb3duZXIgKi9cbiAgb3duZXI6IHN0cmluZyxcblxuICAvKiogUmVwb3NpdG9yeSBuYW1lIDxyZXBvc2l0b3J5PiBmb3JtYXQgKi9cbiAgcmVwb3NpdG9yeTogc3RyaW5nLFxuXG4gIC8qKiBUaGUgY3VzdG9tIGhvc3RuYW1lIG9uIHJlcG9zaXRvcnkgKi9cbiAgaG9zdG5hbWU/OiBzdHJpbmdcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZmV0Y2gtbGlrZSBwcm94eSBmdW5jdGlvbiBmb3IgbWFraW5nIHJlcXVlc3RzIHRvIEdpdEh1YiBwYWdlc1xuICogaG9zdGVkIHNpdGVzLlxuICogXG4gKiBFeGFtcGxlOlxuICogXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBnaXRodWJQYWdlcyB9IGZyb20gXCIuL3NyYy9iYWNrZW5kc1wiO1xuICogY29uc3QgYmFja2VuZCA9IGdpdGh1YlBhZ2VzKHtcbiAqICBvd25lcjogXCJzdXBlcmZseVwiLFxuICogIHJlcG86IFwiY2RuXCIsXG4gKiAgaG9zdG5hbWU6IFwiZG9jcy5mbHkuaW9cIlxuICogfSk7XG4gKiBgYGBcbiAqIEBwYXJhbSBjb25maWcgVGhlIEdpdGh1YiByZXBvc2l0b3J5IHRvIHByb3h5IHRvXG4gKiBAbW9kdWxlIEJhY2tlbmRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnaXRodWJQYWdlcyhvcHRpb25zOiBHaXRIdWJQYWdlc09wdGlvbnMgfCBzdHJpbmcpOiBQcm94eUZ1bmN0aW9uPEdpdEh1YlBhZ2VzT3B0aW9ucz4ge1xuICBjb25zdCBjb25maWcgPSBfbm9ybWFsaXplT3B0aW9ucyhvcHRpb25zKTtcblxuICBsZXQgZ2hGZXRjaCA9IGJ1aWxkR2l0aHViUGFnZXNQcm94eShjb25maWcpXG4gIGxldCBidWlsZFRpbWUgPSAwIC8vIGZpcnN0IGZhaWx1cmUgbWlnaHQgbmVlZCBhIHJldHJ5XG5cbiAgY29uc3QgYyA9IGNvbmZpZ1xuXG4gIGNvbnN0IGZuID0gYXN5bmMgZnVuY3Rpb24gZ2l0aHViUGFnZXNGZXRjaChyZXE6IFJlcXVlc3RJbmZvLCBpbml0PzogUmVxdWVzdEluaXQpIHtcbiAgICBjb25zdCBvcmlnaW5hbCA9IGdoRmV0Y2hcbiAgICBpZih0eXBlb2YgcmVxID09PSBcInN0cmluZ1wiKXtcbiAgICAgIHJlcSA9IG5ldyBSZXF1ZXN0KHJlcSwgaW5pdClcbiAgICB9XG4gICAgY29uc29sZS5kZWJ1ZyhcImdocGFnZXMgc3RhcnRpbmcgZmV0Y2g6XCIsIHJlcS51cmwsIGJ1aWxkVGltZSlcbiAgICBsZXQgcmVzcCA9IGF3YWl0IGdoRmV0Y2gocmVxLCBpbml0KVxuICAgIGNvbnNvbGUuZGVidWcoXCJnaHBhZ2VzIHJlc3Agc3RhdHVzOlwiLCByZXNwLnN0YXR1cylcbiAgICBpZihyZXNwLnN0YXR1cyA9PT0gNDA0ICYmIGdoRmV0Y2gucHJveHlDb25maWcuaG9zdG5hbWUpe1xuICAgICAgLy8gaG9zdG5hbWUgbWlnaHQndmUgYmVlbiBjbGVhcmVkXG4gICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHJlcS51cmwpXG4gICAgICBjb25zdCBkaWZmID0gRGF0ZS5ub3coKSAtIGJ1aWxkVGltZVxuICAgICAgaWYoXG4gICAgICAgICh1cmwucGF0aG5hbWUgPT09IFwiL1wiICYmIGRpZmYgPiAxMDAwMCkgLy8gcmV0cnkgYWZ0ZXIgMTBzIGZvciByb290XG4gICAgICAgfHwgZGlmZiA+IDMwMDAwKXsgLy8gd2FpdCA1bWluIGZvciBldmVyeXRoaW5nIGVsc2VcblxuXG4gICAgICAgIGNvbnNvbGUuZGVidWcoXCJnaHBhZ2VzIGhvc3RuYW1lIHJlcXVlc3QgZ290IDQwNDpcIiwgYy5ob3N0bmFtZSlcbiAgICAgICAgYy5ob3N0bmFtZSA9IHVuZGVmaW5lZFxuICAgICAgICBnaEZldGNoID0gYnVpbGRHaXRodWJQYWdlc1Byb3h5KGMpXG4gICAgICB9XG4gICAgfVxuICAgIGlmKHJlc3Auc3RhdHVzID09PSAzMDEgJiYgIWdoRmV0Y2gucHJveHlDb25maWcuaG9zdG5hbWUpe1xuICAgICAgLy8gMzAxcyBoYXBwZW4gd2hlbiB5b3UgcmVxdWVzdCA8b3JnPi5naXRodWIuaW8vPHJlcG8+IGFuZCBuZWVkIGEgY3VzdG9tIGRvbWFpblxuICAgICAgbGV0IGxvY2F0aW9uID0gcmVzcC5oZWFkZXJzLmdldChcImxvY2F0aW9uXCIpXG4gICAgICBpZihsb2NhdGlvbil7XG4gICAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwobG9jYXRpb24pXG4gICAgICAgIGMuaG9zdG5hbWUgPSB1cmwuaG9zdG5hbWVcbiAgICAgICAgZ2hGZXRjaCA9IGJ1aWxkR2l0aHViUGFnZXNQcm94eShjKVxuICAgICAgICBjb25zb2xlLmRlYnVnKFwiZ2hwYWdlcyBmb3VuZCBob3N0bmFtZTpcIiwgYylcbiAgICAgIH1cbiAgICB9XG4gICAgaWYob3JpZ2luYWwgIT09IGdoRmV0Y2gpe1xuICAgICAgLy8gdW5kZXJseWluZyBwcm94eSBmdW5jdGlvbiBjaGFuZ2VkLCBzdG9yZSBpdCBhbmQgcmV0cnlcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJnaHBhZ2VzIGdvdCBhIG5ldyBmZXRjaCBmblwiKVxuICAgICAgc2VsZi5wcm94eUNvbmZpZyA9IGdoRmV0Y2gucHJveHlDb25maWdcbiAgICAgIHJlc3AgPSBhd2FpdCBnaEZldGNoKHJlcSwgaW5pdClcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BcbiAgfVxuXG4gIGxldCBzZWxmID0gT2JqZWN0LmFzc2lnbihmbiwgeyBwcm94eUNvbmZpZzogZ2hGZXRjaC5wcm94eUNvbmZpZ30pXG4gIHJldHVybiBzZWxmXG59XG5cbmdpdGh1YlBhZ2VzLm5vcm1hbGl6ZU9wdGlvbnMgPSBfbm9ybWFsaXplT3B0aW9ucztcblxuZnVuY3Rpb24gX25vcm1hbGl6ZU9wdGlvbnMoaW5wdXQ6IHVua25vd24pOiBHaXRIdWJQYWdlc09wdGlvbnMge1xuICBjb25zdCBvcHRpb25zOiBHaXRIdWJQYWdlc09wdGlvbnMgPSB7IG93bmVyOiBcIlwiLCByZXBvc2l0b3J5OiBcIlwiIH07XG5cbiAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gXCJzdHJpbmdcIiAmJiBpbnB1dC5pbmNsdWRlcyhcIi9cIikpIHtcbiAgICBbb3B0aW9ucy5vd25lciwgb3B0aW9ucy5yZXBvc2l0b3J5XSA9IGlucHV0LnNwbGl0KFwiL1wiKTtcbiAgfSBlbHNlIGlmIChpc09iamVjdChpbnB1dCkpIHtcbiAgICBtZXJnZShvcHRpb25zLCBpbnB1dCwgW1wib3duZXJcIiwgXCJyZXBvc2l0b3J5XCIsIFwiaG9zdG5hbWVcIl0pO1xuICB9IGVsc2Uge1xuICAgIHRocm93IGVycm9ycy5pbnZhbGlkSW5wdXQoXCJvcHRpb25zIG11c3QgYmUgYSBHaXRIdWJQYWdlc09wdGlvbnMgb2JqZWN0IG9yIGBvd25lci9yZXBvYCBzdHJpbmdcIik7XG4gIH1cblxuICBpZiAoIW9wdGlvbnMub3duZXIpIHtcbiAgICB0aHJvdyBlcnJvcnMuaW52YWxpZFByb3BlcnR5KFwib3duZXJcIiwgXCJpcyByZXF1aXJlZFwiKTtcbiAgfVxuICBpZiAoIW9wdGlvbnMucmVwb3NpdG9yeSkge1xuICAgIHRocm93IGVycm9ycy5pbnZhbGlkUHJvcGVydHkoXCJyZXBvc2l0b3J5XCIsIFwiaXMgcmVxdWlyZWRcIik7XG4gIH1cblxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuZnVuY3Rpb24gYnVpbGRHaXRodWJQYWdlc1Byb3h5KG9wdGlvbnM6IEdpdEh1YlBhZ2VzT3B0aW9ucyk6IFByb3h5RnVuY3Rpb248R2l0SHViUGFnZXNPcHRpb25zPiB7XG4gIGNvbnN0IHtvd25lciwgcmVwb3NpdG9yeSwgaG9zdG5hbWV9ID0gb3B0aW9uc1xuICBjb25zdCBnaEhvc3QgPSBgJHtvd25lcn0uZ2l0aHViLmlvYFxuICBjb25zdCBoZWFkZXJzID0ge1xuICAgIGhvc3Q6IGdoSG9zdCxcbiAgICBcIngtZm9yd2FyZGVkLWhvc3RcIjogZmFsc2VcbiAgfVxuICBsZXQgcGF0aCAgPSBgLyR7cmVwb3NpdG9yeX0vYFxuICBcbiAgaWYoaG9zdG5hbWUpe1xuICAgIHBhdGggPSAnLycgLy8gbm8gcmVwbyBwYXRoIHdoZW4gaG9zdG5hbWUgZXhpc3RzXG4gICAgaGVhZGVycy5ob3N0ID0gaG9zdG5hbWVcbiAgfVxuXG4gIGNvbnNvbGUuZGVidWcoXCJnaHBhZ2VzIGNyZWF0aW5nIHByb3h5OlwiLCBgaHR0cHM6Ly8ke2doSG9zdH0ke3BhdGh9YCwge1xuICAgIGhlYWRlcnM6IGhlYWRlcnMsXG4gICAgc3RyaXBQYXRoOiBwYXRoXG4gIH0pXG4gIGNvbnN0IGZuID0gcHJveHkoYGh0dHBzOi8vJHtnaEhvc3R9JHtwYXRofWAsIHtcbiAgICBoZWFkZXJzOiBoZWFkZXJzLFxuICAgIHN0cmlwUGF0aDogcGF0aFxuICB9KVxuXG4gIHJldHVybiBPYmplY3QuYXNzaWduKGZuLCB7IHByb3h5Q29uZmlnOiBvcHRpb25zIH0gKVxufSJdfQ==