enlarge-file-upload
Version:
A tool for chunked file upload with concurrency control.
256 lines (244 loc) • 6.07 kB
TypeScript
// index.d.ts
import { CancelToken } from "axios";
/**
* 自定义哈希计算的返回结果:
* - hash: 当前文件整体hash值(字符串)
* - hashMap: 一个 Map,用于存储每个分片的哈希值
*/
type HashResult = Promise<{
hash: string;
hashMap: Map<number, string>;
}>;
/**
* 流式计算模式:
* - 参数:
* - chunk: 当前分片的二进制数据
* - index: 当前分片的索引
* - 返回:
* - 一个 Promise,解析为 HashResult
*/
type ChunkHashFn = (chunk: Blob, index: number) => HashResult;
/**
* 单次计算模式:
* - 参数:
* - file: 完整文件对象
* - 返回:
* - 一个 Promise,解析为 HashResult
*/
type FileHashFn = (file: File) => HashResult;
export interface UploadOptions {
/**
* 当前分片数据
* @example new Blob([file.slice(0, chunkSize)])
*/
chunk: Blob;
/**
* 当前分片索引(从0开始计数的绝对位置,包含起始偏移量)
* @example 如果设定 startOffset=3,则实际索引范围是 [3,4,5...]
*/
index: number;
/**
* 文件的唯一哈希值
* @example "sha256-xxxxxx"
*/
hash: string | null;
/**
* 用于取消请求的 axios 取消令牌
* @example axios.CancelToken.source().token
*/
cancelToken: CancelToken;
}
export interface Config {
/**
* 【必需】分片上传处理函数
* @example ({ chunk, index, hash }) => axios.post(uploadUrl, formData)
*/
uploadFunction: (options: UploadOptions) => Promise<void>;
/**
* 【可选】分片大小(字节),默认为 5MB
* @default 5 * 1024 * 1024
*/
chunkSize?: number;
/**
* 【可选】起始分片位置索引(用于断点续传),默认从第一个分片开始
* @example 3 (从第4个分片开始)
*/
startOffset?: number;
/**
* 【可选】指定要上传的分片索引数组(优先级高于 startOffset)
* @example [0,2,3] (仅上传索引为0、2、3的分片)
*/
includeChunks?: number[];
/**
* 【可选】上传失败时的最大重试次数,默认 3 次
* @default 3
*/
maxRetries?: number;
/**
* 【可选】最大并发请求数,默认 5
* @default 5
*/
concurrency?: number;
/**
* 【可选】是否计算文件哈希,默认 false 不计算hash值
* @default false
*/
hash?: boolean;
/**
* 【可选】指定计算hash所需要的webworker线程数
* @default 系统CPU核心数 - 2
*/
threads?: number;
/**
* 【可选】是否等待哈希计算完成再上传,默认 true
* @default true
*/
awaitHash?: boolean;
/**
* 可选】自定义计算哈希函数:
* 支持两种模式:
* 1. 直接传入整体文件的哈希函数
* 2. 传入一个对象,启用 流式计算 模式:
* - flow: 是否启用分片流式处理(chunk)模式
* - calculationHash: 分片级哈希函数
*/
customHash?:
| FileHashFn
| {
flow: Boolean;
calculationHash: ChunkHashFn;
};
/**
* 【可选】是否计算所有切片hash,默认 false
* @default false
*/
chunkMap?: boolean | { async: boolean; indices?: number[] };
/**
* 【回调】开始计算哈希时触发
*/
beginHash?: () => void;
/**
* 【回调】哈希计算完成后触发,返回最终哈希值
*/
endHash?: (hash: string) => void;
/**
* 【回调】上传进度变化时触发,返回 0-100 的数值
*/
onProgress?: (progress: number) => void;
/**
* 【回调】实时上传速度变化时触发,返回带有单位的字符串
* @example "2.45 MB/s"
*/
onSpeed?: (speed: string) => void;
/**
* 【回调】全部分片上传完成且合并成功时触发
*/
onSuccess?: () => void;
}
export interface State {
/**
* 上传进度百分比 (0-100)
*/
progress: number;
/**
* 当前实时上传速度(包含单位)
* @example "1.23 MB/s"
*/
speed: string;
/**
* 是否已完成上传
*/
uploadEnd: boolean;
/**
* 文件哈希值(基于分片内容的 SHA256)
*/
hash: string;
/**
* 当前上传的原始 File 对象
*/
file: File | null;
/**
* 总分片数(包含偏移量分片)
*/
totalChunks: number;
/**
* 上传错误信息
*/
errorMsg: Error | null;
/**
* 所有切片
*/
allChunks: [];
/**
* 所有切片hashMap(需要开启计算才有,默认不开启)
*/
hashMap: Map<number, string>;
}
export interface Uploader {
/**
* 启动文件上传
* @param file - 要上传的浏览器 File 对象
* @throws 分片初始化失败/上传过程中出现未处理错误
*/
upload: (file: File) => Promise<void>;
/**
* 暂停上传(会取消正在传输的请求)
*/
pause: () => void;
/**
* 恢复暂停的上传(从断点继续)
* @throws 未初始化分片时调用会报错
*/
resume: () => Promise<void>;
/**
* 重置所有状态到初始值(相当于重新初始化)
* - 清理所有分片数据
* - 取消所有进行中的请求
* - 清理定时器和缓存数据
* - 重置进度到 0%
*/
reset: () => void;
/**
* 实时状态对象,可通过监听相关属性实现响应式更新
*/
state: State;
}
// 定义基础上传配置接口,只保留核心配置项
export interface CheckerConfig
extends Omit<
Config,
| "startOffset"
| "concurrency"
| "maxRetries"
| "includeChunks"
| "onProgress"
| "onSpeed"
| "onSuccess"
| "uploadFunction"
| "customHash"
> {}
// checker 函数的返回类型
export interface CheckerResult {
/**
* 所有切片hashMap
*/
chunkHashMap: Map<number, string>;
/**
* 文件哈希值
*/
hash: string;
/**
* 总分片数
*/
totalChunks: number;
/**
* 所有切片
*/
allChunks: Blob[];
}
declare function createUploader(config: Config): Uploader;
declare function checker(
file: File,
config: CheckerConfig
): Promise<CheckerResult>;
export { createUploader, checker };