diff --git a/src/state/persisted/__tests__/legacy.test.ts b/src/state/persisted/__tests__/legacy.test.ts new file mode 100644 index 0000000000..229e686a9d --- /dev/null +++ b/src/state/persisted/__tests__/legacy.test.ts @@ -0,0 +1,9 @@ +import {expect, test} from '@jest/globals' + +import {transform} from '#/state/persisted/legacy' +import {schema} from '#/state/persisted/schema' + +test('transform', () => { + const data = transform({}) + expect(() => schema.parse(data)).not.toThrow() +}) diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts index d09de2d372..6f2189a957 100644 --- a/src/state/persisted/legacy.ts +++ b/src/state/persisted/legacy.ts @@ -1,7 +1,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage' import {logger} from '#/logger' -import {defaults, Schema} from '#/state/persisted/schema' +import {defaults, Schema, schema} from '#/state/persisted/schema' import {write, read} from '#/state/persisted/store' /** @@ -153,33 +153,44 @@ export async function migrate() { if (!alreadyMigrated && rawLegacyData) { logger.info('persisted state: migrating legacy storage') + const legacyData = JSON.parse(rawLegacyData) const newData = transform(legacyData) - await write(newData) - // track successful migrations - logger.log('persisted state: migrated legacy storage') + const validate = schema.safeParse(newData) + + if (validate.success) { + await write(newData) + logger.log('persisted state: migrated legacy storage') + } else { + logger.error('persisted state: legacy data failed validation', { + error: validate.error, + }) + + /* + * If transformed data fails validation, start from a clean slate with + * the new data structure. + * + * If this fails, there's likely something related to AsyncStorage + * going wrong. + */ + try { + await write(transform({})) + logger.log( + 'persisted state: recovered from legacy validation failure', + ) + } catch (e: any) { + logger.error(e, { + message: 'persisted state: error recovering from legacy migration', + }) + } + } } else { - // track successful migrations logger.log('persisted state: no migration needed') } } catch (e: any) { logger.error(e, { message: 'persisted state: error migrating legacy storage', }) - - /* - * If we fail to migrate, attempt to start from a blank slate with new data - * structure. If this fails, there's likely something related to - * AsyncStorage going wrong. - */ - try { - const newData = transform({}) - await write(newData) - } catch (e: any) { - logger.error(e, { - message: 'persisted state: error recovering from legacy migration', - }) - } } }