feat(audit): Batch 23 — settings key renames with migration (CC1) + config.ts (CC11)

CC1: customCommandEnabled→enableCustomCommands, downloadArchive→
useDownloadArchive, clipboardWatch→watchClipboard, sidebarCollapsed→
isSidebarCollapsed, hardwareAcceleration→useHardwareAcceleration,
videoDir/audioDir→videoFolder/audioFolder (+ chooseDir/clearDir store
actions → chooseFolder/clearFolder). Rename map in settingsMigration.ts
(pure, unit-tested incl. pre-rename backup fixture), applied as an
idempotent on-disk shim at store open and on backup import so old
settings.json and old backups both keep working.

CC11: update host/owner/repo + release API moved to src/main/config.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 12:34:05 -04:00
parent 545cfeed5e
commit 134c6a167c
25 changed files with 288 additions and 135 deletions
+9 -4
View File
@@ -1,6 +1,7 @@
import { dialog, type BrowserWindow } from 'electron'
import { readFileSync, writeFileSync } from 'fs'
import { getSettings, setSettings, SECRET_KEYS } from './settings'
import { migrateSettingsKeys } from './settingsMigration'
import { listTemplates, replaceTemplates } from './templates'
import { isTemplateLike } from './validation'
import type { BackupExportResult, BackupImportResult, Settings, CommandTemplate } from '@shared/ipc'
@@ -54,9 +55,13 @@ export async function importBackup(win: BrowserWindow | undefined): Promise<Back
// hand-edited or partial backup file degrades gracefully rather than
// corrupting the store.
const file = parsed as Partial<BackupFile>
// Backups exported by an older AeroFetch carry pre-rename keys (CC1) — map
// them forward so old backup files keep restoring cleanly.
const incomingSettings =
file.settings && typeof file.settings === 'object'
? (file.settings as Partial<Settings>)
? (migrateSettingsKeys(
file.settings as unknown as Record<string, unknown>
) as Partial<Settings>)
: undefined
// Drop non-object / id-less entries up front (audit T3) so both the consent
// check below and replaceTemplates see only well-shaped rows. Without this a
@@ -67,7 +72,7 @@ export async function importBackup(win: BrowserWindow | undefined): Promise<Back
: []
// A custom-command template's `args` are extra yt-dlp flags that get spawned on
// the next download. A backup that arrives with customCommandEnabled + a default
// the next download. A backup that arrives with enableCustomCommands + a default
// template carrying args would silently enable code execution the moment a
// download starts — so require an explicit, informed confirmation before
// honouring that, and import the templates in a *disabled* state if declined.
@@ -75,7 +80,7 @@ export async function importBackup(win: BrowserWindow | undefined): Promise<Back
(t) => t && typeof t === 'object' && typeof t.args === 'string' && t.args.trim() !== ''
)
const wouldEnableCustomCommands =
incomingSettings?.customCommandEnabled === true && commandTemplates.length > 0
incomingSettings?.enableCustomCommands === true && commandTemplates.length > 0
let applyCustomCommands = true
if (wouldEnableCustomCommands) {
@@ -120,7 +125,7 @@ export async function importBackup(win: BrowserWindow | undefined): Promise<Back
// enable), force the toggle off so an imported defaultTemplateId can't auto-run.
const safeSettings = applyCustomCommands
? restored
: { ...restored, customCommandEnabled: false }
: { ...restored, enableCustomCommands: false }
setSettings(safeSettings)
}
if (incomingTemplates.length > 0 || Array.isArray(file.templates)) {