diff --git a/electron/src/rt/sqlite-migrations.ts b/electron/src/rt/sqlite-migrations.ts index 5cb29c6b..75962933 100644 --- a/electron/src/rt/sqlite-migrations.ts +++ b/electron/src/rt/sqlite-migrations.ts @@ -323,6 +323,31 @@ const parseSQL = (sql: string): ParsedSQL => { return result; }; +// Add version conflict detection +const validateMigrationVersions = (migrations: Migration[]): void => { + const versions = new Set(); + const duplicates = new Set(); + + migrations.forEach(migration => { + if (versions.has(migration.version)) { + duplicates.add(migration.version); + } + versions.add(migration.version); + }); + + if (duplicates.size > 0) { + throw new Error(`Duplicate migration versions found: ${Array.from(duplicates).join(', ')}`); + } + + // Verify versions are sequential + const sortedVersions = Array.from(versions).sort((a, b) => a - b); + for (let i = 0; i < sortedVersions.length; i++) { + if (sortedVersions[i] !== i + 1) { + throw new Error(`Migration versions must be sequential. Found gap at version ${i + 1}`); + } + } +}; + // Initial migration for accounts table const INITIAL_MIGRATION: Migration = { version: 1, @@ -357,24 +382,10 @@ const INITIAL_MIGRATION: Migration = { const MIGRATIONS: Migration[] = [ INITIAL_MIGRATION, { - version: 1, - name: 'initial_schema', - description: 'Initial database schema with accounts, secret, settings, contacts, logs, and temp tables', + version: 2, + name: '002_secret_and_settings', + description: 'Add secret, settings, contacts, logs, and temp tables', sql: ` - -- Accounts table for user identities - CREATE TABLE IF NOT EXISTS accounts ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dateCreated TEXT NOT NULL, - derivationPath TEXT, - did TEXT NOT NULL, - identityEncrBase64 TEXT, -- encrypted & base64-encoded - mnemonicEncrBase64 TEXT, -- encrypted & base64-encoded - passkeyCredIdHex TEXT, - publicKeyHex TEXT NOT NULL - ); - - CREATE INDEX IF NOT EXISTS idx_accounts_did ON accounts(did); - -- Secret table for storing encryption keys -- Note: This is a temporary solution until better secure storage is implemented CREATE TABLE IF NOT EXISTS secret ( @@ -447,7 +458,6 @@ const MIGRATIONS: Migration[] = [ ); `, rollback: ` - DROP TABLE IF EXISTS accounts; DROP TABLE IF EXISTS secret; DROP TABLE IF EXISTS settings; DROP TABLE IF EXISTS contacts; @@ -457,6 +467,9 @@ const MIGRATIONS: Migration[] = [ } ]; +// Validate migrations before export +validateMigrationVersions(MIGRATIONS); + // Helper functions const verifyPluginState = async (plugin: any): Promise => { try { @@ -1004,6 +1017,9 @@ export async function runMigrations( ): Promise { logger.info('Starting migration process'); + // Validate migrations before running + validateMigrationVersions(MIGRATIONS); + // Verify plugin is available if (!await verifyPluginState(plugin)) { throw new Error('SQLite plugin not available');