type DownloadUrl = string | URL; type DownloadRequest = { url: DownloadUrl; } & RequestInit; type DownloadInput = DownloadUrl | DownloadRequest | Request | Promise; type DownloadFetchCallback = () => Promise; declare class DownloadTaskError extends Error { readonly task: DownloadTask; constructor(msg: string, task: DownloadTask); } declare enum DownloadTaskState { error = -1, init = 0, fetching = 1, reading = 2, complete = 3 } type DownloadTaskProcessCallback = (task: DownloadTask) => void | Promise; type DownloadTaskProcessOptions = { onFetch?: DownloadTaskProcessCallback; onHeaders?: DownloadTaskProcessCallback; onProgress?: DownloadTaskProcessCallback; onComplete?: DownloadTaskProcessCallback; onError?: DownloadTaskProcessCallback; }; declare class DownloadTask { #private; /** * 创建 {@link DownloadTask} 实例,允许多种 input 类型 * * ```ts * // URL 输入 * const task1 = new DownloadTask('url'); * const task2 = new DownloadTask(new URL('url')); * * // Request or DownloadRequest 结构 * const task3 = new DownloadTask(new Request('url')); * const task4 = new DownloadTask({ url: 'url' }); * * // Promise * const abort = new AbortController(); * const task5 = new DownloadTask(fetch('url', { signal: abort.signal })); * * // Response * const task6 = new DownloadTask(await fetch('url')); * ``` * * 下载的目标 url ,必须要输出有效的 `content-length`,否则将会抛出异常 * * @param input */ constructor(input: DownloadInput | Response); protected _initFetch: (input: DownloadInput) => void; /** * {@link DownloadTask} Id * * 用于给 {@link DownloadTask} 的 Key 使用 */ get id(): string; /** * 获取 response */ get resp(): Response | undefined; /** * 当前状态 {@link DownloadTaskState} */ get state(): DownloadTaskState; /** * 获取 Response Content-Length */ get contentLength(): number; /** * 获取 Response Content-Encoding */ get encoding(): string | null; /** * 获取 Response Content-Type */ get mimeType(): string | null; /** * 实际接收内容的大小 */ get size(): number; /** * Response 是否经过压缩(基于 Content-Encoding 判定) */ get isCompressed(): boolean; /** * 强制指定 compressed ,针对一些特殊的场合使用 * * @param isCompressed */ setCompressed: (isCompressed?: boolean) => this; /** * 已接收 Response body 大小 */ get received(): number; /** * 接收 Response body 进度小数(0 - 1) */ get progress(): number; /** * 接收 Response body 进度百分比(0 - 100) */ get percent(): number; /** * 获取 Response body 的 chunks */ get chunks(): Uint8Array | undefined; /** * 是否开始 read */ get isStarted(): boolean; /** * 是否已经读取(完毕) Response body */ get isReaded(): boolean; /** * 获取错误信息 */ get error(): unknown; /** * read 完成时间戳 * * - 如果下载未开始,返回 0 * - 如果下载已开始,但并未下载完成,则会返回当前时间的时间戳 */ get completeTs(): number; /** * read 数据经过多少时间(毫秒) * * 如果为实际完成,则返回当前时间的时间戳 * * 如果未开始,则返回 0 */ get elapsedMs(): number; /** * 接收速度,单位为字节/秒,需要自行转换 * * 如果未开始,返回 0 * * ```ts * import { filesize } from 'filesize'; * * const task = await fetchDownload().read(); * * console.log(`${filesize(task.speed, { bits: true })}/s`); // kbit/s * console.log(`${filesize(task.speed)}/s`); // KB/s * ``` */ get speed(): number; /** * read response body(下载) * * 主要的流程: * * 1. 如果创建 {@link DownloadTask} 实例时输入的非 Response 实例 {@link DownloadInput} * 会创建一个函数去 fetch 输入(主要是 fetch headers,如果传入的是 Response 实例,则跳过这一步)。 * - `onFetch` 对应 fetch 前 * 2. 解析 `Response.headers`,并提取 `content-length`、`content-type`、`content-encoding`, * 其中 `content-length` 为必须的(缺失或小于或等于0时将抛出错误)。 * - `onHeaders` * 3. `stream.read` 实际开始下载 * - `onProgress` 每一次接收 chunk 流 * - `onComplete` 下载完成 * - `onError` 出错时 * * 默认状态下,任意错误都会抛出异常,可通过 `opts.isNotThrow` 为 `true` 禁用抛出异常。 * * ```ts * const task = new DownloadTask('download_url'); * await task.read({ * onFetch: () => {}, // fetch 前 * onHeaders: () => {}, // 读取 headers 时,stream read 之前 * onProgress: () => {}, // 每一次接收 chunk 流时 * onComplete: () => {}, // 下载完成时 * onError: () => {}, // 出错时 * }); * ``` * * @param opts */ read: (opts?: DownloadTaskProcessCallback | DownloadTaskProcessOptions) => Promise; /** * 根据压缩后文件大小,推算出未压缩前的文件大小 * * 文本内容的压缩率,实际取决于源内容的重复率,所以无法一概而论。 * 这里只是尽可能放大压缩后的尺寸,以取得一个较为接近的值 * * @param compressedSize 压缩后的文件大小 */ inferUncompressedSize: (compressedSize: number) => number; newErr: (msg: string) => DownloadTaskError; } declare class DownloadQueueError extends Error { readonly queue: DownloadQueue; constructor(msg: string, queue: DownloadQueue); } type DownloadQueueInput = DownloadInput | Response | DownloadTask; type DownloadQueueProcessCallback = (queue: DownloadQueue, task: DownloadTask) => void | Promise; type DownloadQueueProcessOptions = { onFetch?: DownloadQueueProcessCallback; onHeaders?: DownloadQueueProcessCallback; onProgress?: DownloadQueueProcessCallback; onComplete?: DownloadQueueProcessCallback; onError?: DownloadQueueProcessCallback; onFinish?: (queue: DownloadQueue) => void | Promise; onQueueError?: (queue: DownloadQueue) => void | Promise; }; declare class DownloadQueue { #private; /** * 创建 {@link DownloadQueue} 实例,允许多种 input 类型 * * ```ts * // DownloadTask * const task1 = new DownloadQueue([new DownloadTask('url')]); * const task2 = new DownloadQueue([fetchDownload('url')]); * * // URL 输入 * const task3 = new DownloadQueue(['url']); * const task4 = new DownloadQueue([new URL('url')]); * * // Request or DownloadRequest 结构 * const task5 = new DownloadQueue([new Request('url')]); * const task6 = new DownloadQueue([{ url: 'url' }]); * * // Promise * const abort = new AbortController(); * const task7 = new DownloadQueue([ * fetch('url', { signal: abort.signal }), * ]); * * // Response * const task8 = new DownloadTask([ * await fetch('url'), * ]); * ``` * * @param tasks */ constructor(tasks: DownloadQueueInput[]); /** * {@link DownloadQueue} Id */ get id(): string; /** * 所有下载任务 */ get tasks(): DownloadTask[]; /** * 所有下载任务的总数 */ get tasksCount(): number; /** * 当前状态 {@link DownloadTaskState} * * 注意 {@link DownloadQueue} 不应该出现 `fetching` 状态 */ get state(): DownloadTaskState; /** * 所有下载任务的实际总大小 */ get size(): number; /** * 所有下载任务的 Content-Length 总和 */ get contentLength(): number; /** * 所有下载任务的已接收 Response body 大小 */ get received(): number; /** * 所有下载任务的接收 Response body 进度小数(0 - 1) */ get progress(): number; /** * 所有下载任务的接收 Response body 进度百分比(0 - 100) */ get percent(): number; /** * 是否开始 read */ get isStarted(): boolean; /** * 是否已经 read 完毕 */ get isReaded(): boolean; /** * 获取错误信息 */ get error(): unknown; /** * read 完成时间戳(所有下载任务都完成) * * - 如果下载未开始,返回 0 * - 如果下载已开始,但并未下载完成,则会返回当前时间的时间戳 */ get completeTs(): number; /** * read 数据经过多少时间(毫秒,所有下载任务都完成) * * 如果为实际完成,则返回当前时间的时间戳 * * 如果未开始,则返回 0 */ get elapsedMs(): number; /** * 接收速度(所有下载任务的平均值),单位为字节/秒,需要自行转换 * * 如果未开始,返回 0 * * ```ts * import { filesize } from 'filesize'; * * const task = await fetchDownload().read(); * * console.log(`${filesize(task.speed, { bits: true })}/s`); // kbit/s * console.log(`${filesize(task.speed)}/s`); // KB/s * ``` */ get speed(): number; protected _initTasksQueue: (opts?: DownloadQueueProcessOptions) => Promise[]; reduce: (fn: (acc: T, it: DownloadTask) => T, initValue: T) => T; /** * Queue 读取方法(调用每一个 task 的 read) * * 1. `onFetch`、`onHeaders`、`onProgress`、`onComplete`、`onError` 保留对应每一个 task 的事件 * 2. `onFinish` 对应 Queue 全部 tasks 读取完毕 * 3. `onQueueError` 对应 Queue 任意一个 task 读取过程中出错 * * @param opts */ read: (opts?: DownloadQueueProcessCallback | DownloadQueueProcessOptions) => Promise; newErr: (msg: string) => DownloadQueueError; } /** * 创建 {@link DownloadTask} 或 {@link DownloadQueue} 的快捷方法 * * ```ts * // DownloadTask * const task = fetchDownload('url'); * * // DownloadQueue * const queue = fetchDownload(['url-a', 'url-b', 'url-c']); * ``` * * @param input */ declare const fetchDownload: (input: T) => R; /** * 将 chunks 保存到本机,该方法只可在浏览器中执行 * * ```ts * const task = fetchDownload('url'); * await task.read(); * * saveChunks(task.chunks, 'test.js'); * ``` * * @param chunks * @param filename * @param mimeType */ declare const saveChunks: (chunks: Uint8Array, filename: string | (() => string), mimeType?: string | null) => void; export { DownloadQueue, DownloadQueueError, DownloadTask, DownloadTaskError, DownloadTaskState, fetchDownload, saveChunks }; export type { DownloadFetchCallback, DownloadInput, DownloadQueueInput, DownloadQueueProcessCallback, DownloadQueueProcessOptions, DownloadRequest, DownloadTaskProcessCallback, DownloadTaskProcessOptions, DownloadUrl };