hastily
Version:
express middleware to simulate fastly cdn
211 lines • 16.4 kB
JavaScript
import { createLogger } from './logging';
const paramsLogger = createLogger('params');
const QUALITY = 'quality';
const UNSET = Symbol('unset');
export default class FastlyParams {
constructor(params, req, res) {
this.warnings = [];
this.cachedQuality = UNSET;
this.rgbRE = /^(?:[0-9a-fA-F]{3}){1,2}$/;
this.raw = params;
this.req = req;
this.res = res;
this.log = paramsLogger.child({ req });
}
get quality() {
if (this.cachedQuality !== UNSET) {
return this.cachedQuality;
}
if (!this.has(QUALITY)) {
this.cachedQuality = undefined;
return this.cachedQuality;
}
this.cachedQuality = Number(this.get(QUALITY));
if (isNaN(this.cachedQuality)) {
this.cachedQuality = undefined;
}
return this.cachedQuality;
}
get(param) {
return this.raw.get(param);
}
has(param) {
return this.raw.has(param);
}
warn(type, param, msg) {
this.warnings.push({
msg: `Parameter "${param}=${this.get(param)}" is ${type}${msg ? ' -- ' + msg : ''}`,
type,
});
}
getWarnings() {
return this.warnings.slice();
}
toNumbers(names) {
const nums = [];
for (const name of names) {
if (this.has(name)) {
const param = this.get(name);
const num = Number(param);
if (isNaN(num)) {
this.warn('invalid', name, 'must be a valid number');
}
nums.push(num);
}
else {
nums.push(undefined);
}
}
return nums;
}
toCssBox(name) {
const csv = this.get(name);
const values = csv.split(',');
if (values.length > 4) {
this.warnFail('invalid', name, 'must be 1 to 4 comma-separated pixel values');
}
const nums = [];
for (const value of values) {
const num = Number(value);
if (isNaN(num)) {
this.warnFail('invalid', name, 'values must be numeric');
}
if (num > 0 && num < 1) {
this.warnFail('unsupported', name, 'percentage-based padding');
}
nums.push(num);
}
if (nums.length === 4) {
return {
bottom: nums[2],
left: nums[3],
right: nums[1],
top: nums[0],
};
}
if (nums.length === 3) {
return {
bottom: nums[2],
left: nums[1],
right: nums[1],
top: nums[0],
};
}
if (nums.length === 2) {
return {
bottom: nums[0],
left: nums[1],
right: nums[1],
top: nums[0],
};
}
return {
bottom: nums[0],
left: nums[0],
right: nums[0],
top: nums[0],
};
}
toColor(name) {
const die = () => {
return this.warnFail('invalid', name, 'must be formatted as RGB 0-255,0-255,0-255 or as RGBA 0-255,0-255,0-255,0-1.0');
};
const param = this.get(name);
if (this.rgbRE.test(param)) {
// sharp can support a plain color name, as long as it has a #
return '#' + param;
}
const values = param.split(',');
const toRgb = (nums) => {
if (nums.some((num) => num < 0 || num > 255)) {
die();
}
const [r, g, b] = nums;
return { r, g, b };
};
if (values.length === 4) {
const nums = values.map(Number);
const alpha = nums.pop();
if (alpha < 0 || alpha > 1) {
die();
}
const rgba = toRgb(nums);
rgba.alpha = alpha;
return rgba;
}
else if (values.length === 3) {
const rgba = toRgb(values.map(Number));
return rgba;
}
return die();
}
toTaggedValues(name, positional, named) {
const csv = this.get(name);
const values = csv.split(',').map((v) => v.toLowerCase().trim());
const tagged = {};
named.forEach((n) => {
const valueIndex = values.findIndex((value) => value.startsWith(n));
if (valueIndex > -1) {
tagged[n] = values[valueIndex].slice(n.length);
values.splice(valueIndex, 1);
}
});
// values should just be required positional now
if (values.length !== positional.length) {
this.warnFail('invalid', name, `got ${values.length} arguments, expected ${positional}`);
}
else {
values.forEach((value, i) => {
tagged[positional[i]] = value;
});
}
return tagged;
}
toRegion(name) {
const csv = this.get(name);
if (csv.includes(':') || csv.includes('offset')) {
this.warnFail('unsupported', name, 'ratio-based regions');
}
const values = this.toTaggedValues(name, ['width', 'height'], ['x', 'y', 'smart', 'offset-x', 'offset-y']);
if (values.hasOwnProperty('smart')) {
this.warnFail('unsupported', name, 'smart image cropping');
}
const validate = (tag, optional) => {
if (optional && !values.hasOwnProperty(tag)) {
return;
}
const value = Number(values[tag]);
if (isNaN(value)) {
if (optional) {
this.warn('invalid', name, `${tag} must be a number`);
return undefined;
}
else {
this.warnFail('invalid', name, `${tag} must be a number`);
}
}
if (value < 1 && value !== 0) {
this.warnFail('unsupported', name, `percentage ${tag} value in regions (must use absolute pixels)`);
}
return value;
};
const region = {
height: validate('height'),
width: validate('width'),
};
const left = validate('x', true);
if (left !== undefined) {
region.left = left;
}
const top = validate('y', true);
if (top !== undefined) {
region.top = top;
}
return region;
}
warnFail(type, name, msg) {
this.warn(type, name, msg);
throw new Error(`[${type} ${name}] ${msg}`);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFzdGx5LXBhcmFtcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZmFzdGx5LXBhcmFtcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFZQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRXpDLE1BQU0sWUFBWSxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUU1QyxNQUFNLE9BQU8sR0FBRyxTQUFrQixDQUFDO0FBQ25DLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUU5QixNQUFNLENBQUMsT0FBTyxPQUFPLFlBQVk7SUF3Qi9CLFlBQ0UsTUFBdUMsRUFDdkMsR0FBWSxFQUNaLEdBQXFCO1FBUmYsYUFBUSxHQUFjLEVBQUUsQ0FBQztRQUN6QixrQkFBYSxHQUFnQyxLQUFLLENBQUM7UUFFbkQsVUFBSyxHQUFHLDJCQUEyQixDQUFDO1FBTzFDLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBa0IsQ0FBQztRQUM5QixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ2YsSUFBSSxDQUFDLEdBQUcsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBaENELElBQUksT0FBTztRQUNULElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSyxLQUFLLEVBQUU7WUFDaEMsT0FBTyxJQUFJLENBQUMsYUFBbUMsQ0FBQztTQUNqRDtRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ3RCLElBQUksQ0FBQyxhQUFhLEdBQUcsU0FBUyxDQUFDO1lBQy9CLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztTQUMzQjtRQUNELElBQUksQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENB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