mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import module from "node:module";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { getPluginsDir } from "./paths.js";
|
|
|
|
/**
|
|
* A plugin build leaves host packages (drizzle-orm, express, ssh2, ...) for
|
|
* core to supply, and Node finds them by walking up from the importing file.
|
|
* That works for bundled plugins inside the app, but a .tmxplug unpacked into
|
|
* a data dir outside it (the desktop app keeps it in AppData) finds nothing.
|
|
* Those imports fall back to core's own copy, the one bundled plugins get.
|
|
*/
|
|
|
|
let installed = false;
|
|
|
|
export function isBareSpecifier(specifier: string): boolean {
|
|
if (specifier.startsWith(".") || specifier.startsWith("/")) return false;
|
|
if (specifier.startsWith("#")) return false;
|
|
// file:, node:, data:, and a Windows drive letter
|
|
return !/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(specifier);
|
|
}
|
|
|
|
/** Whether an import from parentURL may fall back to core's packages. */
|
|
export function isUserPluginFile(
|
|
parentURL: string | undefined,
|
|
pluginsDir: string,
|
|
): boolean {
|
|
if (!parentURL?.startsWith("file:")) return false;
|
|
let file: string;
|
|
try {
|
|
file = fileURLToPath(new URL(parentURL));
|
|
} catch {
|
|
return false;
|
|
}
|
|
const relative = path.relative(path.resolve(pluginsDir), file);
|
|
return (
|
|
relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
);
|
|
}
|
|
|
|
export function installHostModuleFallback(): void {
|
|
if (installed) return;
|
|
installed = true;
|
|
// Node 22.15+. Older runtimes keep plain resolution.
|
|
if (typeof module.registerHooks !== "function") return;
|
|
module.registerHooks({
|
|
resolve(specifier, context, nextResolve) {
|
|
try {
|
|
return nextResolve(specifier, context);
|
|
} catch (error) {
|
|
if (
|
|
(error as { code?: string })?.code !== "ERR_MODULE_NOT_FOUND" ||
|
|
!isBareSpecifier(specifier) ||
|
|
!isUserPluginFile(context.parentURL, getPluginsDir())
|
|
) {
|
|
throw error;
|
|
}
|
|
return nextResolve(specifier, {
|
|
...context,
|
|
parentURL: import.meta.url,
|
|
});
|
|
}
|
|
},
|
|
});
|
|
}
|