fix: don't stream when the append IPC is unavailable

Codex re-review: if openRecordingStream exists but appendRecordingChunk
does not (renderer/main version skew), the recorder would open the stream
and switch to streaming mode, but every append silently no-ops and the
save ends up empty. Require both IPC methods before streaming; otherwise
fall back to in-memory buffering. Adds a regression test.

Verified: tsc --noEmit clean; biome clean; vitest 183/183.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
neurot1cal
2026-05-26 16:39:53 -07:00
parent 36d7d2bdd0
commit 5c5cab6903
2 changed files with 27 additions and 1 deletions
+20
View File
@@ -205,6 +205,26 @@ describe("createRecorderHandle", () => {
expect(blob.size).toBe(2);
});
it("buffers in memory when appendRecordingChunk is unavailable (version skew)", async () => {
const openRecordingStream = vi.fn(async () => ({ success: true }));
// appendRecordingChunk intentionally omitted to simulate renderer/main skew.
stubElectronAPI({ openRecordingStream });
const handle = createRecorderHandle({} as MediaStream, { mimeType: "video/webm" }, "rec.webm");
const fake = driver(handle);
fake.emit(new Blob(["a"]));
await tick();
fake.emit(new Blob(["b"]));
fake.stop();
const blob = await handle.recordedBlobPromise;
// Never even attempts to open the stream when it can't append to it.
expect(openRecordingStream).not.toHaveBeenCalled();
expect(handle.isStreaming()).toBe(false);
expect(blob.size).toBe(2);
});
it("discard closes the disk stream for a streamed recording", async () => {
const closeRecordingStream = vi.fn(async () => ({ success: true }));
stubElectronAPI({
+7 -1
View File
@@ -76,8 +76,14 @@ export function createRecorderHandle(
});
};
// Require BOTH stream IPC methods before attempting to stream. If only
// openRecordingStream exists (renderer/main version skew), streaming would
// open but every append would silently no-op, saving an empty file — so in
// that case fall through to in-memory buffering instead.
const openPromise: Promise<{ success: boolean; error?: string }> =
fileName && api?.openRecordingStream
fileName !== undefined &&
typeof api?.openRecordingStream === "function" &&
typeof api?.appendRecordingChunk === "function"
? api.openRecordingStream(fileName)
: Promise.resolve({ success: false });