import fs from 'node:fs'; import fsp from 'node:fs/promises'; import path from 'node:path'; import { spawn } from 'node:child_process'; import { safeJoin } from './paths.mjs'; export async function createZipStream(ctx, items) { const existing = []; for (const rel of items) { const full = safeJoin(ctx.uploadDir, rel); if (fs.existsSync(full)) existing.push({ rel, full }); } if (!existing.length) throw new Error('no files'); const tmpZip = path.join(ctx.uploadDir, ctx.metaDirName, `download-${Date.now()}.zip`); await fsp.mkdir(path.dirname(tmpZip), { recursive: true }); await new Promise((resolve, reject) => { const args = ['-r', tmpZip, ...existing.map((x) => x.full)]; const proc = spawn('zip', args, { cwd: ctx.uploadDir }); proc.on('error', reject); proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`zip exit ${code}`)))); }); const stream = fs.createReadStream(tmpZip); stream.on('close', () => fsp.unlink(tmpZip).catch(() => {})); return stream; }