freedge/backend/src/utils/storage.ts
ordinarthur fc3dfe83c9 refactor(backend): migrate from JavaScript to TypeScript
- tsconfig.json strict mode (noImplicitAny, strictNullChecks, noUnused*)
- Replace nodemon with tsx (watch + run TS directly)
- Build script (tsc -> dist/) and typecheck script
- Fastify decorator types in types/fastify.d.ts (prisma, openai,
  stripe, googleClient, auth helpers, ai helpers, request.user)
- Typed route handlers with generic Body/Params
- Strict null checks on Prisma results and env vars
- Stripe plugin now optional (no-op if STRIPE_SECRET_KEY missing)
- Delete dead utils/errors.js (empty) and utils/resend.js
  (contained a hardcoded Resend API key, unused)
- Add @types/bcrypt, @types/nodemailer, typescript-eslint
- ESLint upgraded to typescript-eslint flat config
- deploy.sh: run prisma generate, migrate deploy, backend build

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 22:36:21 +02:00

81 lines
2.5 KiB
TypeScript

import * as Minio from 'minio';
import * as https from 'node:https';
import type { Readable } from 'node:stream';
interface UploadableFile {
filename: string;
file: Readable | Buffer;
}
let minioClient: Minio.Client | null = null;
function getClient(): Minio.Client | null {
if (minioClient) return minioClient;
if (!process.env.MINIO_ENDPOINT || !process.env.MINIO_ACCESS_KEY) {
return null;
}
const useSSL = process.env.MINIO_USE_SSL === 'true';
const allowSelfSigned = process.env.MINIO_ALLOW_SELF_SIGNED === 'true';
const clientOpts: Minio.ClientOptions = {
endPoint: process.env.MINIO_ENDPOINT.replace(/^https?:\/\//, ''),
port: parseInt(process.env.MINIO_PORT ?? '9000', 10),
useSSL,
accessKey: process.env.MINIO_ACCESS_KEY,
secretKey: process.env.MINIO_SECRET_KEY ?? '',
pathStyle: true,
};
// Ne désactiver la vérification TLS que si explicitement demandé.
if (useSSL && allowSelfSigned) {
(clientOpts as Minio.ClientOptions & { transport?: unknown }).transport = {
agent: new https.Agent({ rejectUnauthorized: false }),
};
}
minioClient = new Minio.Client(clientOpts);
return minioClient;
}
function bucket(): string {
const b = process.env.MINIO_BUCKET;
if (!b) throw new Error('MINIO_BUCKET non défini');
return b;
}
export async function uploadFile(file: UploadableFile, folderPath: string): Promise<string> {
const client = getClient();
if (!client) throw new Error('MinIO non configuré');
const fileName = `${Date.now()}-${file.filename}`;
const filePath = `${folderPath}/${fileName}`;
await client.putObject(bucket(), filePath, file.file);
return filePath;
}
export async function deleteFile(filePath: string): Promise<void> {
const client = getClient();
if (!client) return;
await client.removeObject(bucket(), filePath);
}
export async function getFile(filePath: string): Promise<Readable> {
const client = getClient();
if (!client) throw new Error('MinIO non configuré');
return client.getObject(bucket(), filePath);
}
export async function listFiles(folderPath: string): Promise<Minio.BucketStream<Minio.BucketItem>> {
const client = getClient();
if (!client) throw new Error('MinIO non configuré');
return client.listObjects(bucket(), folderPath);
}
export async function getFileUrl(filePath: string): Promise<string> {
const client = getClient();
if (!client) throw new Error('MinIO non configuré');
return client.presignedUrl('GET', bucket(), filePath);
}