download.ts

2025/03/11に公開
import axios from 'axios'

export interface IDownloadOptions {
  timeout?: number
  // UI update or logs record
  onCancel?: () => void
}

export interface IDownloadResult {
  cancel: () => void
  download: Promise<Blob>
}

export const createDownload = (url: string, options: IDownloadOptions = {}): IDownloadResult => {
  const { timeout = 1000 * 60 * 5, onCancel } = options
  const abortController = new AbortController()

  const timeoutId = setTimeout(() => {
    abortController.abort()
    onCancel?.()
  }, timeout)

  const download = (async () => {
    try {
      const response = await axios.get<Blob>(url, {
        signal: abortController.signal,
        responseType: 'blob',
      })

      clearTimeout(timeoutId)
      return response.data
    } catch (error) {
      clearTimeout(timeoutId)
      throw error
    }
  })()

  return {
    cancel: () => {
      abortController.abort()
      clearTimeout(timeoutId)
      onCancel?.()
    },
    download,
  }
}

Discussion