preload.ts
1 import { contextBridge, ipcRenderer } from 'electron'; 2 import type { 3 ChangedFile, 4 GenerateReviewRequest, 5 Preferences, 6 PrSearchResult, 7 PrStatus, 8 ReviewGuide, 9 ReviewHistoryEntry, 10 SendSlideChatRequest, 11 StartReviewResult, 12 SubmitReviewRequest, 13 FreshnessResult, 14 UpdateInfo, 15 } from '../lib/types'; 16 17 contextBridge.exposeInMainWorld('electronAPI', { 18 startReview: (req: GenerateReviewRequest): Promise<StartReviewResult> => ipcRenderer.invoke('start-review', req), 19 cancelReview: (reviewId: string): Promise<void> => ipcRenderer.invoke('cancel-review', reviewId), 20 getConfig: (): Promise<{ githubToken: string | null }> => ipcRenderer.invoke('get-config'), 21 startOAuth: (): Promise<void> => ipcRenderer.invoke('start-oauth'), 22 getAuthState: (): Promise<{ authenticated: boolean; login: string | null }> => ipcRenderer.invoke('get-auth-state'), 23 signOut: (): Promise<void> => ipcRenderer.invoke('sign-out'), 24 savePat: (token: string): Promise<string> => ipcRenderer.invoke('save-pat', token), 25 listReviews: (): Promise<ReviewHistoryEntry[]> => ipcRenderer.invoke('list-reviews'), 26 loadReview: (id: string): Promise<ReviewGuide> => ipcRenderer.invoke('load-review', id), 27 deleteReview: (id: string): Promise<void> => ipcRenderer.invoke('delete-review', id), 28 deleteAllReviews: (): Promise<void> => ipcRenderer.invoke('delete-all-reviews'), 29 onReviewProgress: (callback: (reviewId: string, chunk: string, isThinking: boolean) => void): void => { 30 ipcRenderer.on( 31 'review-progress', 32 (_event, { reviewId, chunk, isThinking }: { reviewId: string; chunk: string; isThinking: boolean }) => 33 callback(reviewId, chunk, isThinking) 34 ); 35 }, 36 offReviewProgress: (): void => { 37 ipcRenderer.removeAllListeners('review-progress'); 38 }, 39 onReviewToolUse: (callback: (reviewId: string, toolName: string) => void): void => { 40 ipcRenderer.on('review-tool-use', (_event, { reviewId, toolName }: { reviewId: string; toolName: string }) => 41 callback(reviewId, toolName) 42 ); 43 }, 44 offReviewToolUse: (): void => { 45 ipcRenderer.removeAllListeners('review-tool-use'); 46 }, 47 onReviewPhase: (callback: (reviewId: string, phase: string) => void): void => { 48 ipcRenderer.on('review-phase', (_event, { reviewId, phase }: { reviewId: string; phase: string }) => 49 callback(reviewId, phase) 50 ); 51 }, 52 offReviewPhase: (): void => { 53 ipcRenderer.removeAllListeners('review-phase'); 54 }, 55 onReviewCompleted: (callback: (reviewId: string) => void): void => { 56 ipcRenderer.on('review-completed', (_event, { reviewId }: { reviewId: string }) => callback(reviewId)); 57 }, 58 offReviewCompleted: (): void => { 59 ipcRenderer.removeAllListeners('review-completed'); 60 }, 61 onReviewFailed: (callback: (reviewId: string, error: string) => void): void => { 62 ipcRenderer.on('review-failed', (_event, { reviewId, error }: { reviewId: string; error: string }) => 63 callback(reviewId, error) 64 ); 65 }, 66 offReviewFailed: (): void => { 67 ipcRenderer.removeAllListeners('review-failed'); 68 }, 69 onReviewStats: (callback: (reviewId: string, inputBytes: number) => void): void => { 70 ipcRenderer.on('review-stats', (_event, { reviewId, inputBytes }: { reviewId: string; inputBytes: number }) => 71 callback(reviewId, inputBytes) 72 ); 73 }, 74 offReviewStats: (): void => { 75 ipcRenderer.removeAllListeners('review-stats'); 76 }, 77 onReviewNavigate: (callback: (reviewId: string) => void): void => { 78 ipcRenderer.on('review-navigate', (_event, { reviewId }: { reviewId: string }) => callback(reviewId)); 79 }, 80 offReviewNavigate: (): void => { 81 ipcRenderer.removeAllListeners('review-navigate'); 82 }, 83 sendSlideChat: (req: SendSlideChatRequest): Promise<string> => ipcRenderer.invoke('send-slide-chat', req), 84 onChatProgress: (callback: (chunk: string) => void): void => { 85 ipcRenderer.on('chat-progress', (_event, { chunk }: { chunk: string }) => callback(chunk)); 86 }, 87 offChatProgress: (): void => { 88 ipcRenderer.removeAllListeners('chat-progress'); 89 }, 90 onChatToolUse: (callback: (toolName: string) => void): void => { 91 ipcRenderer.on('chat-tool-use', (_event, { toolName }: { toolName: string }) => callback(toolName)); 92 }, 93 offChatToolUse: (): void => { 94 ipcRenderer.removeAllListeners('chat-tool-use'); 95 }, 96 submitReview: (req: SubmitReviewRequest): Promise<{ reviewUrl: string; droppedCommentCount: number }> => 97 ipcRenderer.invoke('submit-review', req), 98 checkPrFreshness: (prUrl: string, headSha: string | undefined): Promise<FreshnessResult> => 99 ipcRenderer.invoke('check-pr-freshness', prUrl, headSha), 100 loadPreferences: (): Promise<Preferences> => ipcRenderer.invoke('load-preferences'), 101 savePreferences: (prefs: Preferences): Promise<void> => ipcRenderer.invoke('save-preferences', prefs), 102 searchPullRequests: (): Promise<PrSearchResult[]> => ipcRenderer.invoke('search-pull-requests'), 103 reRenderHunks: (review: ReviewGuide): Promise<ReviewGuide> => ipcRenderer.invoke('re-render-hunks', review), 104 getPrStatus: (prUrl: string): Promise<PrStatus> => ipcRenderer.invoke('get-pr-status', prUrl), 105 onUpdateAvailable: (callback: (info: UpdateInfo) => void): void => { 106 ipcRenderer.on('update-available', (_event, info: UpdateInfo) => callback(info)); 107 }, 108 offUpdateAvailable: (): void => { 109 ipcRenderer.removeAllListeners('update-available'); 110 }, 111 onUpdateReady: (callback: (version: string) => void): void => { 112 ipcRenderer.on('update-ready', (_event, version: string) => callback(version)); 113 }, 114 offUpdateReady: (): void => { 115 ipcRenderer.removeAllListeners('update-ready'); 116 }, 117 dismissUpdate: (version: string): Promise<void> => ipcRenderer.invoke('dismiss-update', version), 118 openExternal: (url: string): Promise<void> => ipcRenderer.invoke('open-external', url), 119 openLogsDirectory: (): Promise<void> => ipcRenderer.invoke('open-logs-directory'), 120 openReviewPrompt: (id: string): Promise<void> => ipcRenderer.invoke('open-review-prompt', id), 121 detectBinaryPath: (name: string): Promise<string> => ipcRenderer.invoke('detect-binary-path', name), 122 checkCliInstalled: (provider: string): Promise<{ installed: boolean; resolvedPath: string }> => 123 ipcRenderer.invoke('check-cli-installed', provider), 124 onNewReviewInHistory: (callback: () => void): void => { 125 ipcRenderer.on('new-review-in-history', () => callback()); 126 }, 127 offNewReviewInHistory: (): void => { 128 ipcRenderer.removeAllListeners('new-review-in-history'); 129 }, 130 markReviewRead: (id: string): Promise<void> => ipcRenderer.invoke('mark-review-read', id), 131 getPrState: (prUrl: string): Promise<{ prState: 'open' | 'merged' | 'closed'; headSha: string }> => 132 ipcRenderer.invoke('get-pr-state', prUrl), 133 getPrFiles: (prUrl: string): Promise<ChangedFile[]> => ipcRenderer.invoke('get-pr-files', prUrl), 134 platform: process.platform, 135 isPackaged: process.env.APP_IS_PACKAGED === '1', 136 });