Files
orca/src/preload/api/app-bridge.ts
T
Neil 401664298f fix(preload): make a dropped bridge key a compile error
The split silently dropped jira.searchUsers and
runtimeEnvironments.retryControlConnection. Neither failed typecheck: the bridge
modules carried no satisfies annotation and the composed api object was
unannotated, so a missing key was only a runtime TypeError in the renderer.

Annotates each module against PreloadApi, the type window.api is already
declared as, so the contract supplies the shape rather than a parallel copy.
Deleting jira.searchUsers now fails with TS2741 naming the key.

Turning this on surfaced 106 places where a bridge locally annotated
Promise<unknown> or unknown[] over a contract that declares concrete types --
the bridge was erasing types the renderer relied on. Those annotations are gone.

Also exposes app.awaitBeforeUnloadCheckpoint, which was declared and called but
never actually on the bridge, so the lazy-chunk recovery reload optional-chained
to a no-op and navigated without joining the checkpoint. The missing key was
caught by the new annotation rather than by hand.
2026-09-01 18:24:49 -07:00

78 lines
3.9 KiB
TypeScript

import { ipcRenderer } from 'electron'
import type { AppIdentity } from '../../shared/app-identity'
import type { FloatingTerminalCwdRequest } from '../../shared/ui-chrome-types'
import type { MacCapturedDigitRowChord } from '../../shared/macos-symbolic-hotkeys'
import type { MarkdownDocument } from '../../shared/filesystem-entry-types'
import type { WriteTerminalRenderDesyncEvidenceArgs } from '../../shared/terminal-render-desync-evidence'
import {
KEYBOARD_LAYOUT_CHANGED_CHANNEL,
type KeyboardLayoutChangeEvent
} from '../../shared/keyboard-layout-events'
import { prepareAndInvokeAppRestart } from '../renderer-restart-wiring'
import { awaitBeforeUnloadCheckpoint, startupDiagnosticsEnabled } from '../preload-runtime-support'
import type { PreloadApi } from '../api-types'
export const appApi = {
getIdentity: (): Promise<AppIdentity> => ipcRenderer.invoke('app:getIdentity'),
getFeatureWallAssetBaseUrl: (): Promise<string> =>
ipcRenderer.invoke('app:getFeatureWallAssetBaseUrl'),
relaunch: (): Promise<void> =>
prepareAndInvokeAppRestart(
window,
() => ipcRenderer.invoke('app:relaunch'),
awaitBeforeUnloadCheckpoint
),
restart: (): Promise<void> =>
prepareAndInvokeAppRestart(
window,
() => ipcRenderer.invoke('app:restart'),
awaitBeforeUnloadCheckpoint
),
reload: (): Promise<void> =>
prepareAndInvokeAppRestart(
window,
() => ipcRenderer.invoke('app:reload'),
awaitBeforeUnloadCheckpoint
),
stageBeforeUnloadSync: (args: Parameters<PreloadApi['app']['stageBeforeUnloadSync']>[0]) => {
const result = ipcRenderer.sendSync('app:stage-before-unload-sync', args) as { ok?: unknown }
if (result?.ok !== true) {
throw new Error('Failed to stage renderer state before unload.')
}
},
awaitBeforeUnloadCheckpoint: () => awaitBeforeUnloadCheckpoint(),
awaitFirstWindowStartupServices: (): Promise<void> =>
ipcRenderer.invoke('app:awaitFirstWindowStartupServices'),
prepareTerminalStartupRestoration: (): Promise<void> =>
ipcRenderer.invoke('app:prepareTerminalStartupRestoration'),
recoverLegacyWorkerTerminalsForRendererStartup: (): Promise<void> =>
ipcRenderer.invoke('app:recoverLegacyWorkerTerminalsForRendererStartup'),
startupDiagnostic: (event: string, details?: Record<string, unknown>): Promise<void> =>
startupDiagnosticsEnabled
? ipcRenderer.invoke('app:startupDiagnostic', event, details)
: Promise.resolve(),
getKeyboardInputSourceId: (): Promise<string | null> =>
ipcRenderer.invoke('app:getKeyboardInputSourceId'),
getMacCapturedDigitRowChords: (): Promise<MacCapturedDigitRowChord[]> =>
ipcRenderer.invoke('app:getMacCapturedDigitRowChords'),
getKeyboardLayoutSnapshot: () => ipcRenderer.invoke('app:getKeyboardLayoutSnapshot'),
onKeyboardLayoutChanged: (callback: (event: KeyboardLayoutChangeEvent) => void): (() => void) => {
const listener = (_event: Electron.IpcRendererEvent, event: KeyboardLayoutChangeEvent): void =>
callback(event)
ipcRenderer.on(KEYBOARD_LAYOUT_CHANGED_CHANNEL, listener)
return () => ipcRenderer.removeListener(KEYBOARD_LAYOUT_CHANGED_CHANNEL, listener)
},
setUnreadDockBadgeCount: (count: number): Promise<void> =>
ipcRenderer.invoke('app:setUnreadDockBadgeCount', count),
getFloatingTerminalCwd: (args?: FloatingTerminalCwdRequest): Promise<string> =>
ipcRenderer.invoke('app:getFloatingTerminalCwd', args),
getFloatingMarkdownDirectory: (): Promise<string> =>
ipcRenderer.invoke('app:getFloatingMarkdownDirectory'),
pickFloatingMarkdownDocument: (): Promise<MarkdownDocument | null> =>
ipcRenderer.invoke('app:pickFloatingMarkdownDocument'),
pickFloatingWorkspaceDirectory: (): Promise<string | null> =>
ipcRenderer.invoke('app:pickFloatingWorkspaceDirectory'),
writeTerminalRenderDesyncEvidence: (args: WriteTerminalRenderDesyncEvidenceArgs) =>
ipcRenderer.invoke('terminal:writeRenderDesyncEvidence', args)
} satisfies PreloadApi['app']