// Communication adapter that works in both Electron and Web modes import { io, Socket } from "socket.io-client"; type EventCallback = (event: any, ...args: any[]) => void; export interface IPCAdapter { send(channel: string, ...args: any[]): void; invoke(channel: string, ...args: any[]): Promise; on(channel: string, callback: EventCallback): void; } class ElectronAdapter implements IPCAdapter { private ipcRenderer: any; constructor() { this.ipcRenderer = require("electron").ipcRenderer; } send(channel: string, ...args: any[]): void { this.ipcRenderer.send(channel, ...args); } invoke(channel: string, ...args: any[]): Promise { return this.ipcRenderer.invoke(channel, ...args); } on(channel: string, callback: EventCallback): void { this.ipcRenderer.on(channel, callback); } } class WebAdapter implements IPCAdapter { private socket: Socket; private responseHandlers = new Map void; reject: (reason?: any) => void }>(); private requestCounter = 0; constructor() { this.socket = io(); // Handle invoke responses from server this.socket.on("invoke-response", (requestId: number, error: any, result: any) => { const handler = this.responseHandlers.get(requestId); if (handler) { this.responseHandlers.delete(requestId); if (error) { handler.reject(error); } else { handler.resolve(result); } } }); } send(channel: string, ...args: any[]): void { this.socket.emit(channel, ...args); } invoke(channel: string, ...args: any[]): Promise { return new Promise((resolve, reject) => { const requestId = this.requestCounter++; this.responseHandlers.set(requestId, { resolve, reject }); // Set timeout for invoke setTimeout(() => { if (this.responseHandlers.has(requestId)) { this.responseHandlers.delete(requestId); reject(new Error(`Invoke timeout: ${channel}`)); } }, 10000); this.socket.emit("invoke", requestId, channel, ...args); }); } on(channel: string, callback: EventCallback): void { this.socket.on(channel, (...args: any[]) => { // Mimic Electron's event object structure const event = {}; callback(event, ...args); }); } } // Detect environment and create appropriate adapter function createAdapter(): IPCAdapter { // Check if running in Electron const isElectron = typeof window !== "undefined" && typeof (window as any).process !== "undefined" && (window as any).process.type === "renderer"; if (isElectron) { return new ElectronAdapter(); } else { return new WebAdapter(); } } export const ipcAdapter = createAdapter();