feat: add storage path helpers
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
export async function ensureStorageDirs(config) {
|
||||||
|
await fs.mkdir(path.join(config.storageDir, 'uploads'), { recursive: true });
|
||||||
|
await fs.mkdir(path.join(config.storageDir, 'outputs'), { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function uploadPath(config, id, ext) {
|
||||||
|
return path.join(config.storageDir, 'uploads', `${id}.${ext}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function outputPath(config, id, ext) {
|
||||||
|
return path.join(config.storageDir, 'outputs', `${id}.${ext}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteIfExists(filePath) {
|
||||||
|
try {
|
||||||
|
await fs.unlink(filePath);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT') throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import os from 'node:os';
|
||||||
|
import { ensureStorageDirs, uploadPath, outputPath, deleteIfExists } from '../src/storage.js';
|
||||||
|
|
||||||
|
let tmpDir;
|
||||||
|
let config;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'converter-storage-'));
|
||||||
|
config = { storageDir: tmpDir };
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('storage', () => {
|
||||||
|
it('creates uploads and outputs directories', async () => {
|
||||||
|
await ensureStorageDirs(config);
|
||||||
|
|
||||||
|
const uploadsStat = await fs.stat(path.join(tmpDir, 'uploads'));
|
||||||
|
const outputsStat = await fs.stat(path.join(tmpDir, 'outputs'));
|
||||||
|
|
||||||
|
expect(uploadsStat.isDirectory()).toBe(true);
|
||||||
|
expect(outputsStat.isDirectory()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('builds upload and output paths as <uuid>.<ext>', () => {
|
||||||
|
const id = '11111111-1111-4111-8111-111111111111';
|
||||||
|
|
||||||
|
expect(uploadPath(config, id, 'png')).toBe(path.join(tmpDir, 'uploads', `${id}.png`));
|
||||||
|
expect(outputPath(config, id, 'pdf')).toBe(path.join(tmpDir, 'outputs', `${id}.pdf`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deletes an existing file', async () => {
|
||||||
|
await ensureStorageDirs(config);
|
||||||
|
const filePath = uploadPath(config, 'file-to-delete', 'txt');
|
||||||
|
await fs.writeFile(filePath, 'content');
|
||||||
|
|
||||||
|
await deleteIfExists(filePath);
|
||||||
|
|
||||||
|
await expect(fs.stat(filePath)).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not throw when deleting a missing file', async () => {
|
||||||
|
const filePath = uploadPath(config, 'does-not-exist', 'txt');
|
||||||
|
|
||||||
|
await expect(deleteIfExists(filePath)).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user