mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 14:45:24 +00:00
82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import {
|
|
DEFAULT_BACKEND_ENTRY,
|
|
type PluginManifest,
|
|
} from "@termix/plugin-sdk/manifest";
|
|
|
|
/**
|
|
* Where user-installed plugins live. Resolved per call rather than captured at
|
|
* module scope: tests set DATA_DIR in beforeEach, and a module-scope constant
|
|
* would freeze whatever the first import saw.
|
|
*/
|
|
export function getPluginsDir(): string {
|
|
return path.join(process.env.DATA_DIR || "./db/data", "plugins");
|
|
}
|
|
|
|
/**
|
|
* A plugin's own files (ctx.files.dataDir(), downloaded binaries). Kept out of
|
|
* getPluginsDir(), where the loader would read every data folder as a user
|
|
* plugin that clashes with the bundled one of the same name.
|
|
*/
|
|
export function getPluginDataDir(pluginId: string): string {
|
|
return path.join(
|
|
process.env.DATA_DIR || "./db/data",
|
|
"plugin-data",
|
|
pluginId,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Where user .tmxplug files are unpacked. A dot directory inside the user
|
|
* plugins dir, which the loader's directory scan skips.
|
|
*/
|
|
export function getUnpackedPluginsDir(): string {
|
|
return path.join(getPluginsDir(), ".unpacked");
|
|
}
|
|
|
|
/**
|
|
* Where the plugins that ship with Termix live.
|
|
*
|
|
* Separate from getPluginsDir() because that one is user data: a bundled
|
|
* plugin is part of the install and must not be deletable or shadowable by
|
|
* whatever happens to be in the data directory.
|
|
*
|
|
* Resolved from this module's location rather than cwd, because the build
|
|
* emits to dist/backend/backend/plugins/ and the bundled plugins sit beside
|
|
* dist/backend.
|
|
*/
|
|
export function getBundledPluginsDir(): string {
|
|
const override = process.env.TERMIX_BUNDLED_PLUGINS_DIR;
|
|
if (override) return override;
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
const candidates = [
|
|
// Built server: dist/backend/backend/plugins -> dist/plugins
|
|
// Source tree: src/backend/plugins -> plugins
|
|
// Both are three levels up, which is why there is one entry, not two.
|
|
path.resolve(here, "../../../plugins"),
|
|
// Built server invoked from a nested layout: .../dist/backend/backend/plugins
|
|
path.resolve(here, "../../../../plugins"),
|
|
];
|
|
|
|
for (const candidate of candidates) {
|
|
if (fs.existsSync(candidate)) return candidate;
|
|
}
|
|
return candidates[0];
|
|
}
|
|
|
|
/** The backend entry, from the manifest's own `backend` field. */
|
|
export function getPluginBackendEntry(
|
|
pluginDir: string,
|
|
manifest?: Pick<PluginManifest, "backend">,
|
|
): string {
|
|
return path.join(pluginDir, manifest?.backend ?? DEFAULT_BACKEND_ENTRY);
|
|
}
|
|
|
|
export function getPluginManifestPath(pluginDir: string): string {
|
|
return path.join(pluginDir, "manifest.json");
|
|
}
|