lrvo-doctor
Diagnostiquer un projet, variables d'environnement manquantes, contrat d'amorçage dérivé, versions incompatibles et vulnérabilités.
lrvo-doctor confronte un projet à la version de @lrvo/core qu'il a installée. Il ne modifie rien sans --fix, et ce qu'il répare avec --fix ne peut rien détruire.
npx lrvo-doctorOptions
| Option | Effet |
|---|---|
| (aucune) | Diagnostic seul. |
--fix | Applique les réparations sûres, puis re-diagnostique. |
--json | Sort les constats en JSON. |
--no-audit | Saute npm audit, qui est l'étape la plus lente. |
help | Affiche l'aide. |
Code de sortie 0 si aucun constat n'est bloquant, 1 sinon. Un avertissement ne bloque pas.
Les quatre vérifications
Variables d'environnement
Le catalogue de référence est l'union de deux déclarations : les variables que le core déclare dans src/core/doctor/env.js, et les envVars déclarées au manifeste de chaque module installé.
Il ne se lit pas dans .env.example. Ce fichier est le modèle de démarrage copié par @lrvo/start, donc réduit à ce qu'un nouveau projet doit remplir : le prendre pour une déclaration revenait à dénoncer comme inconnue toute variable que le core lit sans qu'elle figure au modèle.
Les modules sont lus qu'ils soient activés ou non. C'est délibéré : un LRVO_MODULE_<NOM> manquant est précisément ce qu'il faut signaler, et filtrer sur les modules actifs le cacherait.
Un manifeste peut déclarer un gabarit plutôt qu'une variable, LRVO_MODULE_POSTS_TYPE_<KEY> par exemple. Son absence n'est jamais signalée, puisque le nom réel dépend du projet, mais il sert à reconnaître ses instances : LRVO_MODULE_POSTS_TYPE_BLOGUE_LIST est une variable connue, pas une inconnue.
| Constat | Gravité |
|---|---|
| Variable absente et requise | Bloquant |
| Variable absente et optionnelle | Jamais signalée |
| Variable présente mais vide alors qu'elle est requise | Bloquant |
Variable requise déjà proposée par un --fix, encore commentée | Bloquant |
Variable LRVO_* inconnue du core et des modules | Information |
Trois variables du core sont requises, et leur absence est donc bloquante : LRVO_DATABASE_URL, LRVO_ENCRYPTION_KEY et NEXT_PUBLIC_URL. Le stockage, le courriel et les paiements restent optionnels : un projet sans téléversement, sans courriel transactionnel ou sans paiement est une configuration légitime.
Une variable optionnelle absente n'est pas une dérive. Sa valeur par défaut s'applique, le projet fonctionne, et le développeur n'a rien à faire. Un module de bonne taille en déclare trente, dont trois comptent vraiment : les signaler toutes noyait les trois. Le catalogue les garde malgré tout, puisque c'est lui qui distingue une clé connue d'une clé inconnue.
Corollaire assumé : une variable optionnelle ajoutée par une version ultérieure du core ou d'un module n'apparaît plus au diagnostic. C'est le CHANGELOG du paquet qui l'annonce, et lrvo-update qui le montre à l'installation.
Contrat de projet
Le contrat déclare les fichiers qu'un projet doit contenir pour que cette version du core démarre. Il vit dans le core, pas dans @lrvo/start : c'est le core qui change quand une sous-entrée bouge ou que l'ordre d'amorçage évolue, et un projet généré ne garde aucune trace de la version du starter qui l'a produit.
Deux modes de vérification :
| Mode | Fichiers | Comportement |
|---|---|---|
| Exact | Les réexports d'une ligne et les redirections fixes. | Aucune personnalisation n'a de sens. Un écart est bloquant. |
| Fragments | instrumentation.js, app/layout.js, theme.js, jsconfig.json. | Présence des fragments obligatoires vérifiée, jamais le contenu entier. Un fichier existant n'est jamais réécrit en entier : seuls ses correctifs ciblés, quand il en a, le modifient. |
jsconfig.json relève des fragments : un projet ajoute légitimement ses propres alias, seuls @styles et @components sont exigés parce que les gabarits du core en dépendent. La recherche d'un fragment ignore les blancs, donc un fichier repassé au formateur reste conforme.
Un fichier Exact n'est réécrit par --fix que s'il est absent ou s'il porte encore, au caractère près, le contenu d'une version antérieure du contrat. C'est ce qui permet de remonter un projet existant sans rien détruire : app/lrvo/[...path]/page.js, par exemple, a gagné l'import de app/.lrvo/public-pages.server.js, et un projet resté au réexport d'une ligne est corrigé automatiquement. Un contenu inconnu, lui, est signalé et laissé intact.
Quand un fichier ainsi réécrit référence un manifeste de app/.lrvo/ qui n'existe pas encore, la commande le dit et renvoie à npx lrvo-modules sync. Elle ne génère jamais ces fichiers elle-même : ils appartiennent à lrvo-modules, et les écrire ici écraserait un manifeste peuplé par une version vide.
La commande contrôle aussi que postinstall, dev et build lancent bien lrvo-modules sync.
Correctifs ciblés
Un fichier en fragments mêle le contrat et le code du projet : le réécrire perdrait ce code. Quand un changement du core suit un motif connu, l'entrée du contrat déclare un correctif ciblé, dans src/core/doctor/patches.js. Il ne touche que les lignes qu'il reconnaît, là où elles sont, et garde le reste au caractère près : commentaires, imports ajoutés, mise en forme.
Trois garde-fous le rendent sûr :
- Il renonce dans le doute. Deux appels à
initializeLrvo, une variablethemedéjà déclarée, unTHEME_INIT_SCRIPTutilisé ailleurs que dans la balise attendue : le correctif ne devine pas, le constat reste à corriger à la main avec la liste des fragments manquants. - Le résultat est revérifié avant l'écriture. Si un fragment manque encore après correction, rien n'est écrit : un fichier à moitié réparé serait pire qu'un constat.
- Il est rejouable. Un fichier déjà corrigé ressort inchangé.
Le diagnostic annonce le correctif avant de l'appliquer, et --fix distingue ce qu'il a créé, réécrit ou corrigé sur place.
| Correctif | Fichier | Effet |
|---|---|---|
instrumentation-theme | instrumentation.js | Ajoute l'import de ./theme.js au-dessus de l'appel à initializeLrvo, et y ajoute theme. Un appel étalé sur plusieurs lignes est remis sur une ligne. |
layout-theme-style | app/layout.js | Remplace la balise <script> de THEME_INIT_SCRIPT par <ThemeStyle />, ou l'ajoute en tête du <head>. Remplace l'import, en gardant les autres noms importés de @lrvo/core/themes. |
Le thème passe ainsi par trois fragments : instrumentation.js importe ./theme.js et appelle initializeLrvo({ modules, theme }), app/layout.js rend <ThemeStyle />, et theme.js exporte un defineTheme(...). Sur un projet antérieur au thème, npx lrvo-doctor --fix fait les trois : il corrige les deux premiers sur place et crée theme.js avec les valeurs par défaut. Voir Personnaliser l'apparence.
Versions et compatibilité
Confronte le core installé au requiresCore de chaque module, signale un manifeste dont la version diverge de son package.json, et compare les paquets tiers aux bornes de paquets supportés.
Le CLI est strict là où l'amorçage ne peut pas se le permettre : initializeLrvo se contente d'avertir sur une combinaison non testée, parce qu'une exception y mettrait un site de production à terre. Ici tout constat de compatibilité est bloquant.
Vulnérabilités
Lance npm audit --omit=dev et remonte chaque alerte jusqu'au paquet de premier niveau qui la tire. Si ce paquet figure dans supported.json et qu'il est sous la version validée, le remède affiché est npm update <paquet>. Ce n'est que lorsqu'il est déjà à jour que la piste overrides est proposée.
C'est l'automatisation de la règle décrite dans Sécurité : la plupart des alertes d'un site LRVO viennent de l'arbre de Next.js et disparaissent avec une montée de version.
Ce que --fix répare, et ce qu'il ne touche pas
| Situation | Action de --fix |
|---|---|
Variable requise absente du .env | Ajoutée en fin de fichier, commentée, avec sa description. |
| Fichier de contrat exact absent | Écrit avec le contenu attendu. |
| Fichier de contrat exact resté à une version antérieure du core | Remonté à la version courante. |
| Fichier de contrat exact au contenu inconnu | Laissé intact, signalé avec le contenu attendu. |
| Fichier à fragments absent, quand le contrat en porte un contenu de semis | Écrit avec ce contenu, jsconfig.json ou theme.js par exemple. |
| Fichier à fragments incomplet, reconnu par son correctif ciblé | Corrigé sur place : seules les lignes reconnues changent. Voir Correctifs ciblés. |
| Fichier à fragments incomplet, non reconnu ou sans correctif | Laissé intact, les fragments manquants sont affichés. |
instrumentation.js, app/layout.js | Jamais réécrits en entier. Ils mêlent contrat et code du projet, seuls leurs correctifs ciblés les modifient. |
Valeur existante dans le .env | Jamais modifiée. Aucune ligne n'est jamais supprimée. |
Les variables sont ajoutées commentées, donc --fix est incapable de changer le comportement du projet. Le développeur décommente ce qui le concerne. Un second --fix ne les rajoute pas : la commande reconnaît ce qu'elle a déjà proposé.
Sortie
◆ Diagnostic du projet...
✓ Variables d'environnement : rien à signaler
◆ Contrat de projet : 2 constat(s)
✗ app/lrvo/media/[filename]/route.js est absent. Route de service des fichiers.
⚠ Le script "dev" ne lance pas « lrvo-modules sync ».
✓ Versions et compatibilité : rien à signaler
✓ Vulnérabilités : rien à signaler
✗ 1 constat(s) bloquant(s), 1 avertissement(s)
· 1 réparable(s) : lance « npx lrvo-doctor --fix »Notes
Un projet fraîchement généré est déclaré conforme. C'est la condition de crédibilité de l'outil, et elle est vérifiée à la publication de @lrvo/start par son script check:contract.
Le diagnostic ne demande aucune base de données. Seules les vérifications de migration passent par la base, et elles vivent dans lrvo-db.
npm audit est lancé sans shell, de la même façon que les lectures de lrvo-update, Windows compris. Si npm reste introuvable, la vérification rapporte « npm audit n'a rien retourné d'exploitable » au lieu d'échouer.
--fix re-diagnostique après réparation, pour que le code de sortie reflète l'état final du projet et non celui d'avant les corrections.