refactor(desktop): extract uninstall IPC from main.cjs into uninstall-ipc.cjs

Eighth main.cjs cluster peel. The two hermes:uninstall:* handlers (summary, run)
move verbatim into electron/uninstall-ipc.cjs behind a registerUninstallIpc({
ipcMain, getUninstallSummary, runDesktopUninstall }) registrar. The uninstall
engine stays in the main process and is injected.

Channel names unchanged → preload + renderer untouched. Adds
electron/uninstall-ipc.test.cjs (surface invariant + run mode normalization).
This commit is contained in:
Brooklyn Nicholson 2026-06-30 14:11:50 -05:00
parent 8a48d54193
commit 150e023fe2
3 changed files with 68 additions and 5 deletions

View file

@ -62,6 +62,7 @@ const { registerUpdatesIpc } = require('./updates-ipc.cjs')
const { registerLogsIpc } = require('./logs-ipc.cjs')
const { registerProjectDirIpc } = require('./project-dir-ipc.cjs')
const { registerVscodeThemeIpc } = require('./vscode-theme-ipc.cjs')
const { registerUninstallIpc } = require('./uninstall-ipc.cjs')
const { OFFICIAL_REPO_HTTPS_URL, isOfficialSshRemote } = require('./update-remote.cjs')
const { resolveBehindCount, shouldCountCommits } = require('./update-count.cjs')
const { runRebuildWithRetry } = require('./update-rebuild.cjs')
@ -7127,11 +7128,8 @@ async function runDesktopUninstall(mode) {
return { ok: true, mode, willRemoveAppBundle: Boolean(removeBundle), scriptPath }
}
ipcMain.handle('hermes:uninstall:summary', async () => getUninstallSummary())
ipcMain.handle('hermes:uninstall:run', async (_event, payload) => {
const mode = payload && typeof payload === 'object' ? payload.mode : payload
return runDesktopUninstall(String(mode || ''))
})
// Uninstall IPC lives in uninstall-ipc.cjs; the uninstall engine is injected.
registerUninstallIpc({ getUninstallSummary, ipcMain, runDesktopUninstall })
// VS Code Marketplace theme IPC lives in vscode-theme-ipc.cjs.
registerVscodeThemeIpc({ ipcMain })

View file

@ -0,0 +1,14 @@
'use strict'
// Uninstall IPC: summarize what a desktop uninstall would remove + run it
// (GUI-only / lite / full). Both delegate to the main-process uninstall engine,
// which is injected.
function registerUninstallIpc({ getUninstallSummary, ipcMain, runDesktopUninstall }) {
ipcMain.handle('hermes:uninstall:summary', async () => getUninstallSummary())
ipcMain.handle('hermes:uninstall:run', async (_event, payload) => {
const mode = payload && typeof payload === 'object' ? payload.mode : payload
return runDesktopUninstall(String(mode || ''))
})
}
module.exports = { registerUninstallIpc }

View file

@ -0,0 +1,51 @@
'use strict'
const assert = require('node:assert/strict')
const test = require('node:test')
const { registerUninstallIpc } = require('./uninstall-ipc.cjs')
function fakeIpcMain() {
const handlers = new Map()
return {
handlers,
handle(channel, handler) {
assert.ok(!handlers.has(channel), `duplicate registration for ${channel}`)
handlers.set(channel, handler)
}
}
}
test('registerUninstallIpc wires only hermes:uninstall:* channels, each to a handler fn', () => {
const ipcMain = fakeIpcMain()
registerUninstallIpc({ ipcMain, getUninstallSummary: async () => ({}), runDesktopUninstall: async () => ({}) })
assert.deepEqual([...ipcMain.handlers.keys()].sort(), ['hermes:uninstall:run', 'hermes:uninstall:summary'])
for (const handler of ipcMain.handlers.values()) {
assert.equal(typeof handler, 'function')
}
})
test('run normalizes both the {mode} object form and the bare-string form', async () => {
const ipcMain = fakeIpcMain()
const modes = []
registerUninstallIpc({
ipcMain,
getUninstallSummary: async () => ({}),
runDesktopUninstall: async mode => {
modes.push(mode)
return { mode }
}
})
await ipcMain.handlers.get('hermes:uninstall:run')({}, { mode: 'full' })
await ipcMain.handlers.get('hermes:uninstall:run')({}, 'lite')
await ipcMain.handlers.get('hermes:uninstall:run')({}, null)
assert.deepEqual(modes, ['full', 'lite', ''])
})