fix(studio): enforce optimistic file concurrency (#2156)

* fix(studio): enforce optimistic file concurrency

* fix(studio): harden conditional file writes

* fix(studio): honor explicit file preconditions

* test(producer): allow zero-ms encode timing
This commit is contained in:
James Russo
2026-07-15 18:07:04 -04:00
committed by GitHub
parent 35e623b4f3
commit 2417293dab
34 changed files with 838 additions and 72 deletions
@@ -14,7 +14,7 @@ export interface RecordEditInput {
export interface DomEditCommitBaseParams {
activeCompPath: string | null;
showToast: (message: string, tone?: "error" | "info") => void;
writeProjectFile: (path: string, content: string) => Promise<void>;
writeProjectFile: ProjectFileWriter;
domEditSaveTimestampRef: MutableRefObject<number>;
editHistory: { recordEdit: (entry: RecordEditInput) => Promise<void> };
projectIdRef: MutableRefObject<string | null>;
@@ -22,6 +22,8 @@ export interface DomEditCommitBaseParams {
clearDomSelection: () => void;
}
type ProjectFileWriter = (path: string, content: string, expectedContent?: string) => Promise<void>;
interface SaveProjectFilesWithHistoryInput {
projectId: string;
label: string;
@@ -30,7 +32,7 @@ interface SaveProjectFilesWithHistoryInput {
coalesceMs?: number;
files: Record<string, string>;
readFile: (path: string) => Promise<string>;
writeFile: (path: string, content: string) => Promise<void>;
writeFile: ProjectFileWriter;
recordEdit: (entry: RecordEditInput) => Promise<void>;
}
@@ -71,7 +73,7 @@ export async function saveProjectFilesWithHistory({
const writtenPaths: string[] = [];
try {
for (const path of changedPaths) {
await writeFile(path, snapshots[path].after);
await writeFile(path, snapshots[path].after, snapshots[path].before);
writtenPaths.push(path);
}
@@ -79,7 +81,7 @@ export async function saveProjectFilesWithHistory({
} catch (error) {
try {
for (const path of writtenPaths.reverse()) {
await writeFile(path, snapshots[path].before);
await writeFile(path, snapshots[path].before, snapshots[path].after);
}
} catch (rollbackError) {
throw new AggregateError(