Files
Termix/plugins/web-endpoint/backend/index.mjs
T

76 lines
3.3 KiB
JavaScript

/**
* Web Endpoint - first-party, in-process plugin.
*
* This plugin runs on the main thread because its one route is a real
* transport consumer: it polls the tunnel manager's live maps
* (activeTunnelRuntimes, connectionStatus, tunnelConnecting), needs the
* plaintext host credentials ctx.hosts deliberately withholds (PluginHostView
* is a 13-field allowlist excluding password, key and passphrase), and hands a
* live ssh2.Client to forwardOut to probe the target. None of that survives
* the structured-clone postMessage boundary a worker plugin talks over.
*
* Unlike every other dispatcher-backed plugin, this one does not register with
* a dispatcher in database.ts: its route is served by the tunnel service on
* port 30003, so the dispatcher lives at
* src/backend/hosts/tunnel/web-endpoint-dispatch.ts instead. Both that service
* and the plugin runtime load into the same backend process, so the
* dispatcher's module-level slot is shared between them. Keeping the URL
* (/ssh/tunnel/web-endpoint/open) byte-identical is also why no nginx change
* was needed -- the generic /ssh/tunnel/ location block already covers it.
*
* Three pieces stay in core rather than moving here:
*
* - The tunnel manager itself (src/backend/hosts/tunnel/manager.ts). It
* serves the whole server-tunnels feature, and the reserved "web:" name
* prefix that exempts these tunnels from the retry machinery is part of
* its own disconnect path.
*
* - host-web-endpoints.ts (the webUiConfig normalizer). Despite its name it
* has no router: it is imported by host.ts, host-bulk-routes.ts and
* host-normalizers.ts to sanitize the column on every host save and list.
* Disabling this plugin must not stop that validation, and core cannot
* import plugin code in any case.
*
* - The Electron half (electron/web-endpoint-window.cjs and the two
* ipcMain handlers in main.cjs). BrowserWindow and session are
* main-process-only, the renderer is what invokes those channels, and the
* main process loads no plugin code at all today.
*
* The enableWebUi/webUiConfig columns stay on core's ssh_data table, declared
* here through contributes.hostCapability -- this plugin system has no
* owned-table migration mechanism of its own.
*/
import path from "node:path";
import { fileURLToPath } from "node:url";
/**
* Loads a module by its path relative to this file's own directory.
*
* The plugin ships beside dist/backend, so in a built server the compiled .js
* for routes.js sits right next to this .mjs. Under vitest/dev nothing imports
* this plugin directly (the loader loads in-process plugins with a plain
* dynamic import, no tsx loader involved), so the only layout that needs to
* resolve here is the built one.
*/
async function loadRelative(relativePath) {
const here = path.dirname(fileURLToPath(import.meta.url));
const target = path.join(here, `${relativePath}.js`);
return import(new URL(`file://${target.replace(/\\/g, "/")}`).href);
}
let routesModule = null;
export async function activate(ctx) {
routesModule = await loadRelative("routes");
routesModule.startWebEndpointService();
ctx.log.info("Web Endpoint router registered at /ssh/tunnel/web-endpoint");
}
export async function deactivate() {
if (routesModule) {
routesModule.stopWebEndpointService();
routesModule = null;
}
}