about summary refs log tree commit diff
path: root/src/state/persisted
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/persisted')
-rw-r--r--src/state/persisted/__tests__/legacy.test.ts13
-rw-r--r--src/state/persisted/index.ts5
-rw-r--r--src/state/persisted/legacy.ts33
-rw-r--r--src/state/persisted/schema.ts7
4 files changed, 38 insertions, 20 deletions
diff --git a/src/state/persisted/__tests__/legacy.test.ts b/src/state/persisted/__tests__/legacy.test.ts
new file mode 100644
index 000000000..7f4b138a1
--- /dev/null
+++ b/src/state/persisted/__tests__/legacy.test.ts
@@ -0,0 +1,13 @@
+import {expect, test} from '@jest/globals'
+
+import {transform} from '#/state/persisted/legacy'
+import {defaults, schema} from '#/state/persisted/schema'
+
+test('defaults', () => {
+  expect(() => schema.parse(defaults)).not.toThrow()
+})
+
+test('transform', () => {
+  const data = transform({})
+  expect(() => schema.parse(data)).not.toThrow()
+})
diff --git a/src/state/persisted/index.ts b/src/state/persisted/index.ts
index 545fdc0e1..67d8b78c6 100644
--- a/src/state/persisted/index.ts
+++ b/src/state/persisted/index.ts
@@ -26,7 +26,10 @@ export async function init() {
   try {
     await migrate() // migrate old store
     const stored = await store.read() // check for new store
-    if (!stored) await store.write(defaults) // opt: init new store
+    if (!stored) {
+      logger.info('persisted state: initializing default storage')
+      await store.write(defaults) // opt: init new store
+    }
     _state = stored || defaults // return new store
     logger.log('persisted state: initialized')
   } catch (e) {
diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts
index 025877529..c45b18322 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'
 
 /**
@@ -66,7 +66,6 @@ type LegacySchema = {
 
 const DEPRECATED_ROOT_STATE_STORAGE_KEY = 'root'
 
-// TODO remove, assume that partial data may be here during our refactor
 export function transform(legacy: Partial<LegacySchema>): Schema {
   return {
     colorMode: legacy.shell?.colorMode || defaults.colorMode,
@@ -116,7 +115,7 @@ export function transform(legacy: Partial<LegacySchema>): Schema {
  * local storage AND old storage exists.
  */
 export async function migrate() {
-  logger.info('persisted state: migrate')
+  logger.info('persisted state: check need to migrate')
 
   try {
     const rawLegacyData = await AsyncStorage.getItem(
@@ -138,6 +137,7 @@ export async function migrate() {
           ),
         })
         logger.info(`persisted state: debug new data`, {
+          hasNewData: Boolean(newData),
           hasExistingLoggedInAccount: Boolean(newData?.session?.currentAccount),
           numberOfExistingAccounts: newData?.session?.accounts?.length,
           existingAccountMatchesLegacy: Boolean(
@@ -145,27 +145,32 @@ export async function migrate() {
               legacy?.session?.data?.did,
           ),
         })
-      } else {
-        logger.info(`persisted state: no legacy to debug, fresh install`)
       }
-    } catch (e) {
-      logger.error(`persisted state: legacy debugging failed`, {error: e})
+    } catch (e: any) {
+      logger.error(e, {message: `persisted state: legacy debugging failed`})
     }
 
     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,
+        })
+      }
     } else {
-      // track successful migrations
       logger.log('persisted state: no migration needed')
     }
-  } catch (e) {
-    logger.error('persisted state: error migrating legacy storage', {
-      error: String(e),
+  } catch (e: any) {
+    logger.error(e, {
+      message: 'persisted state: error migrating legacy storage',
     })
   }
 }
diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts
index 71f9bd545..5ed8e01f3 100644
--- a/src/state/persisted/schema.ts
+++ b/src/state/persisted/schema.ts
@@ -2,17 +2,14 @@ import {z} from 'zod'
 import {deviceLocales} from '#/platform/detection'
 
 // only data needed for rendering account page
-// TODO agent.resumeSession requires the following fields
 const accountSchema = z.object({
   service: z.string(),
   did: z.string(),
   handle: z.string(),
-  email: z.string(),
-  emailConfirmed: z.boolean(),
+  email: z.string().optional(),
+  emailConfirmed: z.boolean().optional(),
   refreshJwt: z.string().optional(), // optional because it can expire
   accessJwt: z.string().optional(), // optional because it can expire
-  // displayName: z.string().optional(),
-  // aviUrl: z.string().optional(),
 })
 export type PersistedAccount = z.infer<typeof accountSchema>