Skip to content

fix(main): async project listing, ffmpeg timeouts + concurrency cap, structured IPC errors, recorder cleanup#52

Merged
thisiscsim merged 1 commit into
mainfrom
fix/main-robustness
Jul 19, 2026
Merged

fix(main): async project listing, ffmpeg timeouts + concurrency cap, structured IPC errors, recorder cleanup#52
thisiscsim merged 1 commit into
mainfrom
fix/main-robustness

Conversation

@thisiscsim

Copy link
Copy Markdown
Owner

Summary

Audit roadmap Phase 5 (main-process robustness + two renderer leak/error fixes).

Main process

  • listProjects is now async (fs/promises + Promise.all). It parses every project's edl.json + meta.json; doing that serially with sync fs on the main (UI) thread janked the window once a user had many projects.
  • Shared runFfmpeg(args, timeoutMs) with a hard SIGKILL timeout replaces the four ad-hoc ffmpeg spawns (thumbnail / duration probe / proxy / voice-sample). A malformed or hostile media file could otherwise hang a spawn forever with no reaping. Proxy encodes are bounded to 2 concurrent — importing N videos previously fired N ffmpeg processes at once, saturating CPU/memory.
  • Structured IPC errors: asset:import, asset:importBuffer, references/benchmark:import, project:watch, and project:thumbnail validate the slug via a shared assertSlug and return { ok:false, error } instead of throwing across IPC (they called safeProjectPath, which throws, outside any try/catch — violating the repo's own IPC convention). asset:importBuffer also rejects a non-basename filename.
  • meta:save / style:patch re-validate the merged result through parseMeta / parseStyleProfile before writing, so an arbitrary renderer patch can't persist unknown keys or an unsafe (url()) palette into the sidecar files.

Renderer

  • RecordButton (LeftRail) and VoicesTab (Settings) now stop the MediaRecorder and release the mic tracks on unmount. Cmd+\ unmounts the rail mid-recording, which left the mic hot and the recorder leaked.
  • Home project/album delete failures now surface an error toast instead of silently doing nothing.

Main-process + preload-adjacent change — restart npm run dev.

Test plan

  • typecheck / lint / format / 101 tests / build green
  • Manual (post-merge): import several videos → at most 2 ffmpeg proxies run at once; a bad slug from a hacked renderer returns an error (no unhandled rejection); start a mic recording then Cmd+\ → mic light turns off; delete a project while the folder is locked → error toast

Made with Cursor

…structured errors, recorder cleanup

Main process:
- listProjects is now async (fs/promises + Promise.all): it parses every
  project's edl.json + meta.json, and doing that serially with sync fs on
  the UI thread janked the window once a user had many projects.
- Shared runFfmpeg(args, timeoutMs) with a hard SIGKILL timeout replaces
  the four ad-hoc ffmpeg spawns (thumbnail/probe/proxy/voice-sample) — a
  malformed file could otherwise hang a spawn forever. Proxy encodes are
  bounded to 2 concurrent (importing N videos previously fired N at once).
- Import/watch/thumbnail handlers validate the slug via a shared
  assertSlug and return {ok:false,error} instead of throwing across IPC
  (they called safeProjectPath, which throws, outside any try/catch).
- meta:save / style:patch re-validate the merged result through
  parseMeta / parseStyleProfile before writing, so an arbitrary renderer
  patch can't persist unknown keys or a url() palette.

Renderer:
- RecordButton (LeftRail) and VoicesTab (Settings) stop the MediaRecorder
  and release the mic on unmount — Cmd+\ unmounts the rail mid-recording,
  which left the mic hot and the recorder leaked.
- Home project/album delete failures now surface an error toast instead of
  silently doing nothing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@thisiscsim
thisiscsim merged commit d9668a5 into main Jul 19, 2026
1 check passed
@thisiscsim
thisiscsim deleted the fix/main-robustness branch July 19, 2026 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant