-
-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Partially solves #154
- Loading branch information
Showing
2 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import type { ConfiguredMiddleware, WretchAddon, WretchResponseChain } from "../types.js" | ||
|
||
export interface ProgressResolver { | ||
/** | ||
* Provides a way to register a callback to be invoked one or multiple times during the download. | ||
* The callback receives the current progress as two arguments, the number of bytes loaded and the total number of bytes to load. | ||
* | ||
* _Under the hood: this method adds a middleware to the chain that will intercept the response and replace the body with a new one that will emit the progress event._ | ||
* | ||
* ```js | ||
* import ProgressAddon from "wretch/addons/progress" | ||
* | ||
* wretch("some_url") | ||
* // Register the addon | ||
* .addon(ProgressAddon()) | ||
* .get() | ||
* // Log the progress as a percentage of completion | ||
* .progress((loaded, total) => console.log(`${(loaded / total * 100).toFixed(0)}%`)) | ||
* ``` | ||
* | ||
* @param onProgress - A callback that will be called one or multiple times with the number of bytes loaded and the total number of bytes to load. | ||
*/ | ||
progress: <T, C extends ProgressResolver, R>( | ||
this: C & WretchResponseChain<T, C, R>, | ||
onProgress: (loaded: number, total: number) => void | ||
) => this | ||
} | ||
|
||
/** | ||
* Adds the ability to monitor progress when downloading a response. | ||
* | ||
* _Compatible with all platforms implementing the [TransformStream WebAPI](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream#browser_compatibility)._ | ||
* | ||
* ```js | ||
* import ProgressAddon from "wretch/addons/progress" | ||
* | ||
* wretch("some_url") | ||
* // Register the addon | ||
* .addon(ProgressAddon()) | ||
* .get() | ||
* // Log the progress as a percentage of completion | ||
* .progress((loaded, total) => console.log(`${(loaded / total * 100).toFixed(0)}%`)) | ||
* ``` | ||
*/ | ||
const progress: () => WretchAddon<unknown, ProgressResolver> = () => { | ||
const cb = { | ||
ref: null | ||
} | ||
|
||
const transformMiddleware: ConfiguredMiddleware = next => (url, opts) => { | ||
let loaded = 0 | ||
let total = 0 | ||
return next(url, opts).then(response => { | ||
try { | ||
const contentLength = response.headers.get("content-length") | ||
total = contentLength ? +contentLength : null | ||
const transform = new TransformStream({ | ||
transform(chunk, controller) { | ||
loaded += chunk.length | ||
if (total < loaded) { | ||
total = loaded | ||
} | ||
if (cb.ref) { | ||
cb.ref(loaded, total) | ||
} | ||
controller.enqueue(chunk) | ||
} | ||
}) | ||
return new Response(response.body.pipeThrough(transform), response) | ||
} catch (e) { | ||
return response | ||
} | ||
}) | ||
} | ||
|
||
return { | ||
beforeRequest(wretch) { | ||
return wretch._middlewares.push(transformMiddleware) | ||
}, | ||
resolver: { | ||
progress(onProgress: (loaded: number, total: number) => void) { | ||
cb.ref = onProgress | ||
return this | ||
} | ||
}, | ||
} | ||
} | ||
|
||
export default progress |