diff --git a/src/main/index.ts b/src/main/index.ts index cc30b7de..6716e5d0 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -181,29 +181,44 @@ else { = (store.preferences.get('storage.vaultPath') as string | null) || path.join(storagePath, 'markdown-vault') ensureFlatSpacesLayout(vaultPath) - const { hasMarkdownVaultData } = lazyRequire( - './storage/providers/markdown', - ) as typeof import('./storage/providers/markdown') - const vaultHasData = hasMarkdownVaultData(vaultPath) - - if (!vaultHasData) { - const { closeDB } = lazyRequire('./db') as typeof import('./db') - const { migrateSqliteToMarkdownStorage } = lazyRequire( - './storage/providers/markdown', - ) as typeof import('./storage/providers/markdown') - try { - migrationResult = migrateSqliteToMarkdownStorage() + // Авто-миграция из SQLite выполняется только один раз. Флаг + // storage.sqliteMigrated персистентно блокирует повтор, иначе ручная + // очистка vault при сохранившемся massCode.db триггерила бы миграцию + // заново и возвращала удалённые данные. + const alreadyMigrated + = store.preferences.get('storage.sqliteMigrated') === true - store.preferences.delete('storage.engine' as any) - store.preferences.delete('backup' as any) - - // eslint-disable-next-line no-console - console.log('[Auto-migration complete]', migrationResult) - } - finally { - closeDB() + if (!alreadyMigrated) { + const { hasMarkdownVaultData } = lazyRequire( + './storage/providers/markdown', + ) as typeof import('./storage/providers/markdown') + const vaultHasData = hasMarkdownVaultData(vaultPath) + + if (!vaultHasData) { + const { closeDB } = lazyRequire('./db') as typeof import('./db') + const { migrateSqliteToMarkdownStorage } = lazyRequire( + './storage/providers/markdown', + ) as typeof import('./storage/providers/markdown') + + try { + migrationResult = migrateSqliteToMarkdownStorage() + + store.preferences.delete('storage.engine' as any) + store.preferences.delete('backup' as any) + + // eslint-disable-next-line no-console + console.log('[Auto-migration complete]', migrationResult) + } + finally { + closeDB() + } } + + // Помечаем миграцию как выполненную в обоих случаях: после успешной + // миграции и как backfill для пользователей, уже мигрировавших в + // прошлых версиях (vault с данными, но без флага). + store.preferences.set('storage.sqliteMigrated', true) } } } diff --git a/src/main/store/__tests__/preferences.test.ts b/src/main/store/__tests__/preferences.test.ts index 8f29cd26..2b1e76c8 100644 --- a/src/main/store/__tests__/preferences.test.ts +++ b/src/main/store/__tests__/preferences.test.ts @@ -170,6 +170,30 @@ describe('preferences store sanitization', () => { ).toBeUndefined() }) + it('keeps persisted sqliteMigrated flag and defaults it to false', async () => { + persistedStateByName.preferences = { + storage: { + sqliteMigrated: true, + }, + } + + const { default: preferences } = await import('../module/preferences') + + expect(preferences.get('storage.sqliteMigrated' as any)).toBe(true) + }) + + it('defaults sqliteMigrated to false for invalid or missing value', async () => { + persistedStateByName.preferences = { + storage: { + sqliteMigrated: 'bad', + }, + } + + const { default: preferences } = await import('../module/preferences') + + expect(preferences.get('storage.sqliteMigrated' as any)).toBe(false) + }) + it('keeps persisted http settings and prunes stale values', async () => { persistedStateByName.preferences = { http: { diff --git a/src/main/store/module/preferences.ts b/src/main/store/module/preferences.ts index 73cd75ba..114462f0 100644 --- a/src/main/store/module/preferences.ts +++ b/src/main/store/module/preferences.ts @@ -58,6 +58,7 @@ const PREFERENCES_DEFAULTS: PreferencesStore = { storage: { rootPath: storagePath, vaultPath: null, + sqliteMigrated: false, }, editor: { code: EDITOR_DEFAULTS, @@ -307,6 +308,10 @@ function sanitizePreferences(value: unknown): PreferencesStore { 'vaultPath', PREFERENCES_DEFAULTS.storage.vaultPath, ), + sqliteMigrated: + typeof storageSource.sqliteMigrated === 'boolean' + ? storageSource.sqliteMigrated + : PREFERENCES_DEFAULTS.storage.sqliteMigrated, }, editor: { code: sanitizeCodeEditorSettings(codeEditorSource), diff --git a/src/main/store/types/index.ts b/src/main/store/types/index.ts index 7e6e43f5..af628c65 100644 --- a/src/main/store/types/index.ts +++ b/src/main/store/types/index.ts @@ -190,6 +190,7 @@ export interface MarkdownSettings { export interface StorageSettings { vaultPath: string | null + sqliteMigrated: boolean } export interface NotesEditorSettings {