feat(F-056): completed feature

This commit is contained in:
chattie
2026-08-19 15:10:09 +02:00
parent cc84f24658
commit a967e49851
29 changed files with 946 additions and 43 deletions

View File

@@ -14,6 +14,9 @@ const PEER_UPLOAD_DIRS = [
path.join(process.cwd(), '..', '..', 'storefront', 'public', 'uploads'),
];
/** Thumbnail widths pre-generated for lists (40px) and previews (200px). */
const THUMBNAIL_WIDTHS = [40, 200];
async function mirrorToPeers(filePath: string): Promise<void> {
await Promise.allSettled(
PEER_UPLOAD_DIRS.map(async (dir) => {
@@ -23,6 +26,34 @@ async function mirrorToPeers(filePath: string): Promise<void> {
);
}
/**
* Generate the 40px/200px thumbnails for every upload directory right after
* the file lands on disk, so list and preview URLs (`/uploads/40/<file>` and
* `/uploads/200/<file>`) resolve without waiting for the batch script.
* Failures are non-fatal: the dynamic `/uploads/[...path]` handler regenerates
* missing thumbnails on demand.
*/
async function generateThumbnails(buffer: Buffer, filename: string): Promise<void> {
let sharp: (input: Buffer) => import('sharp').Sharp;
try {
({ default: sharp } = await import('sharp'));
} catch {
return;
}
const targets = [path.join(process.cwd(), 'public', 'uploads'), ...PEER_UPLOAD_DIRS];
await Promise.allSettled(
targets.flatMap((dir) =>
THUMBNAIL_WIDTHS.map(async (width) => {
const thumbDir = path.join(dir, String(width));
await mkdir(thumbDir, { recursive: true });
const resized = await sharp(buffer).resize({ width, withoutEnlargement: true }).toBuffer();
await writeFile(path.join(thumbDir, filename), resized);
}),
),
);
}
const API = process.env.NEXT_PUBLIC_API_URL ?? 'http://127.0.0.1:3000';
const MAX_SIZE = 10 * 1024 * 1024;
const EXTENSION_BY_TYPE: Readonly<Record<string, string>> = {
@@ -70,6 +101,7 @@ export async function POST(request: NextRequest) {
await mkdir(uploadDir, { recursive: true });
await writeFile(filePath, buffer, { flag: 'wx' });
await mirrorToPeers(filePath);
await generateThumbnails(buffer, filename);
return NextResponse.json({
url: `/uploads/${filename}`,