diff --git a/lib/utils/migration-utils.js b/lib/utils/migration-utils.js --- a/lib/utils/migration-utils.js +++ b/lib/utils/migration-utils.js @@ -191,7 +191,7 @@ threadPermissions.MANAGE_INVITE_LINKS, ]; -type LegacyMigrationManifest = { +export type LegacyMigrationManifest = { +[number | string]: (PersistedState) => Promise, }; type PersistedState = { @@ -204,7 +204,7 @@ export type StorageMigrationFunction = ( debug: boolean, ) => Promise; -type MigrationManifest = { +export type MigrationManifest = { +[number | string]: (PersistedState) => Promise<{ +state: PersistedState, +ops: StoreOperations, diff --git a/native/backup/use-client-backup.js b/native/backup/use-client-backup.js --- a/native/backup/use-client-backup.js +++ b/native/backup/use-client-backup.js @@ -6,10 +6,16 @@ import { accountHasPassword } from 'lib/shared/account-utils.js'; import type { SIWEBackupSecrets } from 'lib/types/siwe-types.js'; import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; +import { runMigrations } from 'lib/utils/migration-utils.js'; import { fetchNativeKeychainCredentials } from '../account/native-credentials.js'; import { commCoreModule } from '../native-modules.js'; -import { persistConfig } from '../redux/persist.js'; +import { defaultState } from '../redux/default-state.js'; +import { + legacyMigrations, + migrations, + persistConfig, +} from '../redux/persist.js'; import { useSelector } from '../redux/redux-utils.js'; type ClientBackup = { @@ -91,10 +97,27 @@ await commCoreModule.restoreBackup(backupSecret); const backupVersion = await commCoreModule.getStoredVersion(); - if (!backupVersion || parseInt(backupVersion) > persistConfig.version) { + const backupVersionNumber = parseInt(backupVersion); + if (!backupVersion || backupVersionNumber > persistConfig.version) { throw new Error(`Incompatible backup version ${backupVersion ?? -1}`); } + console.info('Running backup migrations...'); + await runMigrations( + legacyMigrations, + migrations, + { + ...defaultState, + _persist: { + version: backupVersionNumber, + rehydrated: true, + }, + }, + backupVersionNumber, + persistConfig.version, + process.env.NODE_ENV !== 'production', + ); + console.info('Backup restored.'); }, [currentUserID, loggedIn, setMockCommServicesAuthMetadata]); diff --git a/native/redux/persist.js b/native/redux/persist.js --- a/native/redux/persist.js +++ b/native/redux/persist.js @@ -103,6 +103,8 @@ convertMessageStoreThreadsToNewIDSchema, convertThreadStoreThreadInfosToNewIDSchema, createAsyncMigrate, + type LegacyMigrationManifest, + type MigrationManifest, } from 'lib/utils/migration-utils.js'; import { entries } from 'lib/utils/objects.js'; import { @@ -137,7 +139,7 @@ import { isTaskCancelledError } from '../utils/error-handling.js'; import { defaultURLPrefix } from '../utils/url-utils.js'; -const legacyMigrations = { +const legacyMigrations: LegacyMigrationManifest = { [1]: (state: AppState) => ({ ...state, notifPermissionAlertInfo: defaultAlertInfo, @@ -1305,7 +1307,7 @@ { whitelist: ['reportStore'] }, ); -const migrations = { +const migrations: MigrationManifest = { [75]: (state: AppState) => ({ state, ops: [], @@ -1345,4 +1347,11 @@ return storedPersistor; } -export { persistConfig, codeVersion, setPersistor, getPersistor }; +export { + persistConfig, + codeVersion, + setPersistor, + getPersistor, + migrations, + legacyMigrations, +};