add presets

This commit is contained in:
cupcakearmy 2022-05-29 01:19:18 +02:00
parent 08470ba820
commit 38d35f40aa
No known key found for this signature in database
GPG Key ID: 3235314B4D31232F
4 changed files with 67 additions and 11 deletions

View File

@ -17,6 +17,8 @@ RUN ls -hal
# RUNNER # RUNNER
FROM base FROM base
ENV NODE_ENV=production
COPY package.json pnpm-lock.yaml ./ COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod RUN pnpm install --frozen-lockfile --prod

View File

@ -1,6 +1,6 @@
{ {
"name": "morphus", "name": "morphus",
"version": "0.1.0", "version": "1.0.0-rc.2",
"description": "", "description": "",
"author": "Niccolo Borgioli", "author": "Niccolo Borgioli",
"license": "MIT", "license": "MIT",

View File

@ -30,6 +30,7 @@ const Schema = yaml.DEFAULT_SCHEMA.extend([RegExpTag])
export type NullableStringOrRegexpArray = (string | RegExp)[] | null export type NullableStringOrRegexpArray = (string | RegExp)[] | null
function formatNullableStringOrRegexpArray(values: any) { function formatNullableStringOrRegexpArray(values: any) {
if (values === null) return
if (!Array.isArray(values)) throw new Error('must be an array') if (!Array.isArray(values)) throw new Error('must be an array')
if (values.length === 0) throw new Error('must be an array with at least one element') if (values.length === 0) throw new Error('must be an array with at least one element')
for (const value of values) { for (const value of values) {
@ -39,6 +40,18 @@ function formatNullableStringOrRegexpArray(values: any) {
} }
} }
type PresetsConfig = Record<string, string> | null
function formatPresets(values: any) {
if (values === null) return
if (typeof values === 'object') {
for (const key in values) {
if (typeof values[key] !== 'string') throw new Error('entries for presets must be strings')
}
} else {
throw new Error('presets must be an object or null')
}
}
convict.addParser({ extension: ['yml', 'yaml'], parse: (s) => yaml.load(s, { schema: Schema }) }) convict.addParser({ extension: ['yml', 'yaml'], parse: (s) => yaml.load(s, { schema: Schema }) })
export const config = convict({ export const config = convict({
@ -101,6 +114,19 @@ export const config = convict({
env: 'STORAGE', env: 'STORAGE',
}, },
// Presets
presets: {
doc: 'The presets to use',
format: formatPresets,
nullable: true,
default: null as PresetsConfig,
},
onlyAllowPresets: {
doc: 'Whether to allow only presets',
format: Boolean,
default: false,
},
// Local storage // Local storage
local: { local: {
assets: { assets: {

View File

@ -61,6 +61,11 @@ export class ComplexParameter<N = string, T extends object = {}> {
@IsObject() @IsObject()
options: T options: T
/**
* parses a parameter value from a string
*
* @param parameter parameter to parse
*/
constructor(parameter: string) { constructor(parameter: string) {
const [name, optionsRaw] = parameter.split('|') const [name, optionsRaw] = parameter.split('|')
if (!name) throw new Error('Invalid parameter') if (!name) throw new Error('Invalid parameter')
@ -115,8 +120,33 @@ export class TransformQueryBase {
@ValidateNested() @ValidateNested()
op: ComplexParameter[] = [] op: ComplexParameter[] = []
@IsOptional()
@IsString()
preset?: string
constructor(data: any, options: { headers: IncomingHttpHeaders }) { constructor(data: any, options: { headers: IncomingHttpHeaders }) {
Object.assign(this, data) if (Config.onlyAllowPresets) {
const { url, preset, ...rest } = data
if (!preset) {
throw new Error('Preset is required')
}
if (Object.keys(rest).length > 0) {
throw new Error('only preset parameter is allowed')
}
this.url = url
this.preset = data.preset
} else {
Object.assign(this, data)
}
if (this.preset) {
const preset = Config.presets[this.preset]
if (!preset) {
throw new Error('preset not found')
}
const params = Object.fromEntries(new URLSearchParams(preset).entries())
Object.assign(this, params)
}
if (this.width) this.width = parseInt(this.width as any) if (this.width) this.width = parseInt(this.width as any)
if (this.height) this.height = parseInt(this.height as any) if (this.height) this.height = parseInt(this.height as any)
@ -127,8 +157,7 @@ export class TransformQueryBase {
// @ts-ignore // @ts-ignore
this.format = new ComplexParameter((this.format as any) || 'auto') this.format = new ComplexParameter((this.format as any) || 'auto')
if ((this.format.name as string) === 'auto') { if ((this.format.name as string) === 'auto') {
if (!options.headers) throw new Error('cannot use auto format without user agent') if (!options.headers) throw new Error('cannot use auto format without headers')
this.autoFormat(options.headers) this.autoFormat(options.headers)
} }
@ -152,13 +181,7 @@ export class TransformQueryBase {
} }
} }
toString(): string { private autoFormat(headers: IncomingHttpHeaders) {
const data = flatten(this) as Record<string, any>
return new URLSearchParams(sortObjectByKeys(data)).toString()
}
autoFormat(headers: IncomingHttpHeaders) {
const ua = headers['user-agent']
const accept = headers['accept'] // Accept: image/avif,image/webp,*/* const accept = headers['accept'] // Accept: image/avif,image/webp,*/*
if (accept) { if (accept) {
const acceptTypes = accept.split(',') const acceptTypes = accept.split(',')
@ -173,6 +196,11 @@ export class TransformQueryBase {
this.format!.name = 'jpeg' this.format!.name = 'jpeg'
} }
toString(): string {
const data = flatten(this) as Record<string, any>
return new URLSearchParams(sortObjectByKeys(data)).toString()
}
get hash(): string { get hash(): string {
return sha3(this.toString()) return sha3(this.toString())
} }