feat: wire ICO/HEIC/HEIF converters and iconSize validation into the API
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+39
-1
@@ -8,19 +8,29 @@ import { resolve as resolveConverter, listTargetFormats } from './converters/reg
|
||||
import { registerImageConverters } from './converters/image.js';
|
||||
import { registerImageToPdfConverter } from './converters/imageToPdf.js';
|
||||
import { registerDocumentConverters } from './converters/document.js';
|
||||
import { registerIcoConverter } from './converters/ico.js';
|
||||
import { registerHeicConverter } from './converters/heic.js';
|
||||
import { resolveInputFormat } from './mime.js';
|
||||
import { deleteIfExists } from './storage.js';
|
||||
import { createJob, getJobByUuid } from './jobs/jobRepository.js';
|
||||
import { outputPath } from './storage.js';
|
||||
|
||||
const VALID_ICON_SIZES = [16, 32, 48, 256, 512];
|
||||
|
||||
function isValidQuality(targetFormat, quality) {
|
||||
if (quality === null || quality === undefined) return true;
|
||||
if (!Number.isInteger(quality)) return false;
|
||||
if (targetFormat === 'gif') return false;
|
||||
if (targetFormat === 'gif' || targetFormat === 'ico') return false;
|
||||
if (targetFormat === 'png') return quality >= 0 && quality <= 9;
|
||||
return quality >= 1 && quality <= 100;
|
||||
}
|
||||
|
||||
function isValidIconSize(targetFormat, iconSize) {
|
||||
if (iconSize === null || iconSize === undefined) return true;
|
||||
if (targetFormat !== 'ico') return false;
|
||||
return VALID_ICON_SIZES.includes(iconSize);
|
||||
}
|
||||
|
||||
let convertersRegistered = false;
|
||||
|
||||
function registerAllConverters() {
|
||||
@@ -28,6 +38,8 @@ function registerAllConverters() {
|
||||
registerImageConverters();
|
||||
registerImageToPdfConverter();
|
||||
registerDocumentConverters();
|
||||
registerIcoConverter();
|
||||
registerHeicConverter();
|
||||
convertersRegistered = true;
|
||||
}
|
||||
|
||||
@@ -96,6 +108,21 @@ export function createApp(config, prisma) {
|
||||
return res.status(400).json({ error: 'qualities must have one entry per uploaded file, or be omitted' });
|
||||
}
|
||||
|
||||
let iconSizes;
|
||||
try {
|
||||
iconSizes = JSON.parse(req.body.iconSizes ?? '[]');
|
||||
} catch {
|
||||
return res.status(400).json({ error: 'iconSizes must be a JSON array' });
|
||||
}
|
||||
|
||||
if (!Array.isArray(iconSizes)) {
|
||||
return res.status(400).json({ error: 'iconSizes must be a JSON array' });
|
||||
}
|
||||
|
||||
if (iconSizes.length > 0 && iconSizes.length !== req.files.length) {
|
||||
return res.status(400).json({ error: 'iconSizes must have one entry per uploaded file, or be omitted' });
|
||||
}
|
||||
|
||||
const results = [];
|
||||
for (let i = 0; i < req.files.length; i += 1) {
|
||||
const file = req.files[i];
|
||||
@@ -130,6 +157,16 @@ export function createApp(config, prisma) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const requestedIconSize = iconSizes[i] ?? null;
|
||||
if (!isValidIconSize(targetFormat, requestedIconSize)) {
|
||||
await deleteIfExists(file.path);
|
||||
results.push({
|
||||
file: file.originalname,
|
||||
error: `Invalid iconSize for target format ${targetFormat}`,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const expiresAt = new Date(Date.now() + config.retentionHours * 3600 * 1000);
|
||||
await createJob(prisma, {
|
||||
uuid,
|
||||
@@ -142,6 +179,7 @@ export function createApp(config, prisma) {
|
||||
inputSizeBytes: file.size,
|
||||
expiresAt,
|
||||
quality: requestedQuality,
|
||||
iconSize: requestedIconSize,
|
||||
});
|
||||
|
||||
results.push({ file: file.originalname, id: uuid, status: 'pending' });
|
||||
|
||||
Reference in New Issue
Block a user