mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05:24 +00:00
v26.10.5 (#1710)
* feat: add an auto or fixed columns picker to card grids * feat: add safe mode that only runs layout and theme plugins * docs: add simple layout to plugin table * fix: ask for local network access in the macOS app * feat: allow plugin registries on listed private hosts (#1705) * chore: add private registry hosts to the changelog * feat: use the proxy for plugin registry downloads * fix: allow changing connection origin on shared hosts * chore: update translations and plugin pins * chore: lint, format, and bump version to 26.10.5 --------- Co-authored-by: Lukas <80832688+0skater0@users.noreply.github.com>
This commit is contained in:
1 parent
7b7b17e31f
commit
96b8520fb4
96 files changed
+1885
-474
No files matched your search
@@ -18,6 +18,7 @@ import path from "node:path";
|
||||
import semver from "semver";
|
||||
import { pluginLogger } from "../utils/logger.js";
|
||||
import { isDefaultLookPlugin } from "./bundled-index.js";
|
||||
import { mayRunInSafeMode } from "./safe-mode.js";
|
||||
import {
|
||||
activatePlugin,
|
||||
deactivatePlugin,
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
registerLoadedPlugins,
|
||||
unloadPlugin,
|
||||
} from "./index.js";
|
||||
import { missingShippedPluginIds } from "./boot-state.js";
|
||||
import type { LoadedPlugin, PluginLoader } from "./loader.js";
|
||||
import {
|
||||
getBundledPluginsDir,
|
||||
@@ -763,6 +765,13 @@ export async function setPluginStateUnlocked(
|
||||
if (!loader.get(pluginId)) {
|
||||
throw new PluginManageError("Plugin not found", 404, "NOT_FOUND");
|
||||
}
|
||||
if (enabled && !mayRunInSafeMode(pluginId, loader.list())) {
|
||||
throw new PluginManageError(
|
||||
"Safe mode is on, so only layout and theme plugins can start",
|
||||
409,
|
||||
"SAFE_MODE",
|
||||
);
|
||||
}
|
||||
const plan = await planStateChange(pluginId, enabled);
|
||||
|
||||
if (enabled) {
|
||||
@@ -959,7 +968,11 @@ export function installPlugin(
|
||||
return serialized(async () => {
|
||||
const { createCurrentPluginRepository } = await repos();
|
||||
const repository = createCurrentPluginRepository();
|
||||
if (await repository.findById(pluginId)) {
|
||||
// A record with no code is a plugin an older image shipped: install fills it in.
|
||||
if (
|
||||
(await repository.findById(pluginId)) &&
|
||||
getPluginRuntime().loader.get(pluginId)
|
||||
) {
|
||||
throw new PluginManageError(
|
||||
"Plugin is already installed",
|
||||
409,
|
||||
@@ -1018,6 +1031,63 @@ export function installPlugin(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at boot before plugins start. A plugin the database has on but the
|
||||
* image no longer ships (an update to a smaller image tag) is fetched from the
|
||||
* official registry, so nothing an install used goes missing. One that cannot
|
||||
* be fetched stays as it was and is tried again on the next start.
|
||||
*/
|
||||
export function restoreMissingPlugins(): Promise<LoadedPlugin[]> {
|
||||
return serialized(async () => {
|
||||
const { createCurrentPluginRepository } = await repos();
|
||||
const repository = createCurrentPluginRepository();
|
||||
const { loader } = getPluginRuntime();
|
||||
const ids = missingShippedPluginIds(
|
||||
await repository.listAll(),
|
||||
new Set(loader.list().map((plugin) => plugin.id)),
|
||||
await readUninstalled(),
|
||||
);
|
||||
const restored: LoadedPlugin[] = [];
|
||||
for (const id of ids) {
|
||||
try {
|
||||
const record = await repository.findById(id);
|
||||
const { source, release } = await requireRelease(
|
||||
id,
|
||||
record?.pinnedVersion ?? undefined,
|
||||
channelOf(record),
|
||||
OFFICIAL_REGISTRY_ID,
|
||||
);
|
||||
const plugin = await swapIn(id, { release, source });
|
||||
await repository.update(id, {
|
||||
registryId: source.id,
|
||||
tier: tierFor(plugin, source),
|
||||
});
|
||||
await grantDeclared(plugin, null);
|
||||
restored.push(plugin);
|
||||
pluginLogger.info(
|
||||
`Restored ${id}@${release.version} from the registry`,
|
||||
{
|
||||
operation: "plugin_restore_missing",
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
pluginLogger.warn(`Could not restore ${id}: ${message}`, {
|
||||
operation: "plugin_restore_missing",
|
||||
});
|
||||
// The registry is down or offline, so the rest would fail the same way.
|
||||
if (
|
||||
error instanceof PluginManageError &&
|
||||
error.code === "REGISTRY_UNREACHABLE"
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return restored;
|
||||
});
|
||||
}
|
||||
|
||||
export function updatePlugin(
|
||||
pluginId: string,
|
||||
options: InstallOptions,
|
||||
|
||||
Reference in new issue
Block a user