Makelore 2.0 initial clean snapshot
This commit is contained in:
169
electron/preload/index.ts
Normal file
169
electron/preload/index.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Preload Script
|
||||
* Exposes safe APIs to the renderer process via contextBridge
|
||||
*/
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV === 'development' || Boolean(process.env.VITE_DEV_SERVER_URL);
|
||||
const imageWorkspaceLocalDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL)
|
||||
&& process.env.NIANCODE_IMAGE_WORKSPACE_MODE?.trim().toLowerCase() === 'local';
|
||||
|
||||
const validInvokeChannels = [
|
||||
'hostapi:fetch',
|
||||
'hostapi:token',
|
||||
'hostapi:base-url',
|
||||
'opencode:status',
|
||||
'opencode:start',
|
||||
'opencode:stop',
|
||||
'opencode:restart',
|
||||
'opencode:health',
|
||||
'shell:openExternal',
|
||||
'shell:showItemInFolder',
|
||||
'shell:openPath',
|
||||
'dialog:open',
|
||||
'dialog:save',
|
||||
'dialog:message',
|
||||
'transcript:save',
|
||||
'app:version',
|
||||
'app:name',
|
||||
'app:getPath',
|
||||
'app:platform',
|
||||
'app:quit',
|
||||
'app:relaunch',
|
||||
'app:request',
|
||||
'window:minimize',
|
||||
'window:maximize',
|
||||
'window:close',
|
||||
'window:isMaximized',
|
||||
'settings:get',
|
||||
'settings:set',
|
||||
'settings:setMany',
|
||||
'settings:getAll',
|
||||
'settings:reset',
|
||||
'provider:list',
|
||||
'provider:get',
|
||||
'provider:save',
|
||||
'provider:delete',
|
||||
'provider:setApiKey',
|
||||
'provider:updateWithKey',
|
||||
'provider:deleteApiKey',
|
||||
'provider:hasApiKey',
|
||||
'provider:getApiKey',
|
||||
'provider:setDefault',
|
||||
'provider:getDefault',
|
||||
'provider:validateKey',
|
||||
'update:status',
|
||||
'update:version',
|
||||
'update:check',
|
||||
'update:download',
|
||||
'update:install',
|
||||
'update:setChannel',
|
||||
'update:setAutoDownload',
|
||||
'update:cancelAutoInstall',
|
||||
];
|
||||
|
||||
const validEventChannels = [
|
||||
'navigate',
|
||||
'opencode:status',
|
||||
'opencode:stderr',
|
||||
'update:status-changed',
|
||||
'update:checking',
|
||||
'update:available',
|
||||
'update:not-available',
|
||||
'update:progress',
|
||||
'update:downloaded',
|
||||
'update:error',
|
||||
'update:auto-install-countdown',
|
||||
'oauth:code',
|
||||
'oauth:success',
|
||||
'oauth:error',
|
||||
];
|
||||
|
||||
/**
|
||||
* IPC renderer methods exposed to the renderer process
|
||||
*/
|
||||
const electronAPI = {
|
||||
/**
|
||||
* IPC invoke (request-response pattern)
|
||||
*/
|
||||
ipcRenderer: {
|
||||
invoke: (channel: string, ...args: unknown[]) => {
|
||||
if (validInvokeChannels.includes(channel)) {
|
||||
return ipcRenderer.invoke(channel, ...args);
|
||||
}
|
||||
|
||||
throw new Error(`Invalid IPC channel: ${channel}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen for events from main process
|
||||
*/
|
||||
on: (channel: string, callback: (...args: unknown[]) => void) => {
|
||||
if (validEventChannels.includes(channel) || channel.startsWith('ext:')) {
|
||||
const subscription = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => {
|
||||
callback(...args);
|
||||
};
|
||||
ipcRenderer.on(channel, subscription);
|
||||
|
||||
// Return unsubscribe function
|
||||
return () => {
|
||||
ipcRenderer.removeListener(channel, subscription);
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Invalid IPC channel: ${channel}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen for a single event from main process
|
||||
*/
|
||||
once: (channel: string, callback: (...args: unknown[]) => void) => {
|
||||
if (validEventChannels.includes(channel) || channel.startsWith('ext:')) {
|
||||
ipcRenderer.once(channel, (_event, ...args) => callback(...args));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(`Invalid IPC channel: ${channel}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all listeners for a channel
|
||||
*/
|
||||
off: (channel: string, callback?: (...args: unknown[]) => void) => {
|
||||
if (callback) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
ipcRenderer.removeListener(channel, callback as any);
|
||||
} else {
|
||||
ipcRenderer.removeAllListeners(channel);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Open external URL in default browser
|
||||
*/
|
||||
openExternal: (url: string) => {
|
||||
return ipcRenderer.invoke('shell:openExternal', url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get current platform
|
||||
*/
|
||||
platform: process.platform,
|
||||
|
||||
/**
|
||||
* Check if running in development
|
||||
*/
|
||||
isDev: isDevelopment,
|
||||
|
||||
/**
|
||||
* Narrow anonymous-route exception for the explicit unpackaged image workspace adapter.
|
||||
*/
|
||||
imageWorkspaceLocalDevelopment,
|
||||
};
|
||||
|
||||
// Expose the API to the renderer process
|
||||
contextBridge.exposeInMainWorld('electron', electronAPI);
|
||||
|
||||
// Type declarations for the renderer process
|
||||
export type ElectronAPI = typeof electronAPI;
|
||||
Reference in New Issue
Block a user