UNPKG

hastily

Version:

express middleware to simulate fastly cdn

211 lines 16.4 kB
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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