* Download MCPB file from URL
( url: string, destPath: string, onProgress?: ProgressCallback, )
| 480 | * Download MCPB file from URL |
| 481 | */ |
| 482 | async function downloadMcpb( |
| 483 | url: string, |
| 484 | destPath: string, |
| 485 | onProgress?: ProgressCallback, |
| 486 | ): Promise<Uint8Array> { |
| 487 | logForDebugging(`Downloading MCPB from ${url}`) |
| 488 | if (onProgress) { |
| 489 | onProgress(`Downloading ${url}...`) |
| 490 | } |
| 491 | |
| 492 | const started = performance.now() |
| 493 | let fetchTelemetryFired = false |
| 494 | try { |
| 495 | const response = await axios.get(url, { |
| 496 | timeout: 120000, // 2 minute timeout |
| 497 | responseType: 'arraybuffer', |
| 498 | maxRedirects: 5, // Follow redirects (like curl -L) |
| 499 | onDownloadProgress: progressEvent => { |
| 500 | if (progressEvent.total && onProgress) { |
| 501 | const percent = Math.round( |
| 502 | (progressEvent.loaded / progressEvent.total) * 100, |
| 503 | ) |
| 504 | onProgress(`Downloading... ${percent}%`) |
| 505 | } |
| 506 | }, |
| 507 | }) |
| 508 | |
| 509 | const data = new Uint8Array(response.data) |
| 510 | // Fire telemetry before writeFile — the event measures the network |
| 511 | // fetch, not disk I/O. A writeFile EACCES would otherwise match |
| 512 | // classifyFetchError's /permission denied/ → misreport as auth. |
| 513 | logPluginFetch('mcpb', url, 'success', performance.now() - started) |
| 514 | fetchTelemetryFired = true |
| 515 | |
| 516 | // Save to disk (binary data) |
| 517 | await writeFile(destPath, Buffer.from(data)) |
| 518 | |
| 519 | logForDebugging(`Downloaded ${data.length} bytes to ${destPath}`) |
| 520 | if (onProgress) { |
| 521 | onProgress('Download complete') |
| 522 | } |
| 523 | |
| 524 | return data |
| 525 | } catch (error) { |
| 526 | if (!fetchTelemetryFired) { |
| 527 | logPluginFetch( |
| 528 | 'mcpb', |
| 529 | url, |
| 530 | 'failure', |
| 531 | performance.now() - started, |
| 532 | classifyFetchError(error), |
| 533 | ) |
| 534 | } |
| 535 | const errorMsg = errorMessage(error) |
| 536 | const fullError = new Error( |
| 537 | `Failed to download MCPB file from ${url}: ${errorMsg}`, |
| 538 | ) |
| 539 | logError(fullError) |
no test coverage detected