* Handle external URL. * * Always fetches the URL fresh — there is no filename-based dedup. Distinct URLs * commonly share a path tail (e.g. every Slack clipboard paste is `image.png`), * so keying a cache by filename returns stale bytes. `fetchExternalUrlToWorkspace` * delegates to `uploadWork
( url: string, fileType: string, workspaceId: string, userId: string, executionContext?: ExecutionContext, headers?: Record<string, string>, signal?: AbortSignal, maxDownloadBytes = MAX_DOWNLOAD_SIZE_BYTES, maxParsedOutputBytes?: number )
| 478 | * style aliases for files we already own). |
| 479 | */ |
| 480 | async function handleExternalUrl( |
| 481 | url: string, |
| 482 | fileType: string, |
| 483 | workspaceId: string, |
| 484 | userId: string, |
| 485 | executionContext?: ExecutionContext, |
| 486 | headers?: Record<string, string>, |
| 487 | signal?: AbortSignal, |
| 488 | maxDownloadBytes = MAX_DOWNLOAD_SIZE_BYTES, |
| 489 | maxParsedOutputBytes?: number |
| 490 | ): Promise<ParseResult> { |
| 491 | try { |
| 492 | logger.info('Fetching external URL:', url) |
| 493 | |
| 494 | const { |
| 495 | S3_EXECUTION_FILES_CONFIG, |
| 496 | BLOB_EXECUTION_FILES_CONFIG, |
| 497 | USE_S3_STORAGE, |
| 498 | USE_BLOB_STORAGE, |
| 499 | } = await import('@/lib/uploads/config') |
| 500 | |
| 501 | let isExecutionFile = false |
| 502 | try { |
| 503 | const parsedUrl = new URL(url) |
| 504 | |
| 505 | if (USE_S3_STORAGE && S3_EXECUTION_FILES_CONFIG.bucket) { |
| 506 | const bucketInHost = parsedUrl.hostname.startsWith(S3_EXECUTION_FILES_CONFIG.bucket) |
| 507 | const bucketInPath = parsedUrl.pathname.startsWith(`/${S3_EXECUTION_FILES_CONFIG.bucket}/`) |
| 508 | isExecutionFile = bucketInHost || bucketInPath |
| 509 | } else if (USE_BLOB_STORAGE && BLOB_EXECUTION_FILES_CONFIG.containerName) { |
| 510 | isExecutionFile = url.includes(`/${BLOB_EXECUTION_FILES_CONFIG.containerName}/`) |
| 511 | } |
| 512 | } catch (error) { |
| 513 | logger.warn('Failed to parse URL for execution file check:', error) |
| 514 | isExecutionFile = false |
| 515 | } |
| 516 | |
| 517 | const { filename, buffer, mimeType } = await fetchExternalUrlToWorkspace({ |
| 518 | url, |
| 519 | userId, |
| 520 | workspaceId: workspaceId || undefined, |
| 521 | saveToWorkspace: Boolean(workspaceId) && !isExecutionFile, |
| 522 | headers, |
| 523 | signal, |
| 524 | maxDownloadBytes, |
| 525 | timeoutMs: DOWNLOAD_TIMEOUT_MS, |
| 526 | }) |
| 527 | const extension = path.extname(filename).toLowerCase().substring(1) |
| 528 | |
| 529 | logger.info(`Downloaded file from URL: ${url}, size: ${buffer.length} bytes`) |
| 530 | |
| 531 | let userFile: UserFile | undefined |
| 532 | if (executionContext) { |
| 533 | try { |
| 534 | userFile = await uploadExecutionFile(executionContext, buffer, filename, mimeType, userId) |
| 535 | logger.info(`Stored file in execution storage: ${filename}`, { key: userFile.key }) |
| 536 | } catch (uploadError) { |
| 537 | logger.warn('Failed to store file in execution storage:', uploadError) |
no test coverage detected