@fly/cdn
Version:
Fly's TypeScript CDN
97 lines • 12.9 kB
JavaScript
/** @module Config */
import { validateBackend, buildBackend } from "./backends";
import { isObject } from "../util";
import { validateRule, buildRules } from "./rules";
import { buildMiddleware, validateMiddleware } from "./middleware";
export const CDNConfigKey = "flyCDN";
export function isItemConfig(input) {
if (!isObject(input)) {
throw new Error("must be an object");
}
if (typeof input.type !== "string" || input.type.length == 0) {
throw new Error("must have a type property specifying a backend");
}
return true;
}
export function isCdnConfig(input) {
if (!isObject(input)) {
throw new Error("config must be an object");
}
const { backendConfigs = {}, ruleConfigs = [], middlewareConfigs = [] } = input;
if (!isObject(backendConfigs)) {
throw new Error("backends property must be a map of keys -> Backend definition");
}
for (const [key, cfg] of Object.entries(backendConfigs)) {
try {
if (isItemConfig(cfg)) {
validateBackend(cfg);
}
}
catch (error) {
throw new Error(`backend config for ${key} is invalid: ${error.message || error}`);
}
}
if (!(ruleConfigs instanceof Array)) {
throw new Error("rules property must be an array of Rule definitions");
}
for (const [idx, cfg] of ruleConfigs.entries()) {
try {
validateRule(cfg);
}
catch (error) {
throw new Error(`rule at index ${idx} is invalid: ${error.message || error}`);
}
}
if (!(middlewareConfigs instanceof Array)) {
throw new Error("middleware property must be an array of Middleware definitions");
}
for (const [idx, cfg] of middlewareConfigs.entries()) {
try {
if (isItemConfig) {
validateMiddleware(cfg);
}
}
catch (error) {
throw new Error(`middleware at index ${idx} is invalid: ${error.message || error}`);
}
}
return true;
}
export function buildCdn(config) {
const backends = new Map();
for (const [key, cfg] of Object.entries(config.backends)) {
const b = buildBackend(cfg);
backends.set(key, b);
}
console.log("Built backends:", Object.getOwnPropertyNames(config.backends));
let fn = buildRules(backends, config.rules);
const middleware = config.middleware;
if (middleware && middleware.length > 0) {
for (let i = middleware.length - 1; i >= 0; i--) {
fn = buildMiddleware(fn, middleware[i]);
}
}
return Object.assign(fn, {
backends: backends
});
}
export function buildCdnFromAppConfig(c) {
try {
const config = c || app.config[CDNConfigKey];
if (!config) {
throw new Error("flyCDN config property not found");
}
if (!isCdnConfig(config)) {
// This is unreachable because isCdnConfig throws but typescript can't infer that so we throw too
throw new Error("App config not supported");
}
return buildCdn(config);
}
catch (error) {
const fn = (...args) => {
return Promise.resolve(new Response(`Invalid CDN Config: ${error.message || error}`));
};
return Object.assign(fn, { backends: new Map() });
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHFCQUFxQjtBQUNyQixPQUFPLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxNQUFNLFlBQVksQ0FBQztBQUMzRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBR25DLE9BQU8sRUFBWSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQzdELE9BQU8sRUFBRSxlQUFlLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFHbkUsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQztBQWVyQyxNQUFNLFVBQVUsWUFBWSxDQUFDLEtBQWM7SUFDekMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNwQixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7S0FDdEM7SUFFRCxJQUFJLE9BQU8sS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFO1FBQzVELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztLQUNuRTtJQUVELE9BQU8sSUFBSSxDQUFBO0FBQ2IsQ0FBQztBQUVELE1BQU0sVUFBVSxXQUFXLENBQUMsS0FBYztJQUN4QyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFO1FBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQTtLQUM1QztJQUVELE1BQU0sRUFBRSxjQUFjLEdBQUcsRUFBRyxFQUFFLFdBQVcsR0FBRyxFQUFFLEVBQUUsaUJBQWlCLEdBQUcsRUFBRSxFQUFFLEdBQUcsS0FBSyxDQUFDO0lBRWpGLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLEVBQUU7UUFD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QUFBO0FBQ0osQ0FBQztBQUVELE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxDQUFPO0lBQzNDLElBQUk7UUFDRixNQUFNLE1BQU0sR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1NBQ3JEO1FBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUN4QixpR0FBaUc7WUFDakcsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1NBQzdDO1FBQ0QsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7S0FDeEI7SUFBQyxPQUFPLEtBQUssRUFBRTtRQUNkLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFXLEVBQUUsRUFBRTtZQUM1QixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxRQUFRLENBQUMsdUJBQXVCLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3hGLENBQUMsQ0FBQTtRQUNELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxHQUFHLEVBQXlCLEVBQUMsQ0FBQyxDQUFBO0tBQ3hFO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBAbW9kdWxlIENvbmZpZyAqL1xuaW1wb3J0IHsgdmFsaWRhdGVCYWNrZW5kLCBidWlsZEJhY2tlbmQgfSBmcm9tIFwiLi9iYWNrZW5kc1wiO1xuaW1wb3J0IHsgaXNPYmplY3QgfSBmcm9tIFwiLi4vdXRpbFwiO1xuaW1wb3J0IHsgRmV0Y2hGdW5jdGlvbiB9IGZyb20gXCIuLi9mZXRjaFwiO1xuaW1wb3J0IHsgUHJveHlGdW5jdGlvbiB9IGZyb20gXCIuLi9wcm94eVwiO1xuaW1wb3J0IHsgUnVsZUluZm8sIHZhbGlkYXRlUnVsZSwgYnVpbGRSdWxlcyB9IGZyb20gXCIuL3J1bGVzXCI7XG5pbXBvcnQgeyBidWlsZE1pZGRsZXdhcmUsIHZhbGlkYXRlTWlkZGxld2FyZSB9IGZyb20gXCIuL21pZGRsZXdhcmVcIjtcbmltcG9ydCB7IHN0cmluZ2lmeSB9IGZyb20gXCJxdWVyeXN0cmluZ1wiO1xuXG5leHBvcnQgY29uc3QgQ0ROQ29uZmlnS2V5ID0gXCJmbHlDRE5cIjtcblxuZXhwb3J0IGludGVyZmFjZSBDZG5Db25maWcge1xuICBiYWNrZW5kczogeyBba2V5OiBzdHJpbmddOiBJdGVtQ29uZmlnIH0sXG4gIG1pZGRsZXdhcmU6IEl0ZW1Db25maWdbXSxcbiAgcnVsZXM6IFJ1bGVJbmZvW11cbn1cblxuZXhwb3J0IGludGVyZmFjZSBJdGVtQ29uZmlnIHtcbiAgdHlwZTogc3RyaW5nO1xuICBbcHJvcDogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuZXhwb3J0IHR5cGUgQmFja2VuZFByb3hpZXMgPSBNYXA8c3RyaW5nLCBQcm94eUZ1bmN0aW9uPjtcblxuZXhwb3J0IGZ1bmN0aW9uIGlzSXRlbUNvbmZpZyhpbnB1dDogdW5rbm93bik6IGlucHV0IGlzIEl0ZW1Db25maWcge1xuICBpZiAoIWlzT2JqZWN0KGlucHV0KSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIm11c3QgYmUgYW4gb2JqZWN0XCIpO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBpbnB1dC50eXBlICE9PSBcInN0cmluZ1wiIHx8IGlucHV0LnR5cGUubGVuZ3RoID09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJtdXN0IGhhdmUgYSB0eXBlIHByb3BlcnR5IHNwZWNpZnlpbmcgYSBiYWNrZW5kXCIpO1xuICB9XG5cbiAgcmV0dXJuIHRydWVcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzQ2RuQ29uZmlnKGlucHV0OiB1bmtub3duKTogaW5wdXQgaXMgQ2RuQ29uZmlnIHtcbiAgaWYgKCFpc09iamVjdChpbnB1dCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJjb25maWcgbXVzdCBiZSBhbiBvYmplY3RcIilcbiAgfVxuXG4gIGNvbnN0IHsgYmFja2VuZENvbmZpZ3MgPSB7IH0sIHJ1bGVDb25maWdzID0gW10sIG1pZGRsZXdhcmVDb25maWdzID0gW10gfSA9IGlucHV0O1xuXG4gIGlmICghaXNPYmplY3QoYmFja2VuZENvbmZpZ3MpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiYmFja2VuZHMgcHJvcGVydHkgbXVzdCBiZSBhIG1hcCBvZiBrZXlzIC0+IEJhY2tlbmQgZGVmaW5pdGlvblwiKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgW2tleSwgY2ZnXSBvZiBPYmplY3QuZW50cmllcyhiYWNrZW5kQ29uZmlncykpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKGlzSXRlbUNvbmZpZyhjZmcpKSB7XG4gICAgICAgIHZhbGlkYXRlQmFja2VuZChjZmcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGJhY2tlbmQgY29uZmlnIGZvciAke2tleX0gaXMgaW52YWxpZDogJHtlcnJvci5tZXNzYWdlIHx8IGVycm9yfWApXG4gICAgfVxuICB9XG5cbiAgaWYgKCEocnVsZUNvbmZpZ3MgaW5zdGFuY2VvZiBBcnJheSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJydWxlcyBwcm9wZXJ0eSBtdXN0IGJlIGFuIGFycmF5IG9mIFJ1bGUgZGVmaW5pdGlvbnNcIik7XG4gIH1cblxuICBmb3IgKGNvbnN0IFtpZHgsIGNmZ10gb2YgcnVsZUNvbmZpZ3MuZW50cmllcygpKSB7XG4gICAgdHJ5IHtcbiAgICAgIHZhbGlkYXRlUnVsZShjZmcpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcnVsZSBhdCBpbmRleCAke2lkeH0gaXMgaW52YWxpZDogJHtlcnJvci5tZXNzYWdlIHx8IGVycm9yfWApXG4gICAgfVxuICB9XG5cbiAgaWYgKCEobWlkZGxld2FyZUNvbmZpZ3MgaW5zdGFuY2VvZiBBcnJheSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJtaWRkbGV3YXJlIHByb3BlcnR5IG11c3QgYmUgYW4gYXJyYXkgb2YgTWlkZGxld2FyZSBkZWZpbml0aW9uc1wiKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgW2lkeCwgY2ZnXSBvZiBtaWRkbGV3YXJlQ29uZmlncy5lbnRyaWVzKCkpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKGlzSXRlbUNvbmZpZykge1xuICAgICAgICB2YWxpZGF0ZU1pZGRsZXdhcmUoY2ZnKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBtaWRkbGV3YXJlIGF0IGluZGV4ICR7aWR4fSBpcyBpbnZhbGlkOiAke2Vycm9yLm1lc3NhZ2UgfHwgZXJyb3J9YClcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkQ2RuKGNvbmZpZzogQ2RuQ29uZmlnKSB7XG4gIGNvbnN0IGJhY2tlbmRzID0gbmV3IE1hcDxzdHJpbmcsIFByb3h5RnVuY3Rpb24+KCk7XG5cbiAgZm9yIChjb25zdCBba2V5LCBjZmddIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy5iYWNrZW5kcykpIHtcbiAgICBjb25zdCBiID0gYnVpbGRCYWNrZW5kKGNmZyk7XG4gICAgYmFja2VuZHMuc2V0KGtleSwgYik7XG4gIH1cbiAgY29uc29sZS5sb2coXCJCdWlsdCBiYWNrZW5kczpcIiwgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoY29uZmlnLmJhY2tlbmRzKSk7XG5cbiAgbGV0IGZuID0gYnVpbGRSdWxlcyhiYWNrZW5kcywgY29uZmlnLnJ1bGVzKVxuICBcbiAgY29uc3QgbWlkZGxld2FyZSA9IGNvbmZpZy5taWRkbGV3YXJlO1xuICBpZiAobWlkZGxld2FyZSAmJiBtaWRkbGV3YXJlLmxlbmd0aCA+IDApIHtcbiAgICBmb3IgKGxldCBpID0gbWlkZGxld2FyZS5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgZm4gPSBidWlsZE1pZGRsZXdhcmUoZm4sIG1pZGRsZXdhcmVbaV0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBPYmplY3QuYXNzaWduKGZuLCB7XG4gICAgYmFja2VuZHM6IGJhY2tlbmRzXG4gIH0pXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBidWlsZENkbkZyb21BcHBDb25maWcoYz86IGFueSkge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IGMgfHwgYXBwLmNvbmZpZ1tDRE5Db25maWdLZXldO1xuICAgIGlmICghY29uZmlnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJmbHlDRE4gY29uZmlnIHByb3BlcnR5IG5vdCBmb3VuZFwiKTtcbiAgICB9XG4gICAgaWYgKCFpc0NkbkNvbmZpZyhjb25maWcpKSB7XG4gICAgICAvLyBUaGlzIGlzIHVucmVhY2hhYmxlIGJlY2F1c2UgaXNDZG5Db25maWcgdGhyb3dzIGJ1dCB0eXBlc2NyaXB0IGNhbid0IGluZmVyIHRoYXQgc28gd2UgdGhyb3cgdG9vXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBcHAgY29uZmlnIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgfVxuICAgIHJldHVybiBidWlsZENkbihjb25maWcpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc3QgZm4gPSAoLi4uYXJnczogYW55W10pID0+IHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobmV3IFJlc3BvbnNlKGBJbnZhbGlkIENETiBDb25maWc6ICR7ZXJyb3IubWVzc2FnZSB8fCBlcnJvcn1gKSk7XG4gICAgfVxuICAgIHJldHVybiBPYmplY3QuYXNzaWduKGZuLCB7IGJhY2tlbmRzOiBuZXcgTWFwPHN0cmluZywgUHJveHlGdW5jdGlvbj4oKX0pXG4gIH1cbn1cbiJdfQ==