fix: roll back rejected general settings save

Issue: #439
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-03 13:30:04 +00:00
committed by claude[bot]
parent 5f90eaf4ef
commit d5ad0371aa
24 changed files with 508 additions and 330 deletions
+49
View File
@@ -9,3 +9,52 @@ export function enqueueSerializedWrite(
): Promise<void> {
return previous.catch(() => undefined).then(write);
}
export interface OptimisticAttempt<T> {
previous: T;
previousFingerprint: string;
revision: number;
attempted: T;
attemptedFingerprint: string;
}
/** Capture the server-backed value before exposing a write candidate locally. */
export function optimisticAttempt<T>(
previous: T,
attempted: T,
previousFingerprint: string,
revision: number,
fingerprint: (value: T) => string,
): OptimisticAttempt<T> {
return {
previous: JSON.parse(JSON.stringify(previous)) as T,
previousFingerprint,
revision,
attempted,
attemptedFingerprint: fingerprint(attempted),
};
}
/**
* Roll back only the failed candidate represented by this attempt. A conflict
* reload or a newer edit owns a different revision/content and must win.
*/
export function rollbackOptimistic<T>(
host: {
_serverCfg: T | null;
_cfgRev: number;
_cfgContentFingerprint: string;
requestUpdate: () => unknown;
},
attempt: OptimisticAttempt<T>,
fingerprint: (value: T) => string,
): boolean {
const current = host._serverCfg;
if (!current || host._cfgRev !== attempt.revision
|| (current !== attempt.attempted
&& fingerprint(current) !== attempt.attemptedFingerprint)) return false;
host._serverCfg = attempt.previous;
host._cfgContentFingerprint = attempt.previousFingerprint;
host.requestUpdate();
return true;
}