fix(migration): handle already-v5 settings and ensure 'failed' branch writes v5 marker

This commit is contained in:
2026-06-08 07:02:45 +05:30
parent 74dde8d6d1
commit aeadde5f40
4 changed files with 37 additions and 1 deletions
+4
View File
@@ -25,6 +25,10 @@ class MigrationRunner {
return 'migrated';
} catch (err) {
console.error('[migration-runner] transform failed:', err.message);
// Back up the original and write v5 marker so future launches skip migration.
// Without this, every launch would fail again and the user stays on defaults.
fs.copyFileSync(this.file, this.backup);
fs.writeFileSync(this.file, JSON.stringify({ ...raw, 'migration.version': 5 }, null, 2));
return 'failed';
}
}
+15
View File
@@ -11,6 +11,15 @@ const v4SettingsSchema = z.object({
snippets: z.array(z.unknown()).default([]),
}).passthrough();
const v5OnlyFields = ['updateChannel', 'autoCheckUpdates', 'firstRun'];
function isAlreadyV5(data) {
if (!data || typeof data !== 'object') return false;
if (data['migration.version'] === 5) return true;
// Check for v5-only fields — a v4 file would never have these
return v5OnlyFields.some((f) => f in data);
}
const v5SettingsShape = {
fontSize: 14,
tabSize: 4,
@@ -39,6 +48,12 @@ const v5SettingsShape = {
};
function migrateV4ToV5(v4) {
// If data already looks like v5 (has migration.version=5 or v5-only fields),
// return it as-is so the runner can mark it done without re-migrating.
// This handles the case where a buggy v5 run wrote v5 fields without the marker.
if (isAlreadyV5(v4)) {
return v4;
}
const parsed = v4SettingsSchema.parse(v4 || {});
return {
...v5SettingsShape,