import { authStoragePrefix, buildAccountId, loadAccounts, loadActiveAccountId, loadDraftInstanceUrl, saveAccounts, saveActiveAccountId, saveDraftInstanceUrl, type SavedAccount, } from "@/lib/accounts"; import { migrateAuthStorage } from "@/lib/auth-storage"; import { DEFAULT_API_URL } from "@/lib/config"; import { loadStoredInstanceUrl, saveStoredInstanceUrl } from "@/lib/instance-url"; import { clearTimeClockPrefsForAccount, getLastTimeClockClientId, setLastTimeClockClientId, } from "@/lib/time-clock-prefs"; const LEGACY_OFFICIAL_HOSTS = ["beenvoice.soconnor.dev"]; export function isLegacyOfficialUrl(url: string): boolean { const trimmed = url.trim(); if (!trimmed) return false; try { const withProtocol = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`; return LEGACY_OFFICIAL_HOSTS.includes(new URL(withProtocol).host); } catch { const host = trimmed.replace(/^https?:\/\//, "").replace(/\/$/, "").split("/")[0] ?? ""; return LEGACY_OFFICIAL_HOSTS.includes(host); } } export function migrateOfficialUrl(url: string): string { return isLegacyOfficialUrl(url) ? DEFAULT_API_URL : url; } export async function migrateStoredOfficialUrls(): Promise<{ accounts: SavedAccount[]; activeAccountId: string | null; draftUrl: string | null; }> { const [accounts, activeId, draftUrl, storedInstanceUrl] = await Promise.all([ loadAccounts(), loadActiveAccountId(), loadDraftInstanceUrl(), loadStoredInstanceUrl(), ]); let nextActiveId = activeId; const migratedAccounts: SavedAccount[] = []; for (const account of accounts) { if (!isLegacyOfficialUrl(account.instanceUrl)) { migratedAccounts.push(account); continue; } const newUrl = DEFAULT_API_URL; const newId = buildAccountId(newUrl, account.userId); const oldPrefix = authStoragePrefix(account.id); const newPrefix = authStoragePrefix(newId); if (oldPrefix !== newPrefix) { await migrateAuthStorage(oldPrefix, newPrefix); } const lastClientId = await getLastTimeClockClientId(account.id); if (lastClientId && account.id !== newId) { await setLastTimeClockClientId(newId, lastClientId); await clearTimeClockPrefsForAccount(account.id); } migratedAccounts.push({ ...account, id: newId, instanceUrl: newUrl, }); if (nextActiveId === account.id) { nextActiveId = newId; } } const newDraft = draftUrl && isLegacyOfficialUrl(draftUrl) ? DEFAULT_API_URL : draftUrl; const accountsChanged = migratedAccounts.some( (account, index) => account.id !== accounts[index]?.id || account.instanceUrl !== accounts[index]?.instanceUrl, ); const activeChanged = nextActiveId !== activeId; const draftChanged = newDraft !== draftUrl; const instanceChanged = storedInstanceUrl != null && isLegacyOfficialUrl(storedInstanceUrl) && storedInstanceUrl !== DEFAULT_API_URL; if (accountsChanged) await saveAccounts(migratedAccounts); if (activeChanged) await saveActiveAccountId(nextActiveId); if (draftChanged) await saveDraftInstanceUrl(newDraft); if (instanceChanged) await saveStoredInstanceUrl(DEFAULT_API_URL); return { accounts: migratedAccounts, activeAccountId: nextActiveId, draftUrl: newDraft, }; }