diff --git a/src/app.js b/src/app.js index b22a2f2..b5a4770 100644 --- a/src/app.js +++ b/src/app.js @@ -10,6 +10,8 @@ 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 { registerFontConverter } from './converters/font.js'; +import { registerDfontConverter } from './converters/dfont.js'; import { resolveInputFormat } from './mime.js'; import { deleteIfExists } from './storage.js'; import { createJob, getJobByUuid } from './jobs/jobRepository.js'; @@ -40,6 +42,8 @@ function registerAllConverters() { registerDocumentConverters(); registerIcoConverter(); registerHeicConverter(); + registerFontConverter(); + registerDfontConverter(); convertersRegistered = true; } diff --git a/src/worker.js b/src/worker.js index 4a3dd72..8f17127 100644 --- a/src/worker.js +++ b/src/worker.js @@ -10,6 +10,8 @@ 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 { registerFontConverter } from './converters/font.js'; +import { registerDfontConverter } from './converters/dfont.js'; import { findPendingJobs, markProcessing, markDone, markFailed } from './jobs/jobRepository.js'; const JOB_TIMEOUT_MS = 60000; @@ -82,6 +84,8 @@ async function main() { registerDocumentConverters(); registerIcoConverter(); registerHeicConverter(); + registerFontConverter(); + registerDfontConverter(); startWorker(prisma, config); console.log(`Worker started, polling every ${config.workerPollIntervalMs}ms`); diff --git a/test/api/jobs.test.js b/test/api/jobs.test.js index 829df11..8f763c3 100644 --- a/test/api/jobs.test.js +++ b/test/api/jobs.test.js @@ -179,6 +179,48 @@ describe('POST /api/jobs', () => { expect(response.body.jobs[0].error).toMatch(/Invalid quality/); }); + it('creates a pending job converting an OTF upload to ttf', async () => { + const fixturePath = path.join(import.meta.dirname, '..', 'fixtures', 'sample.otf'); + + const response = await request(app) + .post('/api/jobs') + .field('targetFormats', JSON.stringify(['ttf'])) + .attach('files', fixturePath, 'font.otf'); + + expect(response.status).toBe(201); + expect(response.body.jobs[0].status).toBe('pending'); + + const job = await getJobByUuid(prisma, response.body.jobs[0].id); + expect(job.sourceFormat).toBe('otf'); + expect(job.targetFormat).toBe('ttf'); + expect(job.family).toBe('font'); + expect(job.inputMimeType).toBe('font/otf'); + }); + + it('creates a pending job converting a dfont upload despite file-type misidentifying its content as ico', async () => { + const fixturePath = path.join(import.meta.dirname, '..', 'fixtures', 'sample.dfont'); + + const response = await request(app) + .post('/api/jobs') + .field('targetFormats', JSON.stringify(['ttf'])) + .attach('files', fixturePath, 'font.dfont'); + + expect(response.status).toBe(201); + expect(response.body.jobs[0].status).toBe('pending'); + + const job = await getJobByUuid(prisma, response.body.jobs[0].id); + expect(job.sourceFormat).toBe('dfont'); + expect(job.inputMimeType).toBe('application/x-dfont'); + }); + + it('lists ttf/otf/woff as targets for each other via GET /api/formats, and never lists dfont as a target', async () => { + const ttfTargets = await request(app).get('/api/formats').query({ source: 'ttf' }); + expect(ttfTargets.body.targets).toEqual(expect.arrayContaining(['otf', 'woff'])); + + const otfTargets = await request(app).get('/api/formats').query({ source: 'otf' }); + expect(otfTargets.body.targets).not.toContain('dfont'); + }); + it('creates a pending job converting a HEIC upload to jpg', async () => { const fixturePath = path.join(import.meta.dirname, '..', 'fixtures', 'sample.heic');