fix(server): rendre les chemins par défaut indépendants du cwd

CLIENT_DIST_PATH et TMP_DIR se résolvaient via process.cwd(), donc
uniquement correct si le process est lancé depuis server/. Repéré en
mettant en place la prévisualisation locale (.claude/launch.json, non
versionné) : npm --prefix server run dev depuis la racine du dépôt ne
change pas le cwd du script lancé, `npm --prefix server exec -- node -e
"console.log(process.cwd())"` le confirme (reste la racine du dépôt).

Résout désormais les deux chemins depuis l'emplacement du module
(import.meta.url) plutôt que process.cwd() - invariant quel que soit le
répertoire de lancement, y compris en Docker.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Nicolas 2026-09-16 19:27:42 +02:00
parent 725c5a5a7f
commit cbfce996ed
2 changed files with 12 additions and 4 deletions

View file

@ -1,4 +1,5 @@
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
/**
* Configuration runtime du serveur, dérivée des variables d'environnement.
@ -16,11 +17,18 @@ export interface ServerConfig {
readonly maxConcurrentDownloads: number;
}
// Dossier contenant ce module compilé (server/dist/ en prod, server/src/ sous
// tsx en dev - même profondeur sous server/ dans les deux cas). Sert de base
// aux chemins par défaut ci-dessous : contrairement à process.cwd(), invariant
// quel que soit le répertoire depuis lequel le process a été lancé (ex. `npm
// --prefix server run dev` depuis la racine du dépôt ne change pas le cwd).
const here = fileURLToPath(new URL('.', import.meta.url));
/**
* Construit la configuration du serveur à partir des variables d'environnement,
* en appliquant des valeurs par défaut adaptées au développement local (le
* client compilé et le dossier temporaire sont alors supposés voisins de
* `server/`).
* `server/`, indépendamment du répertoire de travail courant).
*
* @returns La configuration runtime résolue.
*/
@ -31,8 +39,8 @@ export function loadConfig(): ServerConfig {
return {
port: Number.isNaN(parsedPort) ? 3000 : parsedPort,
host: process.env.HOST ?? '0.0.0.0',
clientDistPath: process.env.CLIENT_DIST_PATH ?? resolve(process.cwd(), '../client/dist'),
tmpDir: process.env.TMP_DIR ?? resolve(process.cwd(), 'tmp'),
clientDistPath: process.env.CLIENT_DIST_PATH ?? resolve(here, '../../client/dist'),
tmpDir: process.env.TMP_DIR ?? resolve(here, '../tmp'),
maxConcurrentDownloads:
Number.isNaN(parsedConcurrency) || parsedConcurrency < 1 ? 2 : parsedConcurrency,
};

View file

@ -18,7 +18,7 @@ Pas de `docker-compose.yml` pour l'instant (une seule image, pas encore de dépe
- Fastify 5, TypeScript strict, ESM (`"type": "module"`, imports relatifs en `.js`, résolution `NodeNext`).
- `src/index.ts` : bootstrap (plugins, écoute, arrêt propre SIGINT/SIGTERM).
- `src/config.ts` : configuration runtime depuis l'environnement (`PORT`, `HOST`, `CLIENT_DIST_PATH`).
- `src/config.ts` : configuration runtime depuis l'environnement (`PORT`, `HOST`, `CLIENT_DIST_PATH`, `TMP_DIR`, `MAX_CONCURRENT_DOWNLOADS`). Les valeurs par défaut de `CLIENT_DIST_PATH`/`TMP_DIR` sont résolues depuis l'emplacement du module (`import.meta.url`), pas `process.cwd()` : reste correct quel que soit le répertoire depuis lequel le process est lancé (ex. `npm --prefix server run dev` depuis la racine du dépôt, utilisé par `.claude/launch.json` pour la prévisualisation - non versionné, voir `.gitignore`).
- `src/routes/` : routes Fastify enregistrées comme plugins (`health.ts`, `channel.ts`, `queue.ts`). Chaque domaine métier suit le même principe : un plugin de route fin sous `src/routes/`, qui délègue à un service sous `src/services/`.
- `src/services/` :
- `ytDlpRunner.ts` : exécution bas niveau de yt-dlp (`node:child_process.spawn`, jamais de shell - arguments toujours passés en tableau, jamais concaténés dans une chaîne, pour exclure toute injection de commande). Supporte le suivi ligne par ligne de stdout (`onStdoutLine`, pour la progression) et l'annulation via `AbortSignal`.