File size: 2,496 Bytes
f555806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* eslint-disable */
import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs';
import fsp from 'fs/promises';
import path from 'path';
import archiver from 'archiver';
import { getTrainingFolder } from '@/server/settings';

export const runtime = 'nodejs'; // ensure Node APIs are available
export const dynamic = 'force-dynamic'; // long-running, non-cached

type PostBody = {
  zipTarget: 'samples'; //only samples for now
  jobName: string;
};

async function resolveSafe(p: string) {
  // resolve symlinks + normalize
  return await fsp.realpath(p);
}

export async function POST(request: NextRequest) {
  try {
    const body = (await request.json()) as PostBody;
    if (!body || !body.jobName) {
      return NextResponse.json({ error: 'jobName is required' }, { status: 400 });
    }

    const trainingRoot = await resolveSafe(await getTrainingFolder());
    const folderPath = await resolveSafe(path.join(trainingRoot, body.jobName, 'samples'));
    const outputPath = path.resolve(trainingRoot, body.jobName, 'samples.zip');

    // Must be a directory
    let stat: fs.Stats;
    try {
      stat = await fsp.stat(folderPath);
    } catch {
      return new NextResponse('Folder not found', { status: 404 });
    }
    if (!stat.isDirectory()) {
      return new NextResponse('Not a directory', { status: 400 });
    }

    // delete current one if it exists
    if (fs.existsSync(outputPath)) {
      await fsp.unlink(outputPath);
    }

    // Create write stream & archive
    await new Promise<void>((resolve, reject) => {
      const output = fs.createWriteStream(outputPath);
      const archive = archiver('zip', { zlib: { level: 9 } });

      output.on('close', () => resolve());
      output.on('error', reject);
      archive.on('error', reject);

      archive.pipe(output);

      // Add the directory contents (place them under the folder's base name in the zip)
      const rootName = path.basename(folderPath);
      archive.directory(folderPath, rootName);

      archive.finalize().catch(reject);
    });

    // Return the absolute path so your existing /api/files/[...filePath] can serve it
    // Example download URL (client-side): `/api/files/${encodeURIComponent(resolvedOutPath)}`
    return NextResponse.json({
      ok: true,
      zipPath: outputPath,
      fileName: path.basename(outputPath),
    });
  } catch (err) {
    console.error('Zip error:', err);
    return new NextResponse('Internal Server Error', { status: 500 });
  }
}