(file: File)
| 946 | // ── Main entry point ─────────────────────────────────────────────── |
| 947 | |
| 948 | export async function extractCard(file: File): Promise<ExtractResult> { |
| 949 | if (file.size > MAX_FILE_SIZE) { |
| 950 | return { |
| 951 | status: 'error', |
| 952 | message: `File too large (${(file.size / 1024 / 1024).toFixed(1)} MB). Maximum allowed size is 50 MB.`, |
| 953 | }; |
| 954 | } |
| 955 | |
| 956 | try { |
| 957 | const buffer = await file.arrayBuffer(); |
| 958 | |
| 959 | let inputType: 'png' | 'charx'; |
| 960 | try { |
| 961 | inputType = detectInputType(file.name, buffer); |
| 962 | } catch { |
| 963 | return { |
| 964 | status: 'error', |
| 965 | message: `Unsupported file type: ${file.name}. Expected PNG or ZIP/CharX.`, |
| 966 | }; |
| 967 | } |
| 968 | |
| 969 | // Parse card |
| 970 | let card: Record<string, unknown>; |
| 971 | try { |
| 972 | if (inputType === 'png') { |
| 973 | card = parsePngCardBytes(buffer); |
| 974 | } else { |
| 975 | card = await parseCharx(buffer); |
| 976 | } |
| 977 | } catch (e) { |
| 978 | return { |
| 979 | status: 'error', |
| 980 | message: `Failed to parse ${inputType} file: ${e instanceof Error ? e.message : String(e)}`, |
| 981 | }; |
| 982 | } |
| 983 | |
| 984 | // Convert entries |
| 985 | const converted = loadEntriesFromCard(card); |
| 986 | const entries: Record<string, InternalEntry> = {}; |
| 987 | for (const { entry, index } of converted) { |
| 988 | entries[String(index)] = entry; |
| 989 | } |
| 990 | |
| 991 | // Extract apps and lore |
| 992 | const apps = extractAppsFromEntries(entries); |
| 993 | const lore = extractLoreEntries(entries); |
| 994 | |
| 995 | // Extract and attach regex scripts |
| 996 | const tagAppMap = buildTagAppMap(apps); |
| 997 | const embeddedScripts = loadRegexScriptsFromCard(card); |
| 998 | const allScripts = normalizeScripts(embeddedScripts, tagAppMap); |
| 999 | attachScriptsToApps(allScripts, apps, tagAppMap); |
| 1000 | |
| 1001 | // Extract character info from card |
| 1002 | const cardData = (card['data'] || {}) as Record<string, unknown>; |
| 1003 | const character: CharacterInfo = { |
| 1004 | name: (cardData['name'] as string) || '', |
| 1005 | description: (cardData['description'] as string) || '', |
no test coverage detected