Files
pikasTech-unidesk/scripts/src/trans-config.ts
T
2026-06-29 14:56:01 +00:00

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;
}