Chat2api / electron-stub.js
Jsns82882's picture
Create electron-stub.js
f3fc98a verified
Raw
History Blame Contribute Delete
3.62 kB
// Minimal Electron stub for headless Node.js deployment
// Stubs out all Electron APIs so the Koa proxy boots without a display.
const EventEmitter = require('events');
const path = require('path');
const noop = () => {};
const noopAsync = () => Promise.resolve();
const dataDir = process.env.CHAT2API_DATA_DIR || path.join(require('os').homedir(), '.chat2api');
const app = Object.assign(new EventEmitter(), {
getPath: (name) => {
const map = { userData: dataDir, appData: dataDir, temp: '/tmp', home: require('os').homedir(), logs: dataDir + '/logs' };
return map[name] || dataDir;
},
getVersion: () => '1.0.0',
getName: () => 'Chat2API',
quit: noop,
exit: noop,
isPackaged: false,
isReady: () => true,
whenReady: () => Promise.resolve(),
requestSingleInstanceLock: () => true,
setAppUserModelId: noop,
setLoginItemSettings: noop,
dock: { setIcon: noop, hide: noop },
});
// Fire 'ready' asynchronously so listeners registered after require() still fire
setImmediate(() => app.emit('ready', {}, {}));
const ipcMain = Object.assign(new EventEmitter(), {
handle: noop,
handleOnce: noop,
removeHandler: noop,
});
class BrowserWindow extends EventEmitter {
constructor() { super(); this.webContents = { send: noop, on: noop, once: noop, session: { webRequest: { onBeforeSendHeaders: noop, onHeadersReceived: noop } } }; }
loadURL() { return Promise.resolve(); }
loadFile() { return Promise.resolve(); }
show() {}
hide() {}
close() {}
destroy() {}
isDestroyed() { return false; }
setIcon() {}
setTitle() {}
setMenu() {}
center() {}
focus() {}
static getAllWindows() { return []; }
static fromWebContents() { return null; }
}
class Tray extends EventEmitter {
constructor() { super(); }
setToolTip() {}
setContextMenu() {}
setImage() {}
destroy() {}
}
const Menu = { buildFromTemplate: () => ({}), setApplicationMenu: noop, getApplicationMenu: () => null };
class MenuItem {}
const nativeImage = { createFromPath: () => ({ isEmpty: () => false }), createEmpty: () => ({ isEmpty: () => true }), createFromDataURL: () => ({}) };
const screen = { getPrimaryDisplay: () => ({ workAreaSize: { width: 1920, height: 1080 }, scaleFactor: 1 }), on: noop };
const globalShortcut = { register: noop, unregisterAll: noop, isRegistered: () => false };
const powerMonitor = new EventEmitter();
const dialog = { showMessageBox: noopAsync, showMessageBoxSync: () => 0, showErrorBox: noop, showOpenDialog: noopAsync };
const shell = { openExternal: noopAsync, openPath: noopAsync };
const clipboard = { writeText: noop, readText: () => '' };
const autoUpdater = Object.assign(new EventEmitter(), { setFeedURL: noop, checkForUpdates: noop, quitAndInstall: noop });
const net = { request: () => { const e = new EventEmitter(); e.end = noop; return e; } };
const session = { defaultSession: { webRequest: { onBeforeSendHeaders: noop } } };
const protocol = { registerFileProtocol: noop, registerHttpProtocol: noop };
const contextBridge = { exposeInMainWorld: noop };
const ipcRenderer = Object.assign(new EventEmitter(), { invoke: noopAsync, send: noop, sendSync: () => null, on: (e,f) => ipcRenderer, once: (e,f) => ipcRenderer });
const crashReporter = { start: noop };
const desktopCapturer = { getSources: noopAsync };
const powerSaveBlocker = { start: () => 1, stop: noop };
module.exports = {
app, ipcMain, ipcRenderer, BrowserWindow, Tray, Menu, MenuItem,
nativeImage, screen, globalShortcut, powerMonitor, dialog, shell,
clipboard, autoUpdater, net, session, protocol, contextBridge,
crashReporter, desktopCapturer, powerSaveBlocker,
};