From 8d6deb8691d786df53fde8a2a2b1a6bfdff54b7c Mon Sep 17 00:00:00 2001 From: z3n Date: Fri, 29 May 2026 14:45:39 +0000 Subject: [PATCH] =?UTF-8?q?fix(uploads):=20compatibilit=C3=A9=20Windows=20?= =?UTF-8?q?pour=20l'upload=20multi-fichiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remplace /tmp/uploads par os.tmpdir() (cross-platform) - Ajoute node_modules/.bin au PATH des commandes bundle asyncapi/redocly - Supprime la déclaration en double de execFileAsync Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- .../src/modules/uploads/uploads.controller.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/back/src/modules/uploads/uploads.controller.ts b/back/src/modules/uploads/uploads.controller.ts index 639ba17..2a6a176 100644 --- a/back/src/modules/uploads/uploads.controller.ts +++ b/back/src/modules/uploads/uploads.controller.ts @@ -11,15 +11,21 @@ import { diskStorage } from 'multer'; import * as fs from 'fs'; import * as fsPromises from 'fs/promises'; import * as path from 'path'; +import * as os from 'os'; import { execFile } from 'child_process'; import { promisify } from 'util'; import { randomUUID } from 'crypto'; + +const execFileAsync = promisify(execFile); +const localBin = path.join(process.cwd(), 'node_modules', '.bin'); +const execEnv = { + ...process.env, + PATH: `${localBin}${path.delimiter}${process.env.PATH ?? ''}`, +}; import { ApisService } from '../apis/apis.service'; import { DocsGenerationService } from '../docs-generation/docs-generation.service'; import { ApiType } from '@datacat/shared'; -const execFileAsync = promisify(execFile); - @Controller('uploads') export class UploadsController { constructor( @@ -30,7 +36,7 @@ export class UploadsController { @Post() @UseInterceptors( FilesInterceptor('files', 20, { - storage: diskStorage({ destination: '/tmp/uploads' }), + storage: diskStorage({ destination: path.join(os.tmpdir(), 'datacat-uploads') }), fileFilter: (_req, file, cb) => { if (!file.originalname.match(/\.(yaml|yml)$/i)) { return cb(new BadRequestException('Only YAML files are allowed'), false); @@ -61,8 +67,9 @@ export class UploadsController { if (!body.version) throw new BadRequestException('version is required'); /* Crée le répertoire si absent */ - if (!fs.existsSync('/tmp/uploads')) { - fs.mkdirSync('/tmp/uploads', { recursive: true }); + const uploadDir = path.join(os.tmpdir(), 'datacat-uploads'); + if (!fs.existsSync(uploadDir)) { + fs.mkdirSync(uploadDir, { recursive: true }); } let yamlContent: string; @@ -131,7 +138,7 @@ export class UploadsController { mainFile: Express.Multer.File, type: ApiType, ): Promise { - const tempDir = `/tmp/uploads/${randomUUID()}`; + const tempDir = path.join(os.tmpdir(), 'datacat-uploads', randomUUID()); const bundledPath = path.join(tempDir, 'bundled.yaml'); try { @@ -145,9 +152,9 @@ export class UploadsController { const mainPath = path.join(tempDir, mainFile.originalname); if (type === 'OPENAPI') { - await execFileAsync('redocly', ['bundle', mainPath, '--output', bundledPath]); + await execFileAsync('redocly', ['bundle', mainPath, '--output', bundledPath], { shell: true, env: execEnv }); } else { - await execFileAsync('asyncapi', ['bundle', mainPath, '--output', bundledPath]); + await execFileAsync('asyncapi', ['bundle', mainPath, '--output', bundledPath], { shell: true, env: execEnv }); } return await fsPromises.readFile(bundledPath, 'utf-8');