From 1a36b2abb4298ac20e5c842ac2b06e0230ff5a5e Mon Sep 17 00:00:00 2001 From: xuanru Date: Tue, 30 Jun 2026 22:52:45 +0000 Subject: [PATCH] fix(cli): don't run unbounded ffprobe on remote snapshot inputs VP9-alpha detection (shouldUseVp9AlphaDecoder -> extractMediaMetadata) spawns ffprobe with no timeout. For the new remote http(s) fallback that ran before the bounded extractVideoFrameToBuffer, so a stalled remote host could wedge `hyperframes snapshot` in ffprobe before the 30s extract timer ever started. Probe only local files; for remote URLs skip it (pass false). Local alpha behavior is unchanged. Co-Authored-By: Claude Opus 4.8 --- packages/cli/src/commands/snapshot.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/snapshot.ts b/packages/cli/src/commands/snapshot.ts index f1825e044..ee6bfcfda 100644 --- a/packages/cli/src/commands/snapshot.ts +++ b/packages/cli/src/commands/snapshot.ts @@ -361,6 +361,7 @@ async function captureSnapshots( // — FFmpeg reads http(s) input directly, and Chrome-headless can't seek // it either, so without this those videos render blank in snapshots. let ffmpegInput: string | null = null; + let inputIsLocal = false; try { const url = new URL(v.src); const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, ""); @@ -368,6 +369,7 @@ async function captureSnapshots( const rel = relative(projectDir, candidate); if (!rel.startsWith("..") && !isAbsolute(rel) && existsSync(candidate)) { ffmpegInput = candidate; + inputIsLocal = true; } else if (url.protocol === "http:" || url.protocol === "https:") { ffmpegInput = url.href; } @@ -375,10 +377,19 @@ async function captureSnapshots( /* unresolvable src (e.g. blob:, data:) — skip */ } if (!ffmpegInput) continue; + // VP9-alpha detection shells out to ffprobe, which has no timeout. + // Only probe local files (filesystem-bounded); for remote URLs skip it + // (pass false) so a stalled host can't wedge snapshot in ffprobe before + // the bounded extractVideoFrameToBuffer below ever runs. Remote + // VP9-alpha overlays aren't a current path — revisit with a bounded + // ffprobe if one appears. + const useVp9AlphaDecoder = inputIsLocal + ? await shouldUseVp9AlphaDecoder(ffmpegInput) + : false; const png = await extractVideoFrameToBuffer( ffmpegInput, Math.max(0, v.relTime), - await shouldUseVp9AlphaDecoder(ffmpegInput), + useVp9AlphaDecoder, ); if (!png) continue; updates.push({