tus-js-client-stall-detection
Version:
A pure JavaScript client for the tus resumable upload protocol (fork with stall detection)
141 lines (140 loc) • 5.11 kB
TypeScript
import type { Readable as NodeReadableStream } from 'node:stream';
import type { DetailedError } from './DetailedError.js';
export declare const PROTOCOL_TUS_V1 = "tus-v1";
export declare const PROTOCOL_IETF_DRAFT_03 = "ietf-draft-03";
export declare const PROTOCOL_IETF_DRAFT_05 = "ietf-draft-05";
/**
* ReactNativeFile describes the structure that is returned from the
* Expo image picker (see https://docs.expo.dev/versions/latest/sdk/imagepicker/)
* TODO: Should these properties be fileName and fileSize instead?
* TODO: What about other file pickers without Expo?
* TODO: Should this be renamed to Expo?
* TODO: Only size is relevant for us. Not the rest.
*/
export interface ReactNativeFile {
uri: string;
name?: string;
size?: string;
exif?: Record<string, unknown>;
}
/**
* PathReference is a reference to a file on disk. Currently, it's only supported
* in Node.js. It can be supplied as a normal object or as an instance of `fs.ReadStream`,
* which also statisfies this interface.
*
* Optionally, a start and/or end position can be defined to define a range of bytes from
* the file that should be uploaded instead of the entire file. Both start and end are
* inclusive and start counting at 0, similar to the options accepted by `fs.createReadStream`.
*/
export interface PathReference {
path: string | Buffer;
start?: number;
end?: number;
}
export type UploadInput = Blob | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | ReadableStream | NodeReadableStream | PathReference | ReactNativeFile;
/**
* Options for configuring stall detection behavior
*/
export interface StallDetectionOptions {
enabled: boolean;
stallTimeout: number;
checkInterval: number;
}
export interface UploadOptions {
endpoint?: string;
uploadUrl?: string;
metadata: {
[key: string]: string;
};
metadataForPartialUploads: UploadOptions['metadata'];
fingerprint: (file: UploadInput, options: UploadOptions) => Promise<string | null>;
uploadSize?: number;
onProgress?: (bytesSent: number, bytesTotal: number | null) => void;
onChunkComplete?: (chunkSize: number, bytesAccepted: number, bytesTotal: number | null) => void;
onSuccess?: (payload: OnSuccessPayload) => void;
onError?: (error: Error | DetailedError) => void;
onShouldRetry?: (error: DetailedError, retryAttempt: number, options: UploadOptions) => boolean;
onUploadUrlAvailable?: () => void | Promise<void>;
overridePatchMethod: boolean;
headers: {
[key: string]: string;
};
addRequestId: boolean;
onBeforeRequest?: (req: HttpRequest) => void | Promise<void>;
onAfterResponse?: (req: HttpRequest, res: HttpResponse) => void | Promise<void>;
chunkSize: number;
retryDelays: number[];
parallelUploads: number;
parallelUploadBoundaries?: {
start: number;
end: number;
}[];
storeFingerprintForResuming: boolean;
removeFingerprintOnSuccess: boolean;
uploadLengthDeferred: boolean;
uploadDataDuringCreation: boolean;
urlStorage: UrlStorage;
fileReader: FileReader;
httpStack: HttpStack;
protocol: typeof PROTOCOL_TUS_V1 | typeof PROTOCOL_IETF_DRAFT_03 | typeof PROTOCOL_IETF_DRAFT_05;
stallDetection?: StallDetectionOptions;
}
export interface OnSuccessPayload {
lastResponse: HttpResponse;
}
export interface UrlStorage {
findAllUploads(): Promise<PreviousUpload[]>;
findUploadsByFingerprint(fingerprint: string): Promise<PreviousUpload[]>;
removeUpload(urlStorageKey: string): Promise<void>;
addUpload(fingerprint: string, upload: PreviousUpload): Promise<string | undefined>;
}
export interface PreviousUpload {
size: number | null;
metadata: {
[key: string]: string;
};
creationTime: string;
uploadUrl?: string;
parallelUploadUrls?: string[];
urlStorageKey: string;
}
export interface FileReader {
openFile(input: UploadInput, chunkSize: number): Promise<FileSource>;
}
export interface FileSource {
size: number | null;
slice(start: number, end: number): Promise<SliceResult>;
close(): void;
}
export type SliceType = Blob | ArrayBufferView | NodeReadableStream;
export type SliceResult = {
done: true;
value: null;
size: null;
} | {
done: boolean;
value: NonNullable<SliceType>;
size: number;
};
export interface HttpStack {
createRequest(method: string, url: string): HttpRequest;
getName(): string;
supportsProgressEvents: () => boolean;
}
export type HttpProgressHandler = (bytesSent: number) => void;
export interface HttpRequest {
getMethod(): string;
getURL(): string;
setHeader(header: string, value: string): void;
getHeader(header: string): string | undefined;
setProgressHandler(handler: HttpProgressHandler): void;
send(body?: SliceType): Promise<HttpResponse>;
abort(): Promise<void>;
getUnderlyingObject(): unknown;
}
export interface HttpResponse {
getStatus(): number;
getHeader(header: string): string | undefined;
getBody(): string;
getUnderlyingObject(): unknown;
}