From 6e80d6b1cf8f3127b2772e36e1e2a3f9dc86ebac Mon Sep 17 00:00:00 2001 From: EtienneLescot Date: Mon, 2 Nov 2026 21:15:33 +0100 Subject: [PATCH] fix(cli): keep render settings when exporting a v2 project A v2 project's editor went through normalizeProjectEditor's allowlist before the migration copied it into legacyEditor, so every render setting outside it (cursor, camera background, audio gain...) exported as its default. Keep the unknown keys, normalized ones still win. --- src/cli/exportProject.test.ts | 34 ++++++++++++++++++- src/cli/exportProject.ts | 11 ++++++ src/cli/loadCliProject.ts | 5 ++- .../video-editor/projectPersistence.ts | 7 ++-- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/cli/exportProject.test.ts b/src/cli/exportProject.test.ts index 174308011c..9b20013336 100644 --- a/src/cli/exportProject.test.ts +++ b/src/cli/exportProject.test.ts @@ -2,11 +2,13 @@ import { describe, expect, it, vi } from "vitest"; import { normalizeProjectEditor, PROJECT_VERSION, + type ProjectEditorState, validateProjectData, } from "@/components/video-editor/projectPersistence"; import { migrateProjectDataToAxcutDocument } from "@/lib/ai-edition/document/migrate"; import { isAxcutDocumentFile } from "@/lib/ai-edition/schema"; -import { loadDocumentProject, type VideoProbe } from "./exportProject"; +import { getEditorSettings } from "@/lib/ai-edition/store/editorSettings"; +import { legacyProjectEditor, loadDocumentProject, type VideoProbe } from "./exportProject"; const SCREEN = "/recordings/screen.mp4"; @@ -52,6 +54,36 @@ describe("the project file shapes the CLI export reads", () => { }); }); +describe("legacyProjectEditor", () => { + it("keeps the render settings the normalizer does not know", () => { + const editor = { + cursorModel3d: true, + cursorClickSound: true, + cursorShow: false, + webcamBackgroundMode: "blur", + webcamBlurIntensity: 0.8, + audioGainDb: 6, + }; + const document = migrateProjectDataToAxcutDocument({ + ...v2Project(), + editor: legacyProjectEditor(editor as Partial), + }); + const settings = getEditorSettings(document); + expect(settings.cursor.model3d).toBe(true); + expect(settings.cursor.clickSound).toBe(true); + expect(settings.cursorShow).toBe(false); + expect(settings.webcamBackgroundMode).toBe("blur"); + expect(settings.audioGainDb).toBe(6); + expect(document.legacyEditor).toMatchObject(editor); + }); + + it("still normalizes the keys it knows", () => { + expect(legacyProjectEditor({ aspectRatio: "nope" as never }).aspectRatio).toBe( + normalizeProjectEditor({}).aspectRatio, + ); + }); +}); + describe("loadDocumentProject", () => { it("reads the media, length and size off the document without probing", async () => { const project = await loadDocumentProject(savedDocument(), noProbe); diff --git a/src/cli/exportProject.ts b/src/cli/exportProject.ts index ad762becf3..06c2d93279 100644 --- a/src/cli/exportProject.ts +++ b/src/cli/exportProject.ts @@ -27,6 +27,17 @@ export interface ExportProject { sourceDims: Dims; } +/** + * A v2 project's editor as its migrated document keeps it: normalized, plus every key the + * normalizer does not know. The migration copies it into `legacyEditor`, where the export reads + * the render settings, so a key dropped here exported as its default. + */ +export function legacyProjectEditor( + editor: Partial | undefined, +): ProjectEditorState { + return { ...editor, ...normalizeProjectEditor(editor ?? {}) }; +} + /** * A project the editor saved: the AxcutDocument itself, at any `schemaVersion`, upgraded and * validated as the editor's "Browse files…" does. The main process has already relinked moved diff --git a/src/cli/loadCliProject.ts b/src/cli/loadCliProject.ts index 395514348b..459bae06e1 100644 --- a/src/cli/loadCliProject.ts +++ b/src/cli/loadCliProject.ts @@ -4,7 +4,6 @@ import { type EditorProjectData, - normalizeProjectEditor, resolveProjectMedia, toFileUrl, validateProjectData, @@ -13,7 +12,7 @@ import { migrateProjectDataToAxcutDocument } from "@/lib/ai-edition/document/mig import { applyProbedDuration } from "@/lib/ai-edition/document/timeline"; import { isAxcutDocumentFile } from "@/lib/ai-edition/schema"; import { nativeBridgeClient } from "@/native"; -import { type ExportProject, loadDocumentProject } from "./exportProject"; +import { type ExportProject, legacyProjectEditor, loadDocumentProject } from "./exportProject"; export function probeVideoDimensions( url: string, @@ -70,7 +69,7 @@ async function loadLegacyProject(project: EditorProjectData): Promise