this repo has no description
1import type { 2 MigrationDirection, 3 MigrationState, 4 StoredMigrationState, 5} from "./types"; 6import { clearDPoPKey } from "./atproto-client"; 7 8const STORAGE_KEY = "tranquil_migration_state"; 9const MAX_AGE_MS = 24 * 60 * 60 * 1000; 10 11export function saveMigrationState(state: MigrationState): void { 12 const storedState: StoredMigrationState = { 13 version: 1, 14 direction: state.direction, 15 step: state.direction === "inbound" ? state.step : state.step, 16 startedAt: new Date().toISOString(), 17 sourcePdsUrl: state.direction === "inbound" 18 ? state.sourcePdsUrl 19 : globalThis.location.origin, 20 targetPdsUrl: state.direction === "inbound" 21 ? globalThis.location.origin 22 : state.targetPdsUrl, 23 sourceDid: state.direction === "inbound" ? state.sourceDid : "", 24 sourceHandle: state.direction === "inbound" ? state.sourceHandle : "", 25 targetHandle: state.targetHandle, 26 targetEmail: state.targetEmail, 27 authMethod: state.direction === "inbound" ? state.authMethod : undefined, 28 passkeySetupToken: state.direction === "inbound" 29 ? state.passkeySetupToken ?? undefined 30 : undefined, 31 progress: { 32 repoExported: state.progress.repoExported, 33 repoImported: state.progress.repoImported, 34 blobsTotal: state.progress.blobsTotal, 35 blobsMigrated: state.progress.blobsMigrated, 36 prefsMigrated: state.progress.prefsMigrated, 37 plcSigned: state.progress.plcSigned, 38 }, 39 lastError: state.error ?? undefined, 40 lastErrorStep: state.error ? state.step : undefined, 41 }; 42 43 try { 44 localStorage.setItem(STORAGE_KEY, JSON.stringify(storedState)); 45 } catch { /* localStorage unavailable */ } 46} 47 48export function loadMigrationState(): StoredMigrationState | null { 49 try { 50 const stored = localStorage.getItem(STORAGE_KEY); 51 if (!stored) return null; 52 53 const state = JSON.parse(stored) as StoredMigrationState; 54 55 if (state.version !== 1) { 56 clearMigrationState(); 57 return null; 58 } 59 60 const startedAt = new Date(state.startedAt).getTime(); 61 if (Date.now() - startedAt > MAX_AGE_MS) { 62 clearMigrationState(); 63 return null; 64 } 65 66 return state; 67 } catch { 68 clearMigrationState(); 69 return null; 70 } 71} 72 73export function clearMigrationState(): void { 74 try { 75 localStorage.removeItem(STORAGE_KEY); 76 clearDPoPKey(); 77 } catch { /* localStorage unavailable */ } 78} 79 80export function hasPendingMigration(): boolean { 81 return loadMigrationState() !== null; 82} 83 84export function getResumeInfo(): { 85 direction: MigrationDirection; 86 sourceHandle: string; 87 targetHandle: string; 88 sourcePdsUrl: string; 89 targetPdsUrl: string; 90 targetEmail: string; 91 authMethod?: "password" | "passkey"; 92 progressSummary: string; 93 step: string; 94} | null { 95 const state = loadMigrationState(); 96 if (!state) return null; 97 98 const progressParts: string[] = []; 99 if (state.progress.repoExported) progressParts.push("repo exported"); 100 if (state.progress.repoImported) progressParts.push("repo imported"); 101 if (state.progress.blobsMigrated > 0) { 102 progressParts.push( 103 `${state.progress.blobsMigrated}/${state.progress.blobsTotal} blobs`, 104 ); 105 } 106 if (state.progress.prefsMigrated) progressParts.push("preferences migrated"); 107 if (state.progress.plcSigned) progressParts.push("PLC signed"); 108 109 return { 110 direction: state.direction, 111 sourceHandle: state.sourceHandle, 112 targetHandle: state.targetHandle, 113 sourcePdsUrl: state.sourcePdsUrl, 114 targetPdsUrl: state.targetPdsUrl, 115 targetEmail: state.targetEmail, 116 authMethod: state.authMethod, 117 progressSummary: progressParts.length > 0 118 ? progressParts.join(", ") 119 : "just started", 120 step: state.step, 121 }; 122} 123 124export function updateProgress( 125 updates: Partial<StoredMigrationState["progress"]>, 126): void { 127 const state = loadMigrationState(); 128 if (!state) return; 129 130 state.progress = { ...state.progress, ...updates }; 131 try { 132 localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); 133 } catch { /* localStorage unavailable */ } 134} 135 136export function updateStep(step: string): void { 137 const state = loadMigrationState(); 138 if (!state) return; 139 140 state.step = step; 141 try { 142 localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); 143 } catch { /* localStorage unavailable */ } 144} 145 146export function setError(error: string, step: string): void { 147 const state = loadMigrationState(); 148 if (!state) return; 149 150 state.lastError = error; 151 state.lastErrorStep = step; 152 try { 153 localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); 154 } catch { /* localStorage unavailable */ } 155}