Modules
Registre runtime des packages @lrvo/module-* découverts et activés dans le projet consommateur.
core/modules tient le registre des modules @lrvo/module-* activés. Il ne charge rien lui-même : il est peuplé par le manifeste statique généré dans le projet consommateur.
Pour écrire un module, voir Créer un module. Pour comprendre la découverte et la synchronisation, voir Cycle de vie d'un module.
Import
import {
registerModules, registerModule,
getRegisteredModules, getRegisteredModule, clearRegisteredModules,
onModulesReady, flushModulesReady, resetModulesReady,
findInstalledModuleNames, moduleHasClientEntry, loadModulesForCli,
validateModuleEnvVars, moduleEnvKey, isModuleEnabled,
} from '@lrvo/core/modules';Module serveur : discover.server.js lit le système de fichiers.
API
| Fonction | Rôle |
|---|---|
registerModules(modules) | Peuple le registre depuis le manifeste. Appelée par initializeLrvo({ modules }). |
registerModule(mod) | Bas niveau, utilisée par registerModules. |
getRegisteredModules() | Retourne tous les modules connus. Utilisée par lrvo-db init et la validation d'environnement. |
getRegisteredModule(name) | Retourne un module par son nom de package. |
clearRegisteredModules() | Vide le registre. Usage tests. |
onModulesReady(callback) | Reporte un traitement au moment où tous les modules sont enregistrés. Voir Enregistrement inter-modules. |
flushModulesReady() | Exécute les callbacks en attente. Appelée par initializeLrvo() seulement. |
resetModulesReady() | Vide la file et repasse en mode non initialisé. Usage tests. |
findInstalledModuleNames({ cwd }) | Scan en lecture seule du package.json du projet. Utilisée par lrvo-modules sync. |
moduleHasClientEntry(name) | Indique si le package expose une sous-entrée ./client. Décide de son inclusion dans le manifeste client. |
moduleHasPublicPageEntry(name) | Indique si le package expose une sous-entrée ./public-page. Décide de son inclusion dans le manifeste des pages publiques. |
loadModulesForCli() | Charge les modules hors contexte Next.js, pour lrvo-db. |
validateModuleEnvVars(modules) | Journalise un avertissement par variable requise absente. |
moduleEnvKey(name) | Retourne la variable d'activation associée à un package, par exemple LRVO_MODULE_MEDIAS. |
isModuleEnabled(name) | Indique si le module est activé par sa variable d'environnement. |
Forme attendue d'un module
Le point d'entrée d'un package @lrvo/module-* doit exporter :
| Export | Type | Obligatoire |
|---|---|---|
manifest | { name, version, requiresCore?, permissions?, envVars? } | oui |
register | () => void | Promise<void> | oui |
createTables | async () => { created?, skipped? } | si le module a des tables |
dropTables | async () => void | si le module a des tables |
migrations | Array<{ id, description?, up }> | si le schéma a évolué depuis sa création |
Activation
La découverte inclut un package installé ; l'activation est un second interrupteur, porté par une variable d'environnement propre au module (LRVO_MODULE_<NOM>=true). Un module découvert mais non activé n'enregistre rien.
Enregistrement inter-modules
Le manifeste généré déclenche les register() de tous les modules en parallèle :
await Promise.all(modules.map(m => m.exports.register?.()));L'ordre d'évaluation des register-server.js n'est donc pas garanti. Un module qui lit au niveau racine de son register-server.js un état publié par un autre module lit une valeur non encore écrite, au hasard de la taille du graphe d'imports de chacun. Le symptôme typique est un avertissement « module X n'est pas activé » alors qu'il l'est.
onModulesReady(callback) est le seul point de lecture fiable : initializeLrvo() appelle flushModulesReady() après l'import du manifeste et le peuplement du registre.
import { onModulesReady } from '@lrvo/core/modules';
import { isMediaEnabled } from '@lrvo/core/media-registry';
onModulesReady(() => {
if (!isMediaEnabled()) {
console.warn('[@lrvo/module-exemple] champs image configurés sans module médias');
}
});Un callback enregistré après le flush s'exécute immédiatement, pour qu'un module chargé tardivement ou rechargé à chaud ne reste pas silencieux. Un callback qui lève est journalisé et n'interrompt ni les suivants ni le boot.
Ce mécanisme sert aux diagnostics et au câblage optionnel. Il ne remplace pas une dépendance réelle : un module qui ne peut pas fonctionner sans un autre le déclare dans ses peerDependencies.
Notes
Le registre est un singleton sur globalThis. Deux copies du registre voudraient dire deux jeux de modules, l'un peuplé et l'autre vide selon le chemin d'import. C'est aussi la raison pour laquelle le build n'inline jamais ces fichiers. Voir Registres et singletons et Build et exports.
Les modules sont chargés en ESM natif, hors condition react-server. C'est ce qui interdit un import { cookies } from 'next/headers' au top-level dans la chaîne register(). Voir Frontières serveur/client.