(dataUrl: string)
| 449 | }; |
| 450 | |
| 451 | function parseDataUrl(dataUrl: string): ParsedDataUrl { |
| 452 | if (!dataUrl.startsWith("data:")) throw new Error("Invalid data URL"); |
| 453 | const [header, data] = dataUrl.split(",", 2); |
| 454 | if (data === undefined) throw new Error("Invalid data URL: missing data"); |
| 455 | |
| 456 | const meta = header.slice(5); |
| 457 | let mimeType = "text/plain;charset=US-ASCII"; |
| 458 | const parts = meta.split(";"); |
| 459 | if (parts[0]) mimeType = parts[0]; |
| 460 | const isBase64 = parts.some((p) => p.toLowerCase() === "base64"); |
| 461 | |
| 462 | let buffer: Uint8Array; |
| 463 | if (isBase64) { |
| 464 | buffer = base64ToArray(data); |
| 465 | } else { |
| 466 | // assume text |
| 467 | const decoded = decodeURIComponent(data); |
| 468 | buffer = new TextEncoder().encode(decoded); |
| 469 | } |
| 470 | |
| 471 | return { mimeType, buffer }; |
| 472 | } |
| 473 | |
| 474 | function formatRelativeTime(timestamp: number): string { |
| 475 | if (!timestamp) { |
no test coverage detected