| 243 | // ── Input detection ──────────────────────────────────────────────── |
| 244 | |
| 245 | function detectInputType(fileName: string, buffer: ArrayBuffer): 'png' | 'charx' { |
| 246 | const ext = fileName.split('.').pop()?.toLowerCase(); |
| 247 | if (ext === 'png') return 'png'; |
| 248 | if (ext === 'charx' || ext === 'zip') return 'charx'; |
| 249 | |
| 250 | // Fallback: magic bytes |
| 251 | const bytes = new Uint8Array(buffer.slice(0, 8)); |
| 252 | if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) { |
| 253 | return 'png'; |
| 254 | } |
| 255 | if (bytes[0] === 0x50 && bytes[1] === 0x4b && bytes[2] === 0x03 && bytes[3] === 0x04) { |
| 256 | return 'charx'; |
| 257 | } |
| 258 | |
| 259 | throw new Error(`Cannot detect input type for: ${fileName}`); |
| 260 | } |
| 261 | |
| 262 | // ── Card entry conversion ────────────────────────────────────────── |
| 263 | |