mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 22:25:24 +00:00
feat: load plugin frontends at runtime and remove plugin ids from the shell
This commit is contained in:
1 parent
49f0286a14
commit
e88d5a52e3
721 files changed
+54265
-44416
No files matched your search
@@ -13,6 +13,7 @@ import {
|
||||
createCurrentPluginRepository,
|
||||
} from "../repositories/factory.js";
|
||||
import { getPluginRuntime } from "../../plugins/index.js";
|
||||
import { describePluginFrontend } from "../../plugins/assets.js";
|
||||
import { invalidatePluginPermissionCache } from "../../plugins/permissions.js";
|
||||
import {
|
||||
findField,
|
||||
@@ -44,6 +45,65 @@ const requireManagePlugins = permissionManager.requirePermission(
|
||||
"admin.plugins.manage",
|
||||
);
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /plugins/public:
|
||||
* get:
|
||||
* summary: List the plugin frontends anonymous guest pages need
|
||||
* description: >
|
||||
* No auth. A shared-session or collab guest link has no session, yet its
|
||||
* page still draws surfaces a plugin provides (a remote desktop stream).
|
||||
* Returns only enabled plugins whose manifest sets contributes.guest,
|
||||
* with the fields the browser loader needs and nothing operational.
|
||||
* tags:
|
||||
* - Plugins
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Guest-capable plugins.
|
||||
*/
|
||||
router.get("/public", async (_req: Request, res: Response) => {
|
||||
try {
|
||||
const records = await createCurrentPluginRepository().listAll();
|
||||
const { loader } = getPluginRuntime();
|
||||
const plugins = records.flatMap((record) => {
|
||||
if (record.state !== "enabled") return [];
|
||||
const loaded = loader.get(record.id);
|
||||
let manifest: {
|
||||
contributes?: { guest?: boolean };
|
||||
dependencies?: Record<string, string>;
|
||||
optionalDependencies?: Record<string, string>;
|
||||
};
|
||||
try {
|
||||
manifest = JSON.parse(record.manifestJson);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
if (manifest?.contributes?.guest !== true) return [];
|
||||
return [
|
||||
{
|
||||
id: record.id,
|
||||
name: record.name,
|
||||
version: record.version,
|
||||
enabled: true,
|
||||
state: loaded?.state ?? record.state,
|
||||
contributes: { guest: true },
|
||||
dependencies: manifest.dependencies ?? {},
|
||||
optionalDependencies: manifest.optionalDependencies ?? {},
|
||||
...describePluginFrontend(loaded),
|
||||
},
|
||||
];
|
||||
});
|
||||
res.json(plugins);
|
||||
} catch (error) {
|
||||
databaseLogger.error(
|
||||
"Failed to list guest plugins",
|
||||
error instanceof Error ? error : new Error(String(error)),
|
||||
{ operation: "plugin_list_public" },
|
||||
);
|
||||
res.status(500).json({ error: "Failed to list plugins" });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /plugins:
|
||||
@@ -61,6 +121,13 @@ const requireManagePlugins = permissionManager.requirePermission(
|
||||
* do, what has been granted to it and why it failed are operational
|
||||
* details, so capabilities, grants and lastError are included only for
|
||||
* holders of admin.plugins.manage.
|
||||
*
|
||||
* The frontend fields drive the browser's plugin loader: `frontend`
|
||||
* says there is a bundle at /plugin-assets/<id>/frontend.js,
|
||||
* `assetVersion` is its cache key, `css` says a stylesheet sits beside
|
||||
* it, and `locales` lists the languages it ships ("en" and xx_YY).
|
||||
* `dependencies` and `optionalDependencies` let the loader activate
|
||||
* frontends in the same order the server does.
|
||||
* tags:
|
||||
* - Plugins
|
||||
* responses:
|
||||
@@ -100,17 +167,23 @@ router.get("/", authenticateJWT, async (req: Request, res: Response) => {
|
||||
let contributes: unknown = null;
|
||||
let capabilities: string[] = [];
|
||||
let icon: string | undefined;
|
||||
let dependencies: Record<string, string> = {};
|
||||
let optionalDependencies: Record<string, string> = {};
|
||||
try {
|
||||
const manifest = JSON.parse(record.manifestJson) as {
|
||||
contributes?: unknown;
|
||||
capabilities?: unknown;
|
||||
icon?: unknown;
|
||||
dependencies?: Record<string, string>;
|
||||
optionalDependencies?: Record<string, string>;
|
||||
};
|
||||
contributes = manifest?.contributes ?? null;
|
||||
capabilities = Array.isArray(manifest?.capabilities)
|
||||
? (manifest.capabilities as string[])
|
||||
: [];
|
||||
icon = typeof manifest?.icon === "string" ? manifest.icon : undefined;
|
||||
dependencies = manifest?.dependencies ?? {};
|
||||
optionalDependencies = manifest?.optionalDependencies ?? {};
|
||||
} catch {
|
||||
contributes = null;
|
||||
}
|
||||
@@ -123,6 +196,9 @@ router.get("/", authenticateJWT, async (req: Request, res: Response) => {
|
||||
state: loaded?.state ?? record.state,
|
||||
contributes,
|
||||
icon,
|
||||
dependencies,
|
||||
optionalDependencies,
|
||||
...describePluginFrontend(loaded),
|
||||
};
|
||||
|
||||
if (!canManage) return summary;
|
||||
|
||||
Reference in new issue
Block a user