fix(frontend): écran noir plutôt que muet sur crash de plugin ou d'activation figée

Complète le diagnostic backend (#120) côté frontend : un crash React non
capturé (ex. plugin cassant le rendu) laissait un écran noir sans trace, et
une activation de plugin qui ne se résout jamais (promesse infinie) bloquait
le chargement sans échouer. Ajoute RootErrorBoundary + logging d'erreurs
globales autour de l'arbre React, et un timeout sur l'import/l'activation de
chaque plugin dans loadPlugins pour transformer un hang silencieux en échec
explicite et diagnosticable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 09:48:49 +02:00
parent 961bf4623f
commit c19fb6bf8c
5 changed files with 260 additions and 12 deletions

View File

@ -305,6 +305,28 @@ describe("loadPlugins", () => {
);
});
it("collects a failure when plugin activation does not settle", async () => {
const bundle = dataUrl(`
export function activate() {
return new Promise(() => {});
}
`);
const { registry, failures } = await loadPlugins(
[entry({ id: "dev.acme.hung", displayName: "Hung", bundleUrl: bundle })],
gateways,
{ timeoutMs: 10 },
);
expect(registry.list()).toEqual([]);
expect(failures).toEqual([
{
pluginId: "dev.acme.hung",
reason: "activating plugin timed out after 10 ms",
},
]);
});
it("only loads what the catalog contains — a disabled/absent plugin is simply never in it", async () => {
// The backend contract (carnet §1.3) filters the catalog to
// `enabled && !pendingUninstall` before the loader ever sees it; the