feat: list plugin engine ranges for the mobile app

This commit is contained in:
LukeGus committed 2026-10-25 00:59:04 -05:00
1 parent 1be507b13c
commit 90f5aebafb
4 files changed
+48 -1

No files matched your search

+12 -1
View File
@@ -244,7 +244,9 @@ export async function listPreLoginPlugins(): Promise<
* `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.
* frontends in the same order the server does. `engine` holds the
* manifest's `api` and `termix` ranges, so other clients (the mobile
* app) can tell whether they understand the plugin.
*
* On a desktop linked to a server, `runsOnServer` marks plugins that
* only run on that server and stay off here on purpose, and, for
@@ -303,6 +305,7 @@ router.get("/", authenticateJWT, async (req: Request, res: Response) => {
let features: string[] = [];
let docs: string | undefined;
let env: PluginEnvVar[] = [];
const engine: { api?: string; termix?: string } = {};
let desktopMode: unknown = loaded
? resolvePluginDesktopMode(loaded.manifest)
: undefined;
@@ -322,7 +325,14 @@ router.get("/", authenticateJWT, async (req: Request, res: Response) => {
optionalDependencies?: Record<string, string>;
desktop?: unknown;
runtime?: unknown;
engine?: { api?: unknown; termix?: unknown };
};
if (typeof manifest?.engine?.api === "string") {
engine.api = manifest.engine.api;
}
if (typeof manifest?.engine?.termix === "string") {
engine.termix = manifest.engine.termix;
}
desktopMode = loaded
? resolvePluginDesktopMode(loaded.manifest)
: (manifest?.desktop ??
@@ -365,6 +375,7 @@ router.get("/", authenticateJWT, async (req: Request, res: Response) => {
? "safe-mode"
: (loaded?.state ?? record.state),
runsOnServer: linked && desktopMode === "server",
engine,
contributes,
icon,
dependencies,
@@ -488,6 +488,35 @@ describe("plugins route", () => {
}
});
it("lists a plugin's engine ranges to any user", async () => {
state.plugins.set(
"sample-plugin",
makePlugin({
manifestJson: JSON.stringify({
engine: { api: "^1.13", termix: ">=26.10.6", extra: 1 },
}),
}),
);
state.plugins.set(
"bad-engine",
makePlugin({
id: "bad-engine",
manifestJson: JSON.stringify({ engine: { api: 2 } }),
}),
);
const res = await fetch(`${baseUrl}/plugins`, {
headers: { "x-test-user-id": "regular-user" },
});
const body = (await res.json()) as Array<{ id: string; engine: unknown }>;
expect(body.find((p) => p.id === "sample-plugin")?.engine).toEqual({
api: "^1.13",
termix: ">=26.10.6",
});
expect(body.find((p) => p.id === "bad-engine")?.engine).toEqual({});
});
it("reports an enabled plugin that safe mode keeps off", async () => {
state.plugins.set("sample-plugin", makePlugin({ state: "enabled" }));
@@ -643,6 +672,7 @@ describe("plugins route", () => {
enabled: true,
state: "enabled",
runsOnServer: false,
engine: {},
contributes: null,
dependencies: {},
optionalDependencies: {},