-
-
Notifications
You must be signed in to change notification settings - Fork 98
/
progress.ts
87 lines (83 loc) · 2.95 KB
/
progress.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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> = () => {
function transformMiddleware(state: Record<any, any>) : ConfiguredMiddleware {
return 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 (state.progress) {
state.progress(loaded, total)
}
controller.enqueue(chunk)
}
})
return new Response(response.body.pipeThrough(transform), response)
} catch (e) {
return response
}
})
}
}
return {
beforeRequest(wretch, _, state) {
return wretch.middlewares([transformMiddleware(state)])
},
resolver: {
progress(onProgress: (loaded: number, total: number) => void) {
this._sharedState.progress = onProgress
return this
}
},
}
}
export default progress