(url: string)
| 483 | } |
| 484 | |
| 485 | async function bufferFromImageUrl(url: string): Promise<{ buffer: Buffer; contentType: string }> { |
| 486 | if (url.startsWith('data:')) { |
| 487 | const match = /^data:([^;]+);base64,(.+)$/u.exec(url) |
| 488 | if (!match) throw new Error('Invalid data URI image response') |
| 489 | const buffer = Buffer.from(match[2], 'base64') |
| 490 | assertKnownSizeWithinLimit(buffer.length, MAX_IMAGE_BYTES, 'inline image response') |
| 491 | return { |
| 492 | contentType: match[1], |
| 493 | buffer, |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | const urlValidation = await validateUrlWithDNS(url, 'imageUrl') |
| 498 | if (!urlValidation.isValid || !urlValidation.resolvedIP) { |
| 499 | throw new Error(urlValidation.error || 'Generated image URL failed validation') |
| 500 | } |
| 501 | |
| 502 | const imageResponse = await secureFetchWithPinnedIP(url, urlValidation.resolvedIP, { |
| 503 | method: 'GET', |
| 504 | maxResponseBytes: MAX_IMAGE_BYTES, |
| 505 | }) |
| 506 | if (!imageResponse.ok) { |
| 507 | await readResponseTextWithLimit(imageResponse, { |
| 508 | maxBytes: DEFAULT_MAX_ERROR_BODY_BYTES, |
| 509 | label: 'generated image error response', |
| 510 | }).catch(() => '') |
| 511 | throw new Error(`Failed to download generated image: ${imageResponse.status}`) |
| 512 | } |
| 513 | |
| 514 | const contentType = imageResponse.headers.get('content-type') || 'image/png' |
| 515 | const buffer = await readResponseToBufferWithLimit(imageResponse, { |
| 516 | maxBytes: MAX_IMAGE_BYTES, |
| 517 | label: 'generated image download', |
| 518 | }) |
| 519 | return { buffer, contentType } |
| 520 | } |
| 521 | |
| 522 | async function generateWithOpenAI( |
| 523 | apiKey: string, |
no test coverage detected