feat(FN-3573): harden plugin setup sync and test-isolation handling
- Add plugin setup API coverage for migration and sync edge cases - Expand plugin route tests and implementation safeguards for setup state handling - Update legacy API glue to align plugin setup responses with route behavior - Keep test-isolation runtime ignore handling compatible with live app activity Fusion-Task-Id: FN-3573
This commit is contained in:
@@ -196,10 +196,6 @@ export function createPluginRouter(
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
// ── Error Handler ───────────────────────────────────────────────
|
||||
|
||||
router.use(catchHandler);
|
||||
|
||||
// ── Management Routes ───────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -366,6 +362,88 @@ export function createPluginRouter(
|
||||
res.json(updatedPlugin);
|
||||
}));
|
||||
|
||||
/**
|
||||
* GET /plugins/:id/setup-status
|
||||
* Check plugin setup status.
|
||||
*/
|
||||
router.get("/:id/setup-status", catchHandler(async (req: Request, res: Response) => {
|
||||
const id = req.params.id as string;
|
||||
|
||||
let plugin: import("@fusion/core").PluginInstallation;
|
||||
try {
|
||||
plugin = await pluginStore.getPlugin(id);
|
||||
} catch (err: unknown) {
|
||||
if (
|
||||
(err as NodeJS.ErrnoException).code === "ENOENT"
|
||||
|| (err instanceof Error && err.message.includes("not found"))
|
||||
) {
|
||||
throw notFound(`Plugin "${id}" not found`);
|
||||
}
|
||||
throw internalError(err instanceof Error ? err.message : "Unknown error");
|
||||
}
|
||||
|
||||
if (!pluginRunner?.checkPluginSetup || !pluginRunner.getPluginSetupInfo) {
|
||||
throw internalError("Plugin runner not available");
|
||||
}
|
||||
|
||||
const setupInfo = pluginRunner.getPluginSetupInfo();
|
||||
const hasSetup = setupInfo.some((entry) => entry.pluginId === id);
|
||||
|
||||
if (!hasSetup) {
|
||||
res.json({ hasSetup: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.state !== "started") {
|
||||
res.json({
|
||||
hasSetup: false,
|
||||
status: { status: "error", error: "Plugin not loaded" },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const status = await pluginRunner.checkPluginSetup(id);
|
||||
res.json({ hasSetup: true, ...status });
|
||||
}));
|
||||
|
||||
/**
|
||||
* POST /plugins/:id/setup/install
|
||||
* Trigger plugin setup install hook.
|
||||
*/
|
||||
router.post("/:id/setup/install", catchHandler(async (req: Request, res: Response) => {
|
||||
const id = req.params.id as string;
|
||||
|
||||
let plugin: import("@fusion/core").PluginInstallation;
|
||||
try {
|
||||
plugin = await pluginStore.getPlugin(id);
|
||||
} catch (err: unknown) {
|
||||
if (
|
||||
(err as NodeJS.ErrnoException).code === "ENOENT"
|
||||
|| (err instanceof Error && err.message.includes("not found"))
|
||||
) {
|
||||
throw notFound(`Plugin "${id}" not found`);
|
||||
}
|
||||
throw internalError(err instanceof Error ? err.message : "Unknown error");
|
||||
}
|
||||
|
||||
if (!plugin.enabled) {
|
||||
throw badRequest("Plugin must be enabled before setup install");
|
||||
}
|
||||
|
||||
if (!pluginRunner?.installPluginSetup || !pluginRunner.getPluginSetupInfo) {
|
||||
throw internalError("Plugin runner not available");
|
||||
}
|
||||
|
||||
const setupInfo = pluginRunner.getPluginSetupInfo();
|
||||
const setup = setupInfo.find((entry) => entry.pluginId === id);
|
||||
if (!setup?.hooks.install) {
|
||||
throw badRequest("Plugin has no install hook");
|
||||
}
|
||||
|
||||
const result = await pluginRunner.installPluginSetup(id);
|
||||
res.json(result ?? { success: true });
|
||||
}));
|
||||
|
||||
/**
|
||||
* DELETE /plugins/:id
|
||||
* Uninstall a plugin.
|
||||
|
||||
Reference in New Issue
Block a user