Files
helder/src/preload/index.ts
Jonathan van Rij 43131915c0
Some checks failed
CI / check (push) Has been cancelled
faster loading
2026-06-23 08:52:05 +02:00

108 lines
4.2 KiB
TypeScript

import { contextBridge, clipboard, ipcRenderer } from 'electron'
/**
* The single bridge between renderer and main. The renderer NEVER touches the
* filesystem, git or the OS clipboard directly — everything goes through here.
* (PTYs land here next, for the terminals.)
*/
const api = {
platform: process.platform,
clipboard: {
writeText: (text: string) => clipboard.writeText(text),
readText: (): string => clipboard.readText(),
},
project: {
current: () => ipcRenderer.invoke('project:current'),
open: () => ipcRenderer.invoke('project:open'),
openPath: (path: string) => ipcRenderer.invoke('project:openPath', path),
recent: (): Promise<{ path: string; name: string }[]> => ipcRenderer.invoke('projects:recent'),
},
fs: {
tree: () => ipcRenderer.invoke('fs:tree'),
readDir: (path: string) => ipcRenderer.invoke('fs:readDir', path),
files: () => ipcRenderer.invoke('fs:files'),
read: (path: string) => ipcRenderer.invoke('fs:read', path),
write: (path: string, content: string): Promise<void> => ipcRenderer.invoke('fs:write', path, content),
delete: (path: string): Promise<void> => ipcRenderer.invoke('fs:delete', path),
create: (path: string): Promise<void> => ipcRenderer.invoke('fs:create', path),
mkdir: (path: string): Promise<void> => ipcRenderer.invoke('fs:mkdir', path),
},
shell: {
reveal: (path: string): void => { ipcRenderer.invoke('shell:reveal', path) },
},
git: {
load: () => ipcRenderer.invoke('git:load'),
stage: (paths: string[]) => ipcRenderer.invoke('git:stage', paths),
unstage: (paths: string[]) => ipcRenderer.invoke('git:unstage', paths),
commit: (message: string) => ipcRenderer.invoke('git:commit', message),
push: (): Promise<{ ok: boolean; message: string }> => ipcRenderer.invoke('git:push'),
discard: (paths: string[]) => ipcRenderer.invoke('git:discard', paths),
},
pty: {
available: (): Promise<boolean> => ipcRenderer.invoke('pty:available'),
create: (kind: 'agent' | 'shell', cols: number, rows: number): Promise<number> =>
ipcRenderer.invoke('pty:create', kind, cols, rows),
write: (id: number, data: string): void => ipcRenderer.send('pty:write', id, data),
resize: (id: number, cols: number, rows: number): void => ipcRenderer.send('pty:resize', id, cols, rows),
kill: (id: number): void => ipcRenderer.send('pty:kill', id),
onData: (cb: (id: number, data: string) => void): (() => void) => {
const h = (_e: unknown, p: { id: number; data: string }): void => cb(p.id, p.data)
ipcRenderer.on('pty:data', h)
return () => ipcRenderer.removeListener('pty:data', h)
},
onExit: (cb: (id: number) => void): (() => void) => {
const h = (_e: unknown, p: { id: number }): void => cb(p.id)
ipcRenderer.on('pty:exit', h)
return () => ipcRenderer.removeListener('pty:exit', h)
},
},
config: {
get: () => ipcRenderer.invoke('config:get'),
theme: (): Promise<string> => ipcRenderer.invoke('config:theme'),
},
recent: {
get: (): Promise<string[]> => ipcRenderer.invoke('recent:get'),
set: (list: string[]): Promise<void> => ipcRenderer.invoke('recent:set', list),
},
search: {
content: (query: string) => ipcRenderer.invoke('search:content', query),
files: (): Promise<string[]> => ipcRenderer.invoke('search:files'),
},
dialog: {
unsavedClose: (path: string): Promise<'save' | 'discard' | 'cancel'> =>
ipcRenderer.invoke('dialog:unsavedClose', path),
},
/** Subscribe to "the project changed on disk" pings. Returns an unsubscribe. */
onProjectChanged: (cb: () => void): (() => void) => {
const handler = (): void => cb()
ipcRenderer.on('project:changed', handler)
return () => ipcRenderer.removeListener('project:changed', handler)
},
/** Subscribe to .helder config/theme edits. Returns an unsubscribe. */
onConfigChanged: (cb: () => void): (() => void) => {
const handler = (): void => cb()
ipcRenderer.on('config:changed', handler)
return () => ipcRenderer.removeListener('config:changed', handler)
},
}
if (process.contextIsolated) {
contextBridge.exposeInMainWorld('helder', api)
} else {
;(globalThis as unknown as { helder: typeof api }).helder = api
}
export type HelderApi = typeof api