Skip to content

Commit 00e41e6

Browse files
authored
Merge pull request #26 from 9swampy/features/OverrideOptions
Introduce overrideOptions and progress JSDocs annotations.
2 parents f8f2ae8 + 2bfe77c commit 00e41e6

File tree

3 files changed

+94
-56
lines changed

3 files changed

+94
-56
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ export default function App() {
7676

7777
- An object with the following keys:
7878

79-
| key | description | arguments |
80-
| ------------ | -------------------------------- | --------------------------------------------------------- |
81-
| size | size in bytes | n/a |
82-
| elapsed | elapsed time in seconds | n/a |
83-
| percentage | percentage in string | n/a |
84-
| download | download function handler | (downloadUrl: string, filename: string, timeout?: number) |
85-
| cancel | cancel function handler | n/a |
86-
| error | error object from the request | n/a |
87-
| isInProgress | boolean denoting download status | n/a |
79+
| key | description | arguments |
80+
| ------------ | -------------------------------- | ------------------------------------------------------------------------------------------------- |
81+
| size | size in bytes | n/a |
82+
| elapsed | elapsed time in seconds | n/a |
83+
| percentage | percentage in string | n/a |
84+
| download | download function handler | (downloadUrl: string, filename: string, timeout?: number, overrideOptions?: UseDownloaderOptions) |
85+
| cancel | cancel function handler | n/a |
86+
| error | error object from the request | n/a |
87+
| isInProgress | boolean denoting download status | n/a |
8888

8989
```jsx
9090
const { size, elapsed, percentage, download, cancel, error, isInProgress } =

src/index.ts

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,74 +8,86 @@ import {
88
UseDownloaderOptions,
99
} from './types';
1010

11+
/**
12+
*
13+
* @param param0
14+
* @returns
15+
*/
1116
export const resolver =
1217
({
1318
setSize,
1419
setControllerCallback,
1520
setPercentageCallback,
1621
setErrorCallback,
1722
}: ResolverProps) =>
18-
(response: Response): Response => {
19-
if (!response.ok) {
20-
throw Error(`${response.status} ${response.type} ${response.statusText}`);
21-
}
23+
(response: Response): Response => {
24+
if (!response.ok) {
25+
throw Error(`${response.status} ${response.type} ${response.statusText}`);
26+
}
2227

23-
if (!response.body) {
24-
throw Error('ReadableStream not yet supported in this browser.');
25-
}
28+
if (!response.body) {
29+
throw Error('ReadableStream not yet supported in this browser.');
30+
}
2631

27-
const responseBody = response.body;
32+
const responseBody = response.body;
2833

29-
const contentEncoding = response.headers.get('content-encoding');
30-
const contentLength = response.headers.get(
31-
contentEncoding ? 'x-file-size' : 'content-length'
32-
);
34+
const contentEncoding = response.headers.get('content-encoding');
35+
const contentLength = response.headers.get(
36+
contentEncoding ? 'x-file-size' : 'content-length'
37+
);
3338

34-
const total = parseInt(contentLength || '0', 10);
39+
const total = parseInt(contentLength || '0', 10);
3540

36-
setSize(() => total);
41+
setSize(() => total);
3742

38-
let loaded = 0;
43+
let loaded = 0;
3944

40-
const stream = new ReadableStream<Uint8Array>({
41-
start(controller) {
42-
setControllerCallback(controller);
45+
const stream = new ReadableStream<Uint8Array>({
46+
start(controller) {
47+
setControllerCallback(controller);
4348

44-
const reader = responseBody.getReader();
49+
const reader = responseBody.getReader();
4550

46-
async function read(): Promise<void> {
47-
return reader
48-
.read()
49-
.then(({ done, value }) => {
50-
if (done) {
51-
return controller.close();
52-
}
51+
async function read(): Promise<void> {
52+
return reader
53+
.read()
54+
.then(({ done, value }) => {
55+
if (done) {
56+
return controller.close();
57+
}
5358

54-
loaded += value?.byteLength || 0;
59+
loaded += value?.byteLength || 0;
5560

56-
if (value) {
57-
controller.enqueue(value);
58-
}
61+
if (value) {
62+
controller.enqueue(value);
63+
}
5964

60-
setPercentageCallback({ loaded, total });
65+
setPercentageCallback({ loaded, total });
6166

62-
return read();
63-
})
64-
.catch((error: Error) => {
65-
setErrorCallback(error);
66-
reader.cancel('Cancelled');
67+
return read();
68+
})
69+
.catch((error: Error) => {
70+
setErrorCallback(error);
71+
reader.cancel('Cancelled');
6772

68-
return controller.error(error);
69-
});
70-
}
73+
return controller.error(error);
74+
});
75+
}
7176

72-
return read();
73-
},
74-
});
77+
return read();
78+
},
79+
});
7580

76-
return new Response(stream);
77-
};
81+
return new Response(stream);
82+
};
7883

84+
/**
85+
*
86+
* @param {Blob} data
87+
* @param {string} filename
88+
* @param {string} mime
89+
* @returns
90+
*/
7991
export const jsDownload = (
8092
data: Blob,
8193
filename: string,
@@ -118,12 +130,17 @@ export const jsDownload = (
118130
}, 200);
119131
};
120132

133+
/**
134+
* Initialise a new instance of downloader.
135+
* @param {UseDownloaderOptions} options
136+
* @returns UseDownloader
137+
*/
121138
export default function useDownloader(
122139
options: UseDownloaderOptions = {}
123140
): UseDownloader {
124141
let debugMode = false;
125142
try {
126-
debugMode = process ? !!process?.env?.REACT_APP_DEBUG_MODE : false;
143+
debugMode = process ? !!process?.env?.REACT_APP_DEBUG_MODE : false;
127144
} catch {
128145
debugMode = false;
129146
}
@@ -182,7 +199,7 @@ export default function useDownloader(
182199
}, [setControllerCallback]);
183200

184201
const handleDownload: DownloadFunction = useCallback(
185-
async (downloadUrl, filename, timeout = 0) => {
202+
async (downloadUrl, filename, timeout = 0, overrideOptions = {}) => {
186203
if (isInProgress) return null;
187204

188205
clearAllStateCallback();
@@ -208,6 +225,7 @@ export default function useDownloader(
208225
return fetch(downloadUrl, {
209226
method: 'GET',
210227
...options,
228+
...overrideOptions,
211229
signal: fetchController.signal,
212230
})
213231
.then(resolverWithProgress)

src/types.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ export type ErrorMessage = {
44
errorMessage: string;
55
} | null;
66

7+
/**
8+
* Initiate the download of the specified asset from the specified url. Optionally supply timeout and overrideOptions.
9+
* @example await download('https://example.com/file.zip', 'file.zip')
10+
* @example await download('https://example.com/file.zip', 'file.zip', 500) timeouts after 500ms
11+
* @example await download('https://example.com/file.zip', 'file.zip', undefined, { method: 'GET' }) skips optional timeout but supplies overrideOptions
12+
*/
713
export type DownloadFunction = (
814
/** Download url
915
* @example https://upload.wikimedia.org/wikipedia/commons/4/4d/%D0%93%D0%BE%D0%B2%D0%B5%D1%80%D0%BB%D0%B0_%D1%96_%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D1%81_%D0%B2_%D0%BF%D1%80%D0%BE%D0%BC%D1%96%D0%BD%D1%8F%D1%85_%D0%B2%D1%80%D0%B0%D0%BD%D1%96%D1%88%D0%BD%D1%8C%D0%BE%D0%B3%D0%BE_%D1%81%D0%BE%D0%BD%D1%86%D1%8F.jpg
@@ -14,9 +20,23 @@ export type DownloadFunction = (
1420
*/
1521
filename: string,
1622
/** Optional timeout to download items */
17-
timeout?: number
23+
timeout?: number,
24+
/** Optional options to supplement and/or override UseDownloader options */
25+
overrideOptions?: UseDownloaderOptions
1826
) => Promise<void | null>;
1927

28+
/**
29+
* Provides access to Downloader functionality and settings.
30+
*
31+
* @interface EditDialogField
32+
* @field {number} size in bytes.
33+
* @field {number} elapsed time in seconds.
34+
* @field {number} percentage in string
35+
* @field {DownloadFunction} download function handler
36+
* @field {void} cancel function handler
37+
* @field {ErrorMessage} error object from the request
38+
* @field {boolean} isInProgress boolean flag denoting download status
39+
*/
2040
export interface UseDownloader {
2141
/** Size in bytes */
2242
size: number;

0 commit comments

Comments
 (0)