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