feat(FN-1072): add Electron desktop renderer integration

- Add Electron main-process IPC handlers and preload bridges for API proxying, window controls, update install, and platform lookup
- Introduce a desktop renderer entrypoint with DesktopWrapper and a custom frameless TitleBar component
- Add Electron-aware renderer utilities including API transport selection and hooks for runtime detection, auto-update events, and deep links
- Update dashboard header behavior for Electron mode and expand desktop tests across preload, transport, hooks, and title bar flows
- Document the desktop renderer architecture and update desktop package config/dependencies
This commit is contained in:
gsxdsm
2026-04-08 00:16:25 -07:00
parent 8c5b5e128c
commit a4a99f31b0
27 changed files with 1325 additions and 28 deletions

View File

@@ -1,4 +1,5 @@
import { contextBridge, ipcRenderer } from "electron";
import type { ElectronAPI, ElectronApiResponsePayload, WindowControlAction } from "./renderer/types";
export interface FusionDesktopAPI {
getAppVersion(): Promise<string>;
@@ -6,7 +7,7 @@ export interface FusionDesktopAPI {
onDashboardReady(callback: () => void): () => void;
}
const api: FusionDesktopAPI = {
const fusionDesktop: FusionDesktopAPI = {
getAppVersion(): Promise<string> {
return ipcRenderer.invoke("app:get-version");
},
@@ -22,4 +23,44 @@ const api: FusionDesktopAPI = {
},
};
contextBridge.exposeInMainWorld("fusionDesktop", api);
const electronAPI: ElectronAPI = {
invoke(channel: string, payload?: unknown): Promise<unknown> {
return ipcRenderer.invoke(channel, payload);
},
apiRequest(method: string, path: string, body?: unknown): Promise<ElectronApiResponsePayload> {
return ipcRenderer.invoke("api-request", { method, path, body });
},
getServerPort(): Promise<number> {
return ipcRenderer.invoke("server:get-port");
},
windowControl(action: WindowControlAction): Promise<boolean | void> {
return ipcRenderer.invoke("window:control", action);
},
onUpdateAvailable(callback: (info: Record<string, unknown>) => void): () => void {
const listener = (_event: unknown, info: Record<string, unknown>) => {
callback(info);
};
ipcRenderer.on("update:available", listener);
return () => {
ipcRenderer.removeListener("update:available", listener);
};
},
installUpdate(): Promise<void> {
return ipcRenderer.invoke("update:install");
},
onDeepLink(callback: (url: string) => void): () => void {
const listener = (_event: unknown, url: string) => {
callback(url);
};
ipcRenderer.on("deep-link", listener);
return () => {
ipcRenderer.removeListener("deep-link", listener);
};
},
getPlatform() {
return ipcRenderer.invoke("system:get-platform");
},
};
contextBridge.exposeInMainWorld("fusionDesktop", fusionDesktop);
contextBridge.exposeInMainWorld("electronAPI", electronAPI);