/** * Range-aware download and resumable upload helpers. * * `downloadResumable(misina, url, opts)` issues a Range-aware GET that * can resume after a network failure: it probes the server's * `Accept-Ranges: bytes` advertisement, fetches the body in chunks, * and re-issues the next chunk with `Range: bytes=N-` after a failure. * Falls back to a single streaming GET when the server doesn't * advertise byte ranges. * * `uploadResumable(misina, url, source, opts)` follows * draft-ietf-httpbis-resumable-upload: a `POST` opens the upload, the * server returns the upload location, and the client `PATCH`'es chunks * with `Upload-Offset`. The final chunk carries `Upload-Incomplete: ?0` * to signal completion. On reconnect after a network failure, a `HEAD` * to the upload location returns the server's known offset, which the * client uses to skip already-received bytes. * * Both helpers integrate with `onProgress` so callers can render UI * across pause/resume boundaries. */ import type { Misina } from "../types.mjs"; export interface DownloadProgress { loaded: number; total: number | undefined; percent: number; } export interface DownloadResumableOptions { /** Bytes per range request. Default: 4 MiB. */ chunkSize?: number; /** Total max retry attempts per chunk before giving up. Default: 3. */ maxRetries?: number; /** Progress callback invoked across pause/resume boundaries. */ onProgress?: (progress: DownloadProgress) => void; /** External abort signal — pauses the download. */ signal?: AbortSignal; /** * Resume from this byte offset. Caller passes the offset they have * already persisted (e.g. partial file size). Default: 0. */ startOffset?: number; } export interface ResumableDownloadResult { /** Concatenated body as a Blob. */ blob: Blob; /** Final size in bytes (== blob.size). */ size: number; /** True when the server advertised byte ranges and chunks were used. */ ranged: boolean; } /** * Download a resource with byte-range resume support. Probes * `Accept-Ranges: bytes` and `Content-Length` via a HEAD; if either is * missing or the server doesn't support ranges, falls back to a single * streaming GET. */ export declare function downloadResumable(misina: Misina, url: string, options?: DownloadResumableOptions): Promise; export interface UploadProgress { loaded: number; total: number; percent: number; } export interface UploadResumableOptions { /** Bytes per PATCH. Default: 4 MiB. */ chunkSize?: number; /** * Existing upload location from a previous attempt. When set, the * helper sends `HEAD` to recover the offset and resumes from there. * When unset, the helper opens a new upload via `POST` to `url`. */ uploadUrl?: string; /** Progress callback invoked after each PATCH. */ onProgress?: (progress: UploadProgress) => void; /** External abort signal — pauses the upload. */ signal?: AbortSignal; /** Max retries per chunk before failing. Default: 3. */ maxRetries?: number; } export interface ResumableUploadResult { /** Final upload location (Location header from POST or the input). */ uploadUrl: string; /** Bytes uploaded across the lifetime of this call. */ uploaded: number; } /** * Resumable upload following draft-ietf-httpbis-resumable-upload. The * source must expose a `byteLength` (Uint8Array, ArrayBuffer, Blob). * * Protocol: * 1. `POST url` opens the upload. The server returns the upload * location in `Location`. * 2. The client sends `PATCH ` with `Upload-Offset`, * `Content-Type: application/partial-upload`, and a chunk of bytes. * The final chunk carries `Upload-Incomplete: ?0` to signal end. * 3. On a network failure mid-upload, the client reissues `HEAD * ` to recover the server's known offset and retries the * next chunk from there. * * Pass `uploadUrl` from a previous (interrupted) attempt to resume * without a fresh POST. */ export declare function uploadResumable(misina: Misina, url: string, source: Uint8Array | ArrayBuffer | Blob, options?: UploadResumableOptions): Promise;