import * as SecureStore from "expo-secure-store"; import { authStoragePrefix, buildAccountId } from "@/lib/accounts"; import { normalizeSecureStoreKey } from "@/lib/secure-store-keys"; export const GUEST_AUTH_STORAGE_PREFIX = "beenvoice:guest"; const CHUNK_MARKER = "\u0001ba-chunks:"; const AUTH_STORAGE_SUFFIXES = ["_cookie", "_session_data", "_last_login_method"] as const; function storageKeyForPrefix(prefix: string, suffix: (typeof AUTH_STORAGE_SUFFIXES)[number]) { return normalizeSecureStoreKey(`${prefix}${suffix}`); } async function copySecureStoreEntry(fromKey: string, toKey: string): Promise { const value = await SecureStore.getItemAsync(fromKey); if (value == null) return; await SecureStore.setItemAsync(toKey, value); if (!value.startsWith(CHUNK_MARKER)) return; const count = Number(value.slice(CHUNK_MARKER.length)); if (!Number.isInteger(count) || count < 1) return; for (let i = 0; i < count; i += 1) { const chunk = await SecureStore.getItemAsync(`${fromKey}.${i}`); if (chunk != null) { await SecureStore.setItemAsync(`${toKey}.${i}`, chunk); } } } export async function migrateAuthStorage(fromPrefix: string, toPrefix: string): Promise { if (fromPrefix === toPrefix) return; await Promise.all( AUTH_STORAGE_SUFFIXES.map((suffix) => copySecureStoreEntry(storageKeyForPrefix(fromPrefix, suffix), storageKeyForPrefix(toPrefix, suffix)), ), ); } export async function clearAuthStorage(prefix: string): Promise { await Promise.all( AUTH_STORAGE_SUFFIXES.map(async (suffix) => { const key = storageKeyForPrefix(prefix, suffix); const value = await SecureStore.getItemAsync(key); if (value?.startsWith(CHUNK_MARKER)) { const count = Number(value.slice(CHUNK_MARKER.length)); if (Number.isInteger(count) && count > 0) { await Promise.all( Array.from({ length: count }, (_, index) => SecureStore.deleteItemAsync(`${key}.${index}`), ), ); } } await SecureStore.deleteItemAsync(key); }), ); } /** Clears guest auth storage before signing into an additional account. */ export async function prepareForAdditionalSignIn(): Promise { await clearAuthStorage(GUEST_AUTH_STORAGE_PREFIX); } export async function finalizeAuthenticatedAccount(input: { apiUrl: string; userId: string; email: string; name: string; activeAccountId: string | null; registerAccount: (input: { instanceUrl: string; userId: string; email: string; name: string; }) => Promise; }): Promise { const accountId = buildAccountId(input.apiUrl, input.userId); const targetPrefix = authStoragePrefix(accountId); const sourcePrefix = input.activeAccountId ? authStoragePrefix(input.activeAccountId) : GUEST_AUTH_STORAGE_PREFIX; await migrateAuthStorage(sourcePrefix, targetPrefix); await input.registerAccount({ instanceUrl: input.apiUrl, userId: input.userId, email: input.email, name: input.name, }); }