- 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>
81 lines
2.5 KiB
TypeScript
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);
|
|
}
|