( attachment: File, config: FilesApiConfig, )
| 218 | * @returns Download result with success/failure status |
| 219 | */ |
| 220 | export async function downloadAndSaveFile( |
| 221 | attachment: File, |
| 222 | config: FilesApiConfig, |
| 223 | ): Promise<DownloadResult> { |
| 224 | const { fileId, relativePath } = attachment |
| 225 | const fullPath = buildDownloadPath(getCwd(), config.sessionId, relativePath) |
| 226 | |
| 227 | if (!fullPath) { |
| 228 | return { |
| 229 | fileId, |
| 230 | path: '', |
| 231 | success: false, |
| 232 | error: `Invalid file path: ${relativePath}`, |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | try { |
| 237 | // Download the file content |
| 238 | const content = await downloadFile(fileId, config) |
| 239 | |
| 240 | // Ensure the parent directory exists |
| 241 | const parentDir = path.dirname(fullPath) |
| 242 | await fs.mkdir(parentDir, { recursive: true }) |
| 243 | |
| 244 | // Write the file |
| 245 | await fs.writeFile(fullPath, content) |
| 246 | |
| 247 | logDebug(`Saved file ${fileId} to ${fullPath} (${content.length} bytes)`) |
| 248 | |
| 249 | return { |
| 250 | fileId, |
| 251 | path: fullPath, |
| 252 | success: true, |
| 253 | bytesWritten: content.length, |
| 254 | } |
| 255 | } catch (error) { |
| 256 | logDebugError(`Failed to download file ${fileId}: ${errorMessage(error)}`) |
| 257 | if (error instanceof Error) { |
| 258 | logError(error) |
| 259 | } |
| 260 | |
| 261 | return { |
| 262 | fileId, |
| 263 | path: fullPath, |
| 264 | success: false, |
| 265 | error: errorMessage(error), |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | // Default concurrency limit for parallel downloads |
| 271 | const DEFAULT_CONCURRENCY = 5 |
no test coverage detected