From 528a31b16f80625fcf54d2097589c5f7bc3f4998 Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:25:13 +1000 Subject: [PATCH] fix: clean up ipc edge cases --- electron/ipc/cursor/interaction.ts | 2 ++ electron/ipc/project/manager.ts | 13 +++++++++++-- electron/ipc/project/session.ts | 7 +++++-- electron/ipc/register/project.ts | 8 ++++++-- electron/ipc/register/recording.ts | 5 +++++ electron/ipc/register/sources.ts | 9 ++++++++- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/electron/ipc/cursor/interaction.ts b/electron/ipc/cursor/interaction.ts index e0b501e1..37cfc633 100644 --- a/electron/ipc/cursor/interaction.ts +++ b/electron/ipc/cursor/interaction.ts @@ -97,6 +97,8 @@ export async function startInteractionCapture() { return; } + stopInteractionCapture(); + try { const hook = loadUiohookModule(); console.log( diff --git a/electron/ipc/project/manager.ts b/electron/ipc/project/manager.ts index 9859db0b..48541e8e 100644 --- a/electron/ipc/project/manager.ts +++ b/electron/ipc/project/manager.ts @@ -298,8 +298,17 @@ export async function listProjectLibraryEntries() { export async function loadProjectFromPath(projectPath: string) { const normalizedPath = normalizePath(projectPath); - const content = await fs.readFile(normalizedPath, "utf-8"); - const project = JSON.parse(content); + let project: unknown; + try { + const content = await fs.readFile(normalizedPath, "utf-8"); + project = JSON.parse(content); + } catch (error) { + return { + success: false, + canceled: false, + message: `Failed to read project file: ${error instanceof Error ? error.message : String(error)}`, + }; + } const mediaSources = await resolveProjectMediaSources(project); if (!mediaSources.success) { diff --git a/electron/ipc/project/session.ts b/electron/ipc/project/session.ts index 995f7193..2f0001c1 100644 --- a/electron/ipc/project/session.ts +++ b/electron/ipc/project/session.ts @@ -70,11 +70,14 @@ export async function resolveRecordingSessionManifest( } const webcamPath = path.join(path.dirname(normalizedVideoPath), webcamFileName); - await fs.access(webcamPath, fsConstants.F_OK); + const webcamExists = await fs + .access(webcamPath, fsConstants.F_OK) + .then(() => true) + .catch(() => false); return { videoPath: normalizedVideoPath, - webcamPath, + webcamPath: webcamExists ? webcamPath : null, timeOffsetMs: normalizeRecordingTimeOffsetMs(parsed.timeOffsetMs), }; } catch { diff --git a/electron/ipc/register/project.ts b/electron/ipc/register/project.ts index 2e9836d9..cf9b6208 100644 --- a/electron/ipc/register/project.ts +++ b/electron/ipc/register/project.ts @@ -355,7 +355,8 @@ export function registerProjectHandlers() { return { success: false, error: 'Only auto-generated recordings can be deleted' }; } const resolvedPath = await fs.realpath(filePath).catch(() => path.resolve(filePath)); - const recordingsDir = await getRecordingsDir(); + const recordingsDirRaw = await getRecordingsDir(); + const recordingsDir = await fs.realpath(recordingsDirRaw).catch(() => path.resolve(recordingsDirRaw)); if (!isPathInsideDirectory(resolvedPath, recordingsDir) || !isAutoRecordingPath(resolvedPath)) { return { success: false, error: 'Only auto-generated recordings can be deleted' }; } @@ -363,7 +364,10 @@ export function registerProjectHandlers() { // Also delete the cursor telemetry sidecar if it exists const telemetryPath = getTelemetryPathForVideo(resolvedPath); await fs.unlink(telemetryPath).catch(() => {}); - if (currentVideoPath === resolvedPath) { + const currentResolved = currentVideoPath + ? await fs.realpath(currentVideoPath).catch(() => currentVideoPath) + : null; + if (currentResolved === resolvedPath) { setCurrentVideoPath(null); setCurrentRecordingSession(null); } diff --git a/electron/ipc/register/recording.ts b/electron/ipc/register/recording.ts index 83d4b27b..c1551058 100644 --- a/electron/ipc/register/recording.ts +++ b/electron/ipc/register/recording.ts @@ -994,6 +994,11 @@ export function registerRecordingHandlers( return await finalizeStoredVideo(finalVideoPath) } catch (error) { console.error('Failed to stop FFmpeg recording:', error) + try { + ffmpegCaptureProcess?.kill() + } catch { + // ignore cleanup failures + } setFfmpegCaptureProcess(null) setFfmpegCaptureTargetPath(null) setFfmpegScreenRecordingActive(false) diff --git a/electron/ipc/register/sources.ts b/electron/ipc/register/sources.ts index cb24341b..84004fd0 100644 --- a/electron/ipc/register/sources.ts +++ b/electron/ipc/register/sources.ts @@ -432,7 +432,14 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
` - await highlightWin.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`) + try { + await highlightWin.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`) + } catch (loadError) { + if (!highlightWin.isDestroyed()) { + highlightWin.close() + } + throw loadError + } setTimeout(() => { if (!highlightWin.isDestroyed()) highlightWin.close()