diff --git a/apps/desktop/src/preview/Manager.test.ts b/apps/desktop/src/preview/Manager.test.ts index 79a059d82894..f6ab1561e186 100644 --- a/apps/desktop/src/preview/Manager.test.ts +++ b/apps/desktop/src/preview/Manager.test.ts @@ -575,6 +575,32 @@ describe("PreviewManager", () => { webviewSend.mockClear(); }); + effectIt.effect("preserves recording artifacts saved in the same millisecond", () => + withManager((manager) => + Effect.gen(function* () { + const stored = new Map(); + const save = (path: string, bytes: Uint8Array) => { + stored.set(path, Uint8Array.from(bytes)); + return undefined; + }; + writeFile.mockImplementationOnce(save).mockImplementationOnce(save); + const firstBytes = new Uint8Array([1, 2, 3]); + const secondBytes = new Uint8Array([4, 5, 6]); + const [first, second] = yield* Effect.all( + [ + manager.saveRecording("tab_first", "video/webm", firstBytes), + manager.saveRecording("tab_second", "video/webm", secondBytes), + ], + { concurrency: "unbounded" }, + ); + + expect(first.path).not.toBe(second.path); + expect(stored.get(first.path)).toEqual(firstBytes); + expect(stored.get(second.path)).toEqual(secondBytes); + }), + ), + ); + effectIt.effect.each([false, true])( "preserves simultaneous same-name downloads with an existing destination: %s", (existing) => diff --git a/apps/desktop/src/preview/Manager.ts b/apps/desktop/src/preview/Manager.ts index 14bdd0e1d6ba..7f28cbb49011 100644 --- a/apps/desktop/src/preview/Manager.ts +++ b/apps/desktop/src/preview/Manager.ts @@ -3268,7 +3268,8 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function data: Uint8Array, ) { const [createdAt, millis] = yield* Effect.all([currentIso, currentMillis]); - const id = `browser-recording-${millis.toString(36)}`; + const uuid = yield* random.uuidV4(); + const id = `browser-recording-${millis.toString(36)}-${uuid.slice(0, 8)}`; const extension = recordingFileExtension(mimeType); const artifactPath = path.join(resolvedArtifactDirectory, `${id}.${extension}`); yield* fileSystem.makeDirectory(resolvedArtifactDirectory, { recursive: true }).pipe( @@ -3282,7 +3283,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function }), ), ); - yield* fileSystem.writeFile(artifactPath, data).pipe( + yield* fileSystem.writeFile(artifactPath, data, { flag: "wx" }).pipe( Effect.mapError( (cause) => new PreviewOperationError({