(url: string, dest: string, onProgress?: (pct: number) => void)
| 102 | } |
| 103 | |
| 104 | async function downloadFile(url: string, dest: string, onProgress?: (pct: number) => void): Promise<void> { |
| 105 | const res = await fetch(url, { signal: AbortSignal.timeout(120_000) }); |
| 106 | if (!res.ok) throw new CLIError(`Download failed: ${res.status} ${res.statusText}`, ExitCode.GENERAL); |
| 107 | |
| 108 | const total = Number(res.headers.get('content-length') ?? 0); |
| 109 | let received = 0; |
| 110 | |
| 111 | const writer = createWriteStream(dest); |
| 112 | const reader = res.body!.getReader(); |
| 113 | |
| 114 | await new Promise<void>((resolve, reject) => { |
| 115 | writer.on('error', reject); |
| 116 | const pump = async () => { |
| 117 | try { |
| 118 | while (true) { |
| 119 | const { done, value } = await reader.read(); |
| 120 | if (done) { writer.end(); break; } |
| 121 | writer.write(value); |
| 122 | received += value.length; |
| 123 | if (onProgress && total > 0) onProgress(Math.round(received / total * 100)); |
| 124 | } |
| 125 | resolve(); |
| 126 | } catch (e) { reject(e); } |
| 127 | }; |
| 128 | pump(); |
| 129 | }); |
| 130 | } |
| 131 | |
| 132 | export async function resolveUpdateTarget(channel: Channel): Promise<UpdateTarget> { |
| 133 | const platform = await detectPlatform(); |
no test coverage detected