import * as DocumentPicker from "expo-document-picker"; import * as LegacyFileSystem from "expo-file-system/legacy"; import type { CodexAuth } from "@/types/codex"; function sanitizeFileName(name: string): string { return name.replace(/[^a-zA-Z0-9._-]/g, "_"); } async function readPickedTextFile(uri: string, fileName?: string): Promise { try { const response = await fetch(uri); if (!response.ok) { throw new Error(`HTTP_ERROR_${response.status}`); } return await response.text(); } catch { try { return await LegacyFileSystem.readAsStringAsync(uri); } catch { const cacheDirectory = LegacyFileSystem.cacheDirectory; if (!cacheDirectory) { throw new Error("DOCUMENT_NOT_READABLE"); } const destination = `${cacheDirectory}${Date.now()}-${sanitizeFileName( fileName ?? "import.json" )}`; try { await LegacyFileSystem.copyAsync({ from: uri, to: destination }); return await LegacyFileSystem.readAsStringAsync(destination); } catch { throw new Error("DOCUMENT_NOT_READABLE"); } } } } export async function pickAndReadCodexAuth(): Promise { const result = await DocumentPicker.getDocumentAsync({ type: "application/json", copyToCacheDirectory: true, }); if (result.canceled) throw new Error("PICKER_CANCELLED"); const { uri, name } = result.assets[0]; const text = await readPickedTextFile(uri, name); let parsed: Record; try { parsed = JSON.parse(text); } catch { throw new Error("INVALID_JSON"); } const tokens = parsed["tokens"] as Record | undefined; const accessToken = (tokens?.["access_token"] ?? parsed["accessToken"]) as string | undefined; const accountId = ( tokens?.["account_id"] ?? parsed["accountId"] ?? parsed["account_id"] ) as string | undefined; if (!accessToken || typeof accessToken !== "string") { throw new Error("MISSING_ACCESS_TOKEN"); } return { accessToken, accountId }; }