76 lines
3.3 KiB
TypeScript
76 lines
3.3 KiB
TypeScript
import { existsSync, readFileSync } from "node:fs";
|
|
import { isAbsolute } from "node:path";
|
|
import { rootPath } from "./config";
|
|
|
|
export type TransSshBackendPreference = "local-backend-core-broker" | "remote-frontend-websocket";
|
|
|
|
export interface TransSshBackendConfig {
|
|
backend: TransSshBackendPreference;
|
|
raw: string;
|
|
sourceRef: string;
|
|
}
|
|
|
|
const defaultTransConfigPath = ".env/trans.ymal";
|
|
|
|
export function readTransSshBackendConfig(env: NodeJS.ProcessEnv = process.env): TransSshBackendConfig | null {
|
|
const configPath = resolveTransConfigPath(env);
|
|
if (!existsSync(configPath.absolutePath)) return null;
|
|
const parsed = asRecord(Bun.YAML.parse(readFileSync(configPath.absolutePath, "utf8")) as unknown, configPath.sourceRef);
|
|
const kind = optionalString(parsed, "kind", configPath.sourceRef);
|
|
if (kind !== null && kind !== "UniDeskTransConfig") {
|
|
throw new Error(`${configPath.sourceRef}.kind must be UniDeskTransConfig`);
|
|
}
|
|
const ssh = optionalRecord(parsed, "ssh", configPath.sourceRef);
|
|
if (ssh === null) return null;
|
|
const raw = optionalString(ssh, "backend", `${configPath.sourceRef}.ssh`);
|
|
if (raw === null) return null;
|
|
const backend = normalizeTransSshBackend(raw, `${configPath.sourceRef}.ssh.backend`);
|
|
if (backend === "auto") return null;
|
|
return {
|
|
backend,
|
|
raw,
|
|
sourceRef: `${configPath.sourceRef}#ssh.backend`,
|
|
};
|
|
}
|
|
|
|
function resolveTransConfigPath(env: NodeJS.ProcessEnv): { absolutePath: string; sourceRef: string } {
|
|
const configured = (env.UNIDESK_TRANS_CONFIG_PATH ?? env.UNIDESK_TRANS_YAML_PATH)?.trim();
|
|
if (configured !== undefined && configured.length > 0) {
|
|
return {
|
|
absolutePath: isAbsolute(configured) ? configured : rootPath(configured),
|
|
sourceRef: configured,
|
|
};
|
|
}
|
|
return {
|
|
absolutePath: rootPath(defaultTransConfigPath),
|
|
sourceRef: defaultTransConfigPath,
|
|
};
|
|
}
|
|
|
|
function normalizeTransSshBackend(raw: string, path: string): TransSshBackendPreference | "auto" {
|
|
const normalized = raw.trim();
|
|
if (normalized === "backend-core" || normalized === "local-backend-core-broker") return "local-backend-core-broker";
|
|
if (normalized === "frontend-websocket" || normalized === "remote-frontend-websocket") return "remote-frontend-websocket";
|
|
if (normalized === "auto") return "auto";
|
|
throw new Error(`${path} must be one of: backend-core, local-backend-core-broker, frontend-websocket, remote-frontend-websocket, auto`);
|
|
}
|
|
|
|
function asRecord(value: unknown, path: string): Record<string, unknown> {
|
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be an object`);
|
|
return value as Record<string, unknown>;
|
|
}
|
|
|
|
function optionalRecord(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown> | null {
|
|
const value = obj[key];
|
|
if (value === undefined) return null;
|
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path}.${key} must be an object`);
|
|
return value as Record<string, unknown>;
|
|
}
|
|
|
|
function optionalString(obj: Record<string, unknown>, key: string, path: string): string | null {
|
|
const value = obj[key];
|
|
if (value === undefined) return null;
|
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string`);
|
|
return value;
|
|
}
|