Axios が responseType: 'stream' を指定した Node リクエストを解決した時点で、ボディは消費可能になっています。しかしファイルはまだ完成していません。保存先への転送を待ってください:

import { createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';

const response = await client.get(url, { responseType: 'stream' });
await pipeline(response.data, createWriteStream(partPath));

これは設定済みのクライアントを使います。そのアダプターが選択したプロキシまたは SOCKS エージェントに対応している必要があります。Axios の組み込み HTTP プロキシオプションと SOCKS エージェントは別々の仕組みです。URL、タイムアウト、キャンセルポリシーはアプリケーションが指定します。

この操作が所有する一時パスを使ってください。書き込みストリームを作る前に衝突の扱いを決めておきましょう。そうすれば失敗後の後片付けが他人のファイルを削除してしまうことはありません。意図的な再開には独自のポリシーが必要です。

pipeline は読み取りと書き込みを調整し、その失敗を報告します。response.data.pipe(file) を呼んで即座に成功をログに出すと、この完了点を飛ばしてしまいます。有効な HTTP レスポンスが届いた後でも、ネットワークの切断やディスクの満杯は起こり得ます。レスポンスの文脈と、処理を止めたエラーを保持してください。

待っていた処理が成功したら、アプリケーションの 成果物チェック を行い、それから最終的な名前を公開します。完了とは、この API の下でストリームが消費され書き込まれたという意味であり、期待したリリースやドキュメントであるという意味ではありません。失敗やキャンセルの際は、選んだ再開ポリシーに従って部分ファイルを保持または削除します。キャンセルシグナルは該当するリクエストとストリーム操作を停止できますが、出力をどう扱うかは決めません。

関連記事