diff --git a/web/redux/default-state.js b/web/redux/default-state.js --- a/web/redux/default-state.js +++ b/web/redux/default-state.js @@ -40,7 +40,10 @@ }, windowActive: true, pushApiPublicKey: null, - windowDimensions: { width: window.width, height: window.height }, + windowDimensions: { + width: typeof window !== 'undefined' ? window.width : 0, + height: typeof window !== 'undefined' ? window.height : 0, + }, loadingStatuses: {}, calendarFilters: defaultCalendarFilters, dataLoaded: false, @@ -68,7 +71,7 @@ keyserverStore: { keyserverInfos: { [authoritativeKeyserverID]: defaultKeyserverInfo( - keyserverURL, + typeof keyserverURL !== 'undefined' ? keyserverURL : '', electron?.platform ?? 'web', ), }, diff --git a/web/redux/handle-redux-migration-failure.js b/web/redux/handle-redux-migration-failure.js --- a/web/redux/handle-redux-migration-failure.js +++ b/web/redux/handle-redux-migration-failure.js @@ -4,7 +4,8 @@ import { resetUserSpecificState } from 'lib/utils/reducers-utils.js'; import { defaultWebState } from './default-state.js'; -import { nonUserSpecificFieldsWeb, type AppState } from './redux-setup.js'; +import { nonUserSpecificFieldsWeb } from './persist-constants.js'; +import { type AppState } from './redux-setup.js'; const persistWhitelist = [ 'enabledApps', diff --git a/web/redux/persist.js b/web/redux/migrations.js copy from web/redux/persist.js copy to web/redux/migrations.js --- a/web/redux/persist.js +++ b/web/redux/migrations.js @@ -1,20 +1,15 @@ // @flow import invariant from 'invariant'; -import { getStoredState, purgeStoredState } from 'redux-persist'; -import storage from 'redux-persist/es/storage/index.js'; -import type { PersistConfig } from 'redux-persist/src/types.js'; -import { - type ClientDBKeyserverStoreOperation, - keyserverStoreOpsHandlers, - type ReplaceKeyserverOperation, +import type { + ClientDBKeyserverStoreOperation, + ReplaceKeyserverOperation, } from 'lib/ops/keyserver-store-ops.js'; +import { keyserverStoreOpsHandlers } from 'lib/ops/keyserver-store-ops.js'; import type { ClientDBMessageStoreOperation } from 'lib/ops/message-store-ops.js'; import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; import { patchRawThreadInfoWithSpecialRole } from 'lib/permissions/special-roles.js'; -import { keyserverStoreTransform } from 'lib/shared/transforms/keyserver-store-transform.js'; -import { messageStoreMessagesBlocklistTransform } from 'lib/shared/transforms/message-store-transform.js'; import { defaultAlertInfos } from 'lib/types/alert-types.js'; import { defaultCalendarQuery } from 'lib/types/entry-types.js'; import type { KeyserverInfo } from 'lib/types/keyserver-types.js'; @@ -27,12 +22,13 @@ import type { ClientDBThreadInfo } from 'lib/types/thread-types.js'; import { getConfig } from 'lib/utils/config.js'; import { parseCookies } from 'lib/utils/cookie-utils.js'; -import { isDev } from 'lib/utils/dev-utils.js'; import { - generateIDSchemaMigrationOpsForDrafts, convertDraftStoreToNewIDSchema, - createAsyncMigrate, - type StorageMigrationFunction, + generateIDSchemaMigrationOpsForDrafts, +} from 'lib/utils/migration-utils.js'; +import type { + LegacyMigrationManifest, + MigrationManifest, } from 'lib/utils/migration-utils.js'; import { entries } from 'lib/utils/objects.js'; import { @@ -40,23 +36,16 @@ convertRawThreadInfoToClientDBThreadInfo, } from 'lib/utils/thread-ops-utils.js'; -import commReduxStorageEngine from './comm-redux-storage-engine.js'; -import { - handleReduxMigrationFailure, - persistWhitelist, -} from './handle-redux-migration-failure.js'; -import { rootKey, rootKeyPrefix, storeVersion } from './persist-constants.js'; +import { handleReduxMigrationFailure } from './handle-redux-migration-failure.js'; import type { AppState } from './redux-setup.js'; import { unshimClientDB } from './unshim-utils.js'; import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import { getCommSharedWorker } from '../shared-worker/shared-worker-provider.js'; import { getOlmWasmPath } from '../shared-worker/utils/constants.js'; -import { isSQLiteSupported } from '../shared-worker/utils/db-utils.js'; import { workerRequestMessageTypes } from '../types/worker-types.js'; declare var keyserverURL: string; - -const legacyMigrations = { +const legacyMigrations: LegacyMigrationManifest = { [1]: async (state: any) => { const { primaryIdentityPublicKey, @@ -471,65 +460,11 @@ unshimClientDB(state, [messageTypes.UPDATE_RELATIONSHIP]), }; -const migrateStorageToSQLite: StorageMigrationFunction< - WebNavInfo, - AppState, -> = async debug => { - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - if (!isSupported) { - return undefined; - } - - const oldStorage = await getStoredState({ storage, key: rootKey }); - if (!oldStorage) { - return undefined; - } - - purgeStoredState({ storage, key: rootKey }); - if (debug) { - console.log('redux-persist: migrating state to SQLite storage'); - } - - const allKeys = Object.keys(oldStorage); - const transforms = persistConfig.transforms ?? []; - const newStorage = { ...oldStorage }; - - for (const transform of transforms) { - for (const key of allKeys) { - const transformedStore = transform.out(newStorage[key], key, newStorage); - newStorage[key] = transformedStore; - } - } - - return newStorage; -}; - -const migrations = { - // This migration doesn't change the store but sets a persisted version - // in the DB +const migrations: MigrationManifest = { [75]: (state: AppState) => ({ state, ops: [], }), }; -const persistConfig: PersistConfig = { - keyPrefix: rootKeyPrefix, - key: rootKey, - storage: commReduxStorageEngine, - whitelist: isSQLiteSupported() - ? persistWhitelist - : [...persistWhitelist, 'draftStore'], - migrate: (createAsyncMigrate( - legacyMigrations, - { debug: isDev }, - migrations, - (error: Error, state: AppState) => handleReduxMigrationFailure(state), - migrateStorageToSQLite, - ): any), - version: storeVersion, - transforms: [messageStoreMessagesBlocklistTransform, keyserverStoreTransform], -}; - -export { persistConfig }; +export { migrations, legacyMigrations }; diff --git a/web/redux/persist-constants.js b/web/redux/persist-constants.js --- a/web/redux/persist-constants.js +++ b/web/redux/persist-constants.js @@ -4,5 +4,22 @@ const rootKeyPrefix = 'persist:'; const completeRootKey = `${rootKeyPrefix}${rootKey}`; const storeVersion = 75; +const nonUserSpecificFieldsWeb = [ + 'loadingStatuses', + 'windowDimensions', + 'lifecycleState', + 'windowActive', + 'pushApiPublicKey', + 'keyserverStore', + 'initialStateLoaded', + '_persist', + 'customServer', +]; -export { rootKey, rootKeyPrefix, completeRootKey, storeVersion }; +export { + rootKey, + rootKeyPrefix, + completeRootKey, + storeVersion, + nonUserSpecificFieldsWeb, +}; diff --git a/web/redux/persist.js b/web/redux/persist.js --- a/web/redux/persist.js +++ b/web/redux/persist.js @@ -1,475 +1,28 @@ // @flow -import invariant from 'invariant'; import { getStoredState, purgeStoredState } from 'redux-persist'; import storage from 'redux-persist/es/storage/index.js'; import type { PersistConfig } from 'redux-persist/src/types.js'; -import { - type ClientDBKeyserverStoreOperation, - keyserverStoreOpsHandlers, - type ReplaceKeyserverOperation, -} from 'lib/ops/keyserver-store-ops.js'; -import type { ClientDBMessageStoreOperation } from 'lib/ops/message-store-ops.js'; -import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; -import { patchRawThreadInfoWithSpecialRole } from 'lib/permissions/special-roles.js'; import { keyserverStoreTransform } from 'lib/shared/transforms/keyserver-store-transform.js'; import { messageStoreMessagesBlocklistTransform } from 'lib/shared/transforms/message-store-transform.js'; -import { defaultAlertInfos } from 'lib/types/alert-types.js'; -import { defaultCalendarQuery } from 'lib/types/entry-types.js'; -import type { KeyserverInfo } from 'lib/types/keyserver-types.js'; -import { messageTypes } from 'lib/types/message-types-enum.js'; -import type { ClientDBMessageInfo } from 'lib/types/message-types.js'; import type { WebNavInfo } from 'lib/types/nav-types.js'; -import { cookieTypes } from 'lib/types/session-types.js'; -import { defaultConnectionInfo } from 'lib/types/socket-types.js'; -import { defaultGlobalThemeInfo } from 'lib/types/theme-types.js'; -import type { ClientDBThreadInfo } from 'lib/types/thread-types.js'; -import { getConfig } from 'lib/utils/config.js'; -import { parseCookies } from 'lib/utils/cookie-utils.js'; import { isDev } from 'lib/utils/dev-utils.js'; import { - generateIDSchemaMigrationOpsForDrafts, - convertDraftStoreToNewIDSchema, createAsyncMigrate, type StorageMigrationFunction, } from 'lib/utils/migration-utils.js'; -import { entries } from 'lib/utils/objects.js'; -import { - convertClientDBThreadInfoToRawThreadInfo, - convertRawThreadInfoToClientDBThreadInfo, -} from 'lib/utils/thread-ops-utils.js'; import commReduxStorageEngine from './comm-redux-storage-engine.js'; import { handleReduxMigrationFailure, persistWhitelist, } from './handle-redux-migration-failure.js'; +import { migrations, legacyMigrations } from './migrations.js'; import { rootKey, rootKeyPrefix, storeVersion } from './persist-constants.js'; import type { AppState } from './redux-setup.js'; -import { unshimClientDB } from './unshim-utils.js'; -import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import { getCommSharedWorker } from '../shared-worker/shared-worker-provider.js'; -import { getOlmWasmPath } from '../shared-worker/utils/constants.js'; import { isSQLiteSupported } from '../shared-worker/utils/db-utils.js'; -import { workerRequestMessageTypes } from '../types/worker-types.js'; - -declare var keyserverURL: string; - -const legacyMigrations = { - [1]: async (state: any) => { - const { - primaryIdentityPublicKey, - ...stateWithoutPrimaryIdentityPublicKey - } = state; - return { - ...stateWithoutPrimaryIdentityPublicKey, - cryptoStore: { - primaryAccount: null, - primaryIdentityKeys: null, - notificationAccount: null, - notificationIdentityKeys: null, - }, - }; - }, - [2]: async (state: AppState) => { - return state; - }, - [3]: async (state: AppState) => { - let newState = state; - if (state.draftStore) { - newState = { - ...newState, - draftStore: convertDraftStoreToNewIDSchema(state.draftStore), - }; - } - - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - - if (!isSupported) { - return newState; - } - - const stores = await sharedWorker.schedule({ - type: workerRequestMessageTypes.GET_CLIENT_STORE, - }); - invariant(stores?.store, 'Stores should exist'); - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { - draftStoreOperations: generateIDSchemaMigrationOpsForDrafts( - stores.store.drafts, - ), - }, - }); - - return newState; - }, - [4]: async (state: any) => { - const { lastCommunicatedPlatformDetails, keyserverStore, ...rest } = state; - - return { - ...rest, - keyserverStore: { - ...keyserverStore, - keyserverInfos: { - ...keyserverStore.keyserverInfos, - [authoritativeKeyserverID]: { - ...keyserverStore.keyserverInfos[authoritativeKeyserverID], - lastCommunicatedPlatformDetails, - }, - }, - }, - }; - }, - [5]: async (state: any) => { - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - if (!isSupported) { - return state; - } - - if (!state.draftStore) { - return state; - } - - const { drafts } = state.draftStore; - const draftStoreOperations = []; - for (const key in drafts) { - const text = drafts[key]; - draftStoreOperations.push({ - type: 'update', - payload: { key, text }, - }); - } - - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { draftStoreOperations }, - }); - - return state; - }, - [6]: async (state: AppState) => ({ - ...state, - integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' }, - }), - [7]: async (state: AppState): Promise => { - if (!document.cookie) { - return state; - } - - const params = parseCookies(document.cookie); - let cookie = null; - if (params[cookieTypes.USER]) { - cookie = `${cookieTypes.USER}=${params[cookieTypes.USER]}`; - } else if (params[cookieTypes.ANONYMOUS]) { - cookie = `${cookieTypes.ANONYMOUS}=${params[cookieTypes.ANONYMOUS]}`; - } - - return { - ...state, - keyserverStore: { - ...state.keyserverStore, - keyserverInfos: { - ...state.keyserverStore.keyserverInfos, - [authoritativeKeyserverID]: { - ...state.keyserverStore.keyserverInfos[authoritativeKeyserverID], - cookie, - }, - }, - }, - }; - }, - [8]: async (state: AppState) => ({ - ...state, - globalThemeInfo: defaultGlobalThemeInfo, - }), - [9]: async (state: AppState) => ({ - ...state, - keyserverStore: { - ...state.keyserverStore, - keyserverInfos: { - ...state.keyserverStore.keyserverInfos, - [authoritativeKeyserverID]: { - ...state.keyserverStore.keyserverInfos[authoritativeKeyserverID], - urlPrefix: keyserverURL, - }, - }, - }, - }), - [10]: async (state: AppState) => { - const { keyserverInfos } = state.keyserverStore; - const newKeyserverInfos: { [string]: KeyserverInfo } = {}; - for (const key in keyserverInfos) { - newKeyserverInfos[key] = { - ...keyserverInfos[key], - connection: { ...defaultConnectionInfo }, - updatesCurrentAsOf: 0, - sessionID: null, - }; - } - return { - ...state, - keyserverStore: { - ...state.keyserverStore, - keyserverInfos: newKeyserverInfos, - }, - }; - }, - [11]: async (state: AppState) => { - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - if (!isSupported) { - return state; - } - - const replaceOps: $ReadOnlyArray = entries( - state.keyserverStore.keyserverInfos, - ).map(([id, keyserverInfo]) => ({ - type: 'replace_keyserver', - payload: { - id, - keyserverInfo, - }, - })); - - const keyserverStoreOperations: $ReadOnlyArray = - keyserverStoreOpsHandlers.convertOpsToClientDBOps([ - { type: 'remove_all_keyservers' }, - ...replaceOps, - ]); - - try { - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { keyserverStoreOperations }, - }); - return state; - } catch (e) { - console.log(e); - return handleReduxMigrationFailure(state); - } - }, - [12]: async (state: AppState) => { - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - if (!isSupported) { - return state; - } - const replaceOps: $ReadOnlyArray = entries( - state.keyserverStore.keyserverInfos, - ) - .filter(([, keyserverInfo]) => !keyserverInfo.actualizedCalendarQuery) - .map(([id, keyserverInfo]) => ({ - type: 'replace_keyserver', - payload: { - id, - keyserverInfo: { - ...keyserverInfo, - actualizedCalendarQuery: defaultCalendarQuery( - getConfig().platformDetails.platform, - ), - }, - }, - })); - if (replaceOps.length === 0) { - return state; - } - - const newState = { - ...state, - keyserverStore: keyserverStoreOpsHandlers.processStoreOperations( - state.keyserverStore, - replaceOps, - ), - }; - const keyserverStoreOperations = - keyserverStoreOpsHandlers.convertOpsToClientDBOps(replaceOps); - - try { - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { keyserverStoreOperations }, - }); - return newState; - } catch (e) { - console.log(e); - return handleReduxMigrationFailure(newState); - } - }, - [13]: async (state: any) => { - const { cryptoStore, ...rest } = state; - const sharedWorker = await getCommSharedWorker(); - await sharedWorker.schedule({ - type: workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT, - olmWasmPath: getOlmWasmPath(), - initialCryptoStore: cryptoStore, - }); - return rest; - }, - [14]: async (state: AppState) => { - const sharedWorker = await getCommSharedWorker(); - const isSupported = await sharedWorker.isSupported(); - - if (!isSupported) { - return state; - } - - const stores = await sharedWorker.schedule({ - type: workerRequestMessageTypes.GET_CLIENT_STORE, - }); - const keyserversDBInfo = stores?.store?.keyservers; - if (!keyserversDBInfo) { - return state; - } - - const { translateClientDBData } = keyserverStoreOpsHandlers; - const keyservers = translateClientDBData(keyserversDBInfo); - - // There is no modification of the keyserver data, but the ops handling - // should correctly split the data between synced and non-synced tables - - const replaceOps: $ReadOnlyArray = entries( - keyservers, - ).map(([id, keyserverInfo]) => ({ - type: 'replace_keyserver', - payload: { - id, - keyserverInfo, - }, - })); - - const keyserverStoreOperations: $ReadOnlyArray = - keyserverStoreOpsHandlers.convertOpsToClientDBOps([ - { type: 'remove_all_keyservers' }, - ...replaceOps, - ]); - - try { - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { keyserverStoreOperations }, - }); - return state; - } catch (e) { - console.log(e); - return handleReduxMigrationFailure(state); - } - }, - [15]: (state: any) => { - const { notifPermissionAlertInfo, ...rest } = state; - const newState = { - ...rest, - alertStore: { - alertInfos: defaultAlertInfos, - }, - }; - - return newState; - }, - [16]: async (state: AppState) => { - // 1. Check if `databaseModule` is supported and early-exit if not. - const sharedWorker = await getCommSharedWorker(); - const isDatabaseSupported = await sharedWorker.isSupported(); - - if (!isDatabaseSupported) { - return state; - } - - // 2. Get existing `stores` from SQLite. - const stores = await sharedWorker.schedule({ - type: workerRequestMessageTypes.GET_CLIENT_STORE, - }); - - const messages: ?$ReadOnlyArray = - stores?.store?.messages; - - if (messages === null || messages === undefined || messages.length === 0) { - return state; - } - - // 3. Filter out `UNSUPPORTED.UPDATE_RELATIONSHIP` `ClientDBMessageInfo`s. - const unsupportedMessageIDsToRemove = messages - .filter((message: ClientDBMessageInfo) => { - if (parseInt(message.type) !== messageTypes.UPDATE_RELATIONSHIP) { - return false; - } - if (message.content === null || message.content === undefined) { - return false; - } - const { operation } = JSON.parse(message.content); - return operation === 'farcaster_mutual'; - }) - .map(message => message.id); - - // 4. Construct `ClientDBMessageStoreOperation`s - const messageStoreOperations: $ReadOnlyArray = - [ - { - type: 'remove', - payload: { ids: unsupportedMessageIDsToRemove }, - }, - ]; - - // 5. Process the constructed `messageStoreOperations`. - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { messageStoreOperations }, - }); - - return state; - }, - [17]: async (state: AppState) => { - // 1. Check if `databaseModule` is supported and early-exit if not. - const sharedWorker = await getCommSharedWorker(); - const isDatabaseSupported = await sharedWorker.isSupported(); - - if (!isDatabaseSupported) { - return state; - } - - // 2. Get existing `stores` from SQLite. - const stores = await sharedWorker.schedule({ - type: workerRequestMessageTypes.GET_CLIENT_STORE, - }); - - const threads: ?$ReadOnlyArray = stores?.store?.threads; - - if (threads === null || threads === undefined || threads.length === 0) { - return state; - } - - // 3. Convert to `RawThreadInfo`, patch in `specialRole`, and convert back. - const patchedClientDBThreadInfos: $ReadOnlyArray = - threads - .map(convertClientDBThreadInfoToRawThreadInfo) - .map(patchRawThreadInfoWithSpecialRole) - .map(convertRawThreadInfoToClientDBThreadInfo); - - // 4. Construct operations to remove existing threads and replace them - // with threads that have the `specialRole` field patched in. - const threadStoreOperations: ClientDBThreadStoreOperation[] = []; - threadStoreOperations.push({ type: 'remove_all' }); - for (const clientDBThreadInfo: ClientDBThreadInfo of patchedClientDBThreadInfos) { - threadStoreOperations.push({ - type: 'replace', - payload: clientDBThreadInfo, - }); - } - - // 5. Process the constructed `threadStoreOperations`. - await sharedWorker.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { threadStoreOperations }, - }); - - return state; - }, - [18]: (state: AppState) => - unshimClientDB(state, [messageTypes.UPDATE_RELATIONSHIP]), -}; const migrateStorageToSQLite: StorageMigrationFunction< WebNavInfo, @@ -505,15 +58,6 @@ return newStorage; }; -const migrations = { - // This migration doesn't change the store but sets a persisted version - // in the DB - [75]: (state: AppState) => ({ - state, - ops: [], - }), -}; - const persistConfig: PersistConfig = { keyPrefix: rootKeyPrefix, key: rootKey, diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js --- a/web/redux/redux-setup.js +++ b/web/redux/redux-setup.js @@ -4,15 +4,15 @@ import type { PersistState } from 'redux-persist/es/types.js'; import { - logOutActionTypes, - deleteKeyserverAccountActionTypes, deleteAccountActionTypes, + deleteKeyserverAccountActionTypes, keyserverAuthActionTypes, + logOutActionTypes, } from 'lib/actions/user-actions.js'; import { setNewSessionActionType } from 'lib/keyserver-conn/keyserver-conn-types.js'; import { - type ReplaceKeyserverOperation, keyserverStoreOpsHandlers, + type ReplaceKeyserverOperation, } from 'lib/ops/keyserver-store-ops.js'; import { type ReplaceThreadActivityEntryOperation, @@ -30,16 +30,16 @@ import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { shouldClearData } from 'lib/shared/data-utils.js'; import { - invalidSessionDowngrade, identityInvalidSessionDowngrade, + invalidSessionDowngrade, invalidSessionRecovery, } from 'lib/shared/session-utils.js'; import type { AlertStore } from 'lib/types/alert-types.js'; import type { AuxUserStore } from 'lib/types/aux-user-types.js'; import type { CommunityStore } from 'lib/types/community-types.js'; import type { - MessageSourceMetadata, DBOpsStore, + MessageSourceMetadata, } from 'lib/types/db-ops-types.js'; import type { DraftStore } from 'lib/types/draft-types.js'; import type { EnabledApps } from 'lib/types/enabled-apps.js'; @@ -64,14 +64,15 @@ import { resetUserSpecificState } from 'lib/utils/reducers-utils.js'; import { - updateWindowActiveActionType, + setInitialReduxState, updateNavInfoActionType, + updateWindowActiveActionType, updateWindowDimensionsActionType, - setInitialReduxState, } from './action-types.js'; import { reduceCommunityPickerStore } from './community-picker-reducer.js'; import { defaultWebState } from './default-state.js'; import reduceNavInfo from './nav-reducer.js'; +import { nonUserSpecificFieldsWeb } from './persist-constants.js'; import { onStateDifference } from './redux-debug-utils.js'; import { reduceServicesAccessToken } from './services-access-token-reducer.js'; import { getVisibility } from './visibility.js'; @@ -85,18 +86,6 @@ +calendar: ?string, }; -const nonUserSpecificFieldsWeb = [ - 'loadingStatuses', - 'windowDimensions', - 'lifecycleState', - 'windowActive', - 'pushApiPublicKey', - 'keyserverStore', - 'initialStateLoaded', - '_persist', - 'customServer', -]; - export type AppState = { +navInfo: WebNavInfo, +currentUserInfo: ?CurrentUserInfo, @@ -548,4 +537,4 @@ }; } -export { nonUserSpecificFieldsWeb, reducer }; +export { reducer }; diff --git a/web/shared-worker/worker/backup.js b/web/shared-worker/worker/backup.js --- a/web/shared-worker/worker/backup.js +++ b/web/shared-worker/worker/backup.js @@ -3,12 +3,16 @@ import backupService from 'lib/facts/backup-service.js'; import { decryptCommon } from 'lib/media/aes-crypto-utils-common.js'; import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; +import { syncedMetadataNames } from 'lib/types/synced-metadata-types.js'; +import { runMigrations } from 'lib/utils/migration-utils.js'; import { getProcessingStoreOpsExceptionMessage } from './process-operations.js'; import { BackupClient, RequestedData, } from '../../backup-client-wasm/wasm/backup-client-wasm.js'; +import { defaultWebState } from '../../redux/default-state.js'; +import { legacyMigrations, migrations } from '../../redux/migrations.js'; import { completeRootKey, storeVersion, @@ -75,6 +79,32 @@ throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule)); } }); + + const versionAfterLogsDownload = getStoredVersion(sqliteQueryExecutor); + if (!versionAfterLogsDownload) { + throw new Error('Missing backup version after log download'); + } + const versionNumberAfterLogsDownload = parseInt(versionAfterLogsDownload); + await runMigrations( + legacyMigrations, + migrations, + { + ...defaultWebState, + _persist: { + version: versionNumberAfterLogsDownload, + rehydrated: true, + }, + }, + versionNumberAfterLogsDownload, + storeVersion, + process.env.NODE_ENV !== 'production', + ); +} + +function getStoredVersion(sqliteQueryExecutor: SQLiteQueryExecutor) { + return sqliteQueryExecutor + .getAllSyncedMetadata() + .find(entry => entry.name === syncedMetadataNames.DB_VERSION)?.data; } export { restoreBackup };