feat: Implement application bootstrap and window management

- Added bootstrap functionality to initialize the Electron application.
- Created a new paths module to manage application paths and URLs.
- Introduced a shutdown service to handle graceful application shutdowns.
- Refactored error logging to use a dedicated logger module.
- Implemented process killing logic for NodeCG processes across platforms.
- Established navigation policies for internal and external URL handling in windows.
- Developed window service for creating and managing application windows.
- Added tests for application paths, application controller, navigation policies, process killer, and shutdown service.
This commit is contained in:
2026-05-24 16:14:23 +02:00
parent c168c3b84a
commit e3d3936156
17 changed files with 1067 additions and 264 deletions
@@ -0,0 +1,54 @@
import { ChildProcess, SpawnOptions } from "node:child_process";
export type PlatformProcessKillerDeps = {
platform: NodeJS.Platform;
spawnProcess: (command: string, args: string[], options: SpawnOptions) => ChildProcess;
killProcess: (pid: number, signal: NodeJS.Signals) => void;
log: (...args: unknown[]) => void;
};
export function killProcessTree(pid: number, signal: NodeJS.Signals, deps: PlatformProcessKillerDeps): boolean {
if (!Number.isSafeInteger(pid) || pid <= 0) {
deps.log(`Invalid pid for process tree termination: ${pid}`);
return false;
}
if (deps.platform === "win32") {
return killWindowsProcessTree(pid, signal, deps);
}
return killPosixProcessTree(pid, signal, deps.killProcess);
}
function killWindowsProcessTree(
pid: number,
signal: NodeJS.Signals,
deps: Pick<PlatformProcessKillerDeps, "spawnProcess" | "log">,
): boolean {
const args = ["/pid", String(pid), "/T", ...(signal === "SIGKILL" ? ["/F"] : [])];
const killer = deps.spawnProcess("taskkill", args, {
stdio: "ignore",
shell: false,
windowsHide: true,
});
killer.on("error", (error) => {
deps.log(`taskkill error for pid=${pid}`, error);
});
return true;
}
function killPosixProcessTree(pid: number, signal: NodeJS.Signals, killProcess: PlatformProcessKillerDeps["killProcess"]): boolean {
try {
killProcess(-pid, signal);
return true;
} catch {
try {
killProcess(pid, signal);
return true;
} catch {
return false;
}
}
}