Harden audit findings: correctness, type-safety, Windows conventions & polish

Audit-pass over CODE-AUDIT.md (~48 items closed this pass; all verified —
typecheck + 234 tests + eslint + prettier green).

Correctness / bugs:
- B3: match the release checksum to the asset's filename line (no wrong-hash verify)
- B4: newline-safe metadata probe (one --print with a unit-separator delimiter)
- B5 / L88: guard the meta event against canceled items; progress no longer promotes
  a queued item outside pump()
- B7: cookie-login promise always resolves (handles destroy-without-close)
- L146: trim parser rejects >2 colon-group times; M36: Library selection counts only
  actionable rows
- L11 / L50 / L156 / L57 / L159 / L15 / L3: live queue count, empty-cookie message,
  schedule picker min, dead-code/comment cleanup

Type safety:
- Enable noUncheckedIndexedAccess + noFallthroughCasesInSwitch (15 real edge cases fixed)

Resilience / Windows / metadata:
- R5: settings write failure handled (no unhandled IPC rejection; reconciles to truth)
- W1 / W5 / W6: min window size, seeded folder picker, parented sign-in window;
  L147 dead macOS branches removed
- CL1: shared stdout markers; package/builder metadata (license, homepage, repository,
  copyright, tsbuildinfo glob)

Copy / docs / tests:
- M37 / SR9 dev-jargon cleanup in hints; M8 / M25 / M26 / L66 / L80 / L81 reconciled
- New unit tests for L35 (isValidMediaItem) and L36 (compareVersions)

This commit also checkpoints the previously-uncommitted feat/tray-background-clipboard
work it builds on: background running + auto-download, library clipboard detection,
tray, binary management & library scale, credential encryption at rest, the shared
jsonStore and ui/ primitives, and the eslint/prettier tooling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 13:02:54 -04:00
parent a6a8c5f578
commit 1376c2dee8
82 changed files with 4571 additions and 1276 deletions
+24 -19
View File
@@ -57,8 +57,7 @@ const api = {
return () => ipcRenderer.removeListener(IpcChannels.appUpdateProgress, listener)
},
getYtdlpVersion: (): Promise<YtdlpVersionResult> =>
ipcRenderer.invoke(IpcChannels.ytdlpVersion),
getYtdlpVersion: (): Promise<YtdlpVersionResult> => ipcRenderer.invoke(IpcChannels.ytdlpVersion),
/** Versions of the bundled ffmpeg + ffprobe (display-only; not auto-updated). */
getFfmpegVersions: (): Promise<FfmpegVersionResult> =>
@@ -69,20 +68,16 @@ const api = {
startDownload: (opts: StartDownloadOptions): Promise<StartDownloadResult> =>
ipcRenderer.invoke(IpcChannels.downloadStart, opts),
cancelDownload: (id: string): Promise<void> =>
ipcRenderer.invoke(IpcChannels.downloadCancel, id),
cancelDownload: (id: string): Promise<void> => ipcRenderer.invoke(IpcChannels.downloadCancel, id),
pauseDownload: (id: string): Promise<void> =>
ipcRenderer.invoke(IpcChannels.downloadPause, id),
pauseDownload: (id: string): Promise<void> => ipcRenderer.invoke(IpcChannels.downloadPause, id),
getDefaultFolder: (): Promise<string> => ipcRenderer.invoke(IpcChannels.defaultFolder),
chooseFolder: (): Promise<string | null> => ipcRenderer.invoke(IpcChannels.chooseFolder),
chooseFolder: (current?: string): Promise<string | null> =>
ipcRenderer.invoke(IpcChannels.chooseFolder, current),
openPath: (path: string): Promise<string> => ipcRenderer.invoke(IpcChannels.openPath, path),
showInFolder: (path: string): Promise<void> =>
ipcRenderer.invoke(IpcChannels.showInFolder, path),
showInFolder: (path: string): Promise<void> => ipcRenderer.invoke(IpcChannels.showInFolder, path),
readClipboard: (): Promise<string> => ipcRenderer.invoke(IpcChannels.clipboardRead),
@@ -184,8 +179,7 @@ const api = {
reindexSource: (id: string): Promise<IndexSourceResult> =>
ipcRenderer.invoke(IpcChannels.sourceReindex, id),
removeSource: (id: string): Promise<Source[]> =>
ipcRenderer.invoke(IpcChannels.sourceRemove, id),
removeSource: (id: string): Promise<Source[]> => ipcRenderer.invoke(IpcChannels.sourceRemove, id),
listSourceItems: (sourceId: string): Promise<MediaItem[]> =>
ipcRenderer.invoke(IpcChannels.sourceItems, sourceId),
@@ -220,8 +214,7 @@ const api = {
runTerminal: (id: string, args: string): Promise<TerminalRunResult> =>
ipcRenderer.invoke(IpcChannels.terminalRun, id, args),
cancelTerminal: (id: string): Promise<void> =>
ipcRenderer.invoke(IpcChannels.terminalCancel, id),
cancelTerminal: (id: string): Promise<void> => ipcRenderer.invoke(IpcChannels.terminalCancel, id),
/** Subscribe to live terminal output. Returns an unsubscribe function. */
onTerminalOutput: (cb: (ev: TerminalEvent) => void): (() => void) => {
@@ -232,7 +225,11 @@ const api = {
/** Reflect overall queue progress on the Windows taskbar (fire-and-forget). */
setTaskbarProgress: (p: TaskbarProgress): void =>
ipcRenderer.send(IpcChannels.taskbarProgress, p)
ipcRenderer.send(IpcChannels.taskbarProgress, p),
/** Open a YouTube WebView to automatically extract a PO token (Phase P). */
mintPoToken: (): Promise<string | null> =>
ipcRenderer.invoke(IpcChannels.youtubePoTokenMint) as Promise<string | null>
}
export type Api = typeof api
@@ -248,11 +245,19 @@ if (process.contextIsolated) {
contextBridge.exposeInMainWorld('electron', electron)
contextBridge.exposeInMainWorld('api', api)
} catch (error) {
console.error(error)
// M30: a broken bridge causes the renderer to silently run in preview/mock mode.
// Notify the main process so it can show a hard error dialog — without this the
// failure is completely invisible to the user.
console.error('[AeroFetch preload] contextBridge failed:', error)
try {
ipcRenderer.send(IpcChannels.preloadBridgeFailure, String(error))
} catch {
/* if IPC itself is broken there is nothing more we can do */
}
}
} else {
// @ts-ignore (defined in index.d.ts)
// @ts-ignore window.electron is declared in index.d.ts
window.electron = electron
// @ts-ignore (defined in index.d.ts)
// @ts-ignore window.api is declared in index.d.ts
window.api = api
}