@anmiles/downloader 4.0.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +8 -5
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/downloader.d.ts +7 -7
- package/dist/lib/downloader.d.ts.map +1 -1
- package/dist/lib/downloader.js +7 -7
- package/dist/lib/downloader.js.map +1 -1
- package/jest.config.js +3 -11
- package/package.json +54 -49
- package/src/index.ts +2 -0
- package/src/lib/__tests__/downloader.test.ts +21 -31
- package/src/lib/downloader.ts +16 -16
- package/tsconfig.build.json +2 -2
- package/tsconfig.json +5 -5
- package/.github/workflows/ci.yml +0 -94
package/.eslintrc.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
root
|
|
2
|
+
root : true,
|
|
3
|
+
|
|
3
4
|
extends : [
|
|
4
|
-
'./node_modules/@anmiles/eslint-config
|
|
5
|
+
'./node_modules/@anmiles/eslint-config/src/base.preset.js',
|
|
6
|
+
'./node_modules/@anmiles/eslint-config/src/ts.preset.js',
|
|
7
|
+
'./node_modules/@anmiles/eslint-config/src/jest.preset.js',
|
|
5
8
|
],
|
|
9
|
+
|
|
6
10
|
ignorePatterns : [
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'dist/',
|
|
11
|
+
'coverage',
|
|
12
|
+
'dist',
|
|
10
13
|
],
|
|
11
14
|
};
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [5.0.0](../../tags/v5.0.0) - 2024-03-16
|
|
9
|
+
### Changed
|
|
10
|
+
- Update eslint config and raise minimum supported NodeJS version to match one in typescript-eslint plugin
|
|
11
|
+
- Update .npmignore
|
|
12
|
+
- Unify jest.config.js by removing redundant patterns and providing support for both ts and tsx
|
|
13
|
+
|
|
8
14
|
## [4.0.2](../../tags/v4.0.2) - 2024-01-31
|
|
9
15
|
### Changed
|
|
10
16
|
- Migrate to GitHub
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0BAA0B;;;AAE1B,+CAA0E;AAAjE,sGAAA,QAAQ,OAAA;AAAE,4GAAA,cAAc,OAAA;AAAE,0GAAA,YAAY,OAAA"}
|
package/dist/lib/downloader.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
type BufferEncoding = Parameters<Buffer['toString']>[0];
|
|
3
|
+
declare function download(url: string): Promise<Buffer>;
|
|
4
|
+
declare function download(url: string, file: string, options?: {
|
|
5
|
+
append?: boolean;
|
|
6
|
+
}): Promise<undefined>;
|
|
7
|
+
declare function downloadString(url: string, encoding?: BufferEncoding): Promise<string>;
|
|
8
|
+
declare function downloadJSON(url: string, encoding?: BufferEncoding): Promise<unknown>;
|
|
2
9
|
export { download, downloadString, downloadJSON };
|
|
3
10
|
declare const _default: {
|
|
4
11
|
download: typeof download;
|
|
@@ -6,11 +13,4 @@ declare const _default: {
|
|
|
6
13
|
downloadJSON: typeof downloadJSON;
|
|
7
14
|
};
|
|
8
15
|
export default _default;
|
|
9
|
-
type BufferEncoding = Parameters<Buffer['toString']>[0];
|
|
10
|
-
declare function download(url: string): Promise<Buffer>;
|
|
11
|
-
declare function download(url: string, file: string, options?: {
|
|
12
|
-
append?: boolean;
|
|
13
|
-
}): Promise<void>;
|
|
14
|
-
declare function downloadString(url: string, encoding?: BufferEncoding): Promise<string>;
|
|
15
|
-
declare function downloadJSON(url: string, encoding?: BufferEncoding): Promise<any>;
|
|
16
16
|
//# sourceMappingURL=downloader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../../src/lib/downloader.ts"],"names":[],"mappings":";AAOA,
|
|
1
|
+
{"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../../src/lib/downloader.ts"],"names":[],"mappings":";AAOA,KAAK,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAExD,iBAAS,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAChD,iBAAS,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAG,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAgDlG,iBAAe,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,cAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7F;AAED,iBAAe,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,cAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,CAG5F;AAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;;;;;;AAClD,wBAA0D"}
|
package/dist/lib/downloader.js
CHANGED
|
@@ -9,8 +9,7 @@ const http_1 = __importDefault(require("http"));
|
|
|
9
9
|
const https_1 = __importDefault(require("https"));
|
|
10
10
|
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
|
11
11
|
const downloader_1 = __importDefault(require("./downloader"));
|
|
12
|
-
|
|
13
|
-
function download(url, file, options) {
|
|
12
|
+
async function download(url, file, options) {
|
|
14
13
|
return new Promise((resolve, reject) => {
|
|
15
14
|
let protocol;
|
|
16
15
|
if (url.startsWith('https://')) {
|
|
@@ -20,7 +19,7 @@ function download(url, file, options) {
|
|
|
20
19
|
protocol = http_1.default;
|
|
21
20
|
}
|
|
22
21
|
else {
|
|
23
|
-
throw `Unknown protocol in url ${url}, expected one of "http" or "https"
|
|
22
|
+
throw new Error(`Unknown protocol in url ${url}, expected one of "http" or "https"`);
|
|
24
23
|
}
|
|
25
24
|
const reqOptions = {
|
|
26
25
|
headers: {
|
|
@@ -29,7 +28,7 @@ function download(url, file, options) {
|
|
|
29
28
|
};
|
|
30
29
|
protocol.get(url, reqOptions, function (res) {
|
|
31
30
|
if (res.statusCode !== 200) {
|
|
32
|
-
reject(`Request to ${url} returned with status code: ${res.statusCode}`);
|
|
31
|
+
reject(new Error(`Request to ${url} returned with status code: ${res.statusCode}`));
|
|
33
32
|
res.resume();
|
|
34
33
|
}
|
|
35
34
|
const chunks = [];
|
|
@@ -44,18 +43,18 @@ function download(url, file, options) {
|
|
|
44
43
|
else {
|
|
45
44
|
res.pipe(fs_1.default.createWriteStream(file, { flags: options?.append ? 'a' : 'w' }));
|
|
46
45
|
res.on('end', function () {
|
|
47
|
-
resolve();
|
|
46
|
+
resolve(undefined);
|
|
48
47
|
});
|
|
49
48
|
}
|
|
50
49
|
}).on('error', (e) => {
|
|
51
|
-
reject(`Request to ${url} failed with error: ${e.message}`);
|
|
50
|
+
reject(new Error(`Request to ${url} failed with error: ${e.message}`));
|
|
52
51
|
});
|
|
53
52
|
});
|
|
54
53
|
}
|
|
55
54
|
exports.download = download;
|
|
56
55
|
async function downloadString(url, encoding = 'utf8') {
|
|
57
56
|
if (!Buffer.isEncoding(encoding)) {
|
|
58
|
-
throw `Unknown encoding ${encoding}
|
|
57
|
+
throw new Error(`Unknown encoding ${String(encoding)}`);
|
|
59
58
|
}
|
|
60
59
|
const buffer = await downloader_1.default.download(url);
|
|
61
60
|
return iconv_lite_1.default.decode(buffer, encoding);
|
|
@@ -66,4 +65,5 @@ async function downloadJSON(url, encoding = 'utf8') {
|
|
|
66
65
|
return JSON.parse(json);
|
|
67
66
|
}
|
|
68
67
|
exports.downloadJSON = downloadJSON;
|
|
68
|
+
exports.default = { download, downloadString, downloadJSON };
|
|
69
69
|
//# sourceMappingURL=downloader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../src/lib/downloader.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,kDAA0B;AAC1B,4DAA+B;AAE/B,8DAAsC;
|
|
1
|
+
{"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../src/lib/downloader.ts"],"names":[],"mappings":"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"}
|
package/jest.config.js
CHANGED
|
@@ -7,18 +7,10 @@ module.exports = {
|
|
|
7
7
|
clearMocks : true,
|
|
8
8
|
|
|
9
9
|
roots : [ '<rootDir>/src' ],
|
|
10
|
-
testMatch : [ '<rootDir>/src/**/__tests__/*.test.ts' ],
|
|
10
|
+
testMatch : [ '<rootDir>/src/**/__tests__/*.test.{ts,tsx}' ],
|
|
11
11
|
|
|
12
12
|
collectCoverageFrom : [
|
|
13
|
-
'<rootDir>/src/**/*.ts',
|
|
14
|
-
'!<rootDir>/src
|
|
15
|
-
'!<rootDir>/src/*.ts',
|
|
16
|
-
'!<rootDir>/src/types/*.ts',
|
|
17
|
-
|
|
18
|
-
'!**/node_modules/**',
|
|
19
|
-
'!**/__tests__/**',
|
|
20
|
-
|
|
21
|
-
'!<rootDir>/coverage/**',
|
|
22
|
-
'!<rootDir>/dist/**',
|
|
13
|
+
'<rootDir>/src/**/*.{ts,tsx}',
|
|
14
|
+
'!<rootDir>/src/**/__tests__/**',
|
|
23
15
|
],
|
|
24
16
|
};
|
package/package.json
CHANGED
|
@@ -1,51 +1,56 @@
|
|
|
1
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
|
-
|
|
2
|
+
"name": "@anmiles/downloader",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "Wrapper for downloading data as string, buffer or complex types",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"download",
|
|
7
|
+
"http",
|
|
8
|
+
"request"
|
|
9
|
+
],
|
|
10
|
+
"author": "Anatoliy Oblaukhov",
|
|
11
|
+
"homepage": "https://github.com/anmiles/downloader",
|
|
12
|
+
"repository": "github:anmiles/downloader",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.18.0"
|
|
16
|
+
},
|
|
17
|
+
"main": "dist/index.js",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "rimraf dist && tsc -p ./tsconfig.build.json",
|
|
20
|
+
"build:ci": "tsc -noEmit -p ./tsconfig.build.json",
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"lint:fix": "npm run lint -- --fix",
|
|
23
|
+
"test": "jest --verbose",
|
|
24
|
+
"test:coverage": "npm test -- --coverage",
|
|
25
|
+
"test:ci": "npm test -- --ci --coverage",
|
|
26
|
+
"test:watch": "npm test -- --watch",
|
|
27
|
+
"test:watch:coverage": "npm test -- --watch --coverage",
|
|
28
|
+
"test:report:coverage": "nyc report --nycrc-path ./coverage.config.js -t ./coverage --report-dir ./coverage"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"iconv-lite": "^0.6.3"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@anmiles/eslint-config": "^7.0.1",
|
|
35
|
+
"@anmiles/tsconfig": "^2.0.1",
|
|
36
|
+
"@stylistic/eslint-plugin": "^1.7.0",
|
|
37
|
+
"@types/event-emitter": "^0.3.5",
|
|
38
|
+
"@types/jest": "^29.5.12",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
|
40
|
+
"@typescript-eslint/parser": "^7.2.0",
|
|
41
|
+
"eslint": "^8.57.0",
|
|
42
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
|
43
|
+
"eslint-plugin-align-assignments": "^1.1.2",
|
|
44
|
+
"eslint-plugin-import": "^2.29.1",
|
|
45
|
+
"eslint-plugin-jest": "^27.9.0",
|
|
46
|
+
"eslint-plugin-jsonc": "^2.13.0",
|
|
47
|
+
"eslint-plugin-n": "^16.6.2",
|
|
48
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
49
|
+
"event-emitter": "^0.3.5",
|
|
50
|
+
"jest": "^29.7.0",
|
|
51
|
+
"nyc": "^15.1.0",
|
|
52
|
+
"rimraf": "^5.0.5",
|
|
53
|
+
"ts-jest": "^29.1.2",
|
|
54
|
+
"typescript": "^5.4.2"
|
|
55
|
+
}
|
|
51
56
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,23 +5,26 @@ import emitter from 'event-emitter';
|
|
|
5
5
|
import iconv from 'iconv-lite';
|
|
6
6
|
|
|
7
7
|
import downloader from '../downloader';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
const original = jest.requireActual<{ default : typeof downloader }>('../downloader').default;
|
|
9
10
|
|
|
10
11
|
jest.mock<Partial<typeof downloader>>('../downloader', () => ({
|
|
11
12
|
download : jest.fn().mockImplementation(() => downloaded),
|
|
12
|
-
downloadString : jest.fn().mockImplementation((...args: Parameters<typeof original.downloadString>) => original.downloadString(...args)),
|
|
13
|
+
downloadString : jest.fn().mockImplementation(async (...args: Parameters<typeof original.downloadString>) => original.downloadString(...args)),
|
|
13
14
|
}));
|
|
14
15
|
|
|
15
16
|
let request: http.ClientRequest;
|
|
16
17
|
let response: http.IncomingMessage;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
/* eslint-disable promise/prefer-await-to-callbacks -- similar signature to original http.get */
|
|
20
|
+
function get(_url: URL | string, _options: https.RequestOptions, callback?: ((res: http.IncomingMessage) => void) | undefined): http.ClientRequest {
|
|
19
21
|
if (callback) {
|
|
20
22
|
callback(response);
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
return request;
|
|
24
26
|
}
|
|
27
|
+
/* eslint-enable promise/prefer-await-to-callbacks */
|
|
25
28
|
|
|
26
29
|
beforeEach(() => {
|
|
27
30
|
request = emitter() as typeof request;
|
|
@@ -33,49 +36,36 @@ beforeEach(() => {
|
|
|
33
36
|
response.statusCode = 200;
|
|
34
37
|
});
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
const httpGetSpy = jest.spyOn(http, 'get').mockImplementation(get);
|
|
40
|
+
const httpsGetSpy = jest.spyOn(https, 'get').mockImplementation(get);
|
|
38
41
|
let downloaded: Buffer;
|
|
39
42
|
|
|
40
|
-
beforeAll(() => {
|
|
41
|
-
httpGetSpy = jest.spyOn(http, 'get');
|
|
42
|
-
httpsGetSpy = jest.spyOn(https, 'get');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
beforeEach(() => {
|
|
46
|
-
httpGetSpy.mockImplementation(get);
|
|
47
|
-
httpsGetSpy.mockImplementation(get);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
afterAll(() => {
|
|
51
|
-
httpGetSpy.mockRestore();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
43
|
describe('src/lib/downloader', () => {
|
|
55
44
|
describe('download', () => {
|
|
56
45
|
it('should throw if url protocol is not supported', async () => {
|
|
57
|
-
|
|
46
|
+
const promise: () => Promise<Buffer> = async () => original.download('ftp://url');
|
|
47
|
+
await expect(promise).rejects.toEqual(new Error('Unknown protocol in url ftp://url, expected one of "http" or "https"'));
|
|
58
48
|
});
|
|
59
49
|
|
|
60
50
|
it('should call http.get if url protocol is http', async () => {
|
|
61
51
|
const promise = original.download('http://url');
|
|
62
52
|
response.emit('end');
|
|
63
53
|
await promise;
|
|
64
|
-
expect(httpGetSpy.mock.calls[0][0]).toEqual('http://url');
|
|
54
|
+
expect(httpGetSpy.mock.calls[0]?.[0]).toEqual('http://url');
|
|
65
55
|
});
|
|
66
56
|
|
|
67
57
|
it('should call https.get if url protocol is https', async () => {
|
|
68
58
|
const promise = original.download('https://url');
|
|
69
59
|
response.emit('end');
|
|
70
60
|
await promise;
|
|
71
|
-
expect(httpsGetSpy.mock.calls[0][0]).toEqual('https://url');
|
|
61
|
+
expect(httpsGetSpy.mock.calls[0]?.[0]).toEqual('https://url');
|
|
72
62
|
});
|
|
73
63
|
|
|
74
64
|
it('should pass user-agent in options', async () => {
|
|
75
65
|
const promise = original.download('http://url');
|
|
76
66
|
response.emit('end');
|
|
77
67
|
await promise;
|
|
78
|
-
expect(httpGetSpy.mock.calls[0][1]).toEqual(expect.objectContaining({
|
|
68
|
+
expect(httpGetSpy.mock.calls[0]?.[1]).toEqual(expect.objectContaining({
|
|
79
69
|
headers : {
|
|
80
70
|
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
|
81
71
|
},
|
|
@@ -83,15 +73,16 @@ describe('src/lib/downloader', () => {
|
|
|
83
73
|
});
|
|
84
74
|
|
|
85
75
|
it('should reject and resume response if status code is not 200', async () => {
|
|
86
|
-
response.statusCode
|
|
87
|
-
|
|
76
|
+
response.statusCode = 404;
|
|
77
|
+
const promise: () => Promise<Buffer> = async () => original.download('http://url');
|
|
78
|
+
await expect(promise).rejects.toEqual(new Error('Request to http://url returned with status code: 404'));
|
|
88
79
|
expect(response.resume).toHaveBeenCalled();
|
|
89
80
|
});
|
|
90
81
|
|
|
91
82
|
it('should reject if response errored', async () => {
|
|
92
83
|
const promise = original.download('http://url');
|
|
93
84
|
request.emit('error', new Error('request error'));
|
|
94
|
-
await expect(
|
|
85
|
+
await expect(promise).rejects.toEqual(new Error('Request to http://url failed with error: request error'));
|
|
95
86
|
});
|
|
96
87
|
|
|
97
88
|
it('should concat and resolve received data if no file specified', async () => {
|
|
@@ -112,10 +103,9 @@ describe('src/lib/downloader', () => {
|
|
|
112
103
|
response.emit('data', new Uint8Array([ 20, 21, 22 ]));
|
|
113
104
|
response.emit('data', new Uint8Array([ 30, 31, 32 ]));
|
|
114
105
|
response.emit('end');
|
|
115
|
-
|
|
106
|
+
await promise;
|
|
116
107
|
expect(createWriteStreamSpy).toHaveBeenCalledWith('file', { flags : 'w' });
|
|
117
108
|
expect(response.pipe).toHaveBeenCalledWith(stream);
|
|
118
|
-
expect(result).toEqual(undefined);
|
|
119
109
|
createWriteStreamSpy.mockRestore();
|
|
120
110
|
});
|
|
121
111
|
|
|
@@ -127,17 +117,17 @@ describe('src/lib/downloader', () => {
|
|
|
127
117
|
response.emit('data', new Uint8Array([ 20, 21, 22 ]));
|
|
128
118
|
response.emit('data', new Uint8Array([ 30, 31, 32 ]));
|
|
129
119
|
response.emit('end');
|
|
130
|
-
|
|
120
|
+
await promise;
|
|
131
121
|
expect(createWriteStreamSpy).toHaveBeenCalledWith('file', { flags : 'a' });
|
|
132
122
|
expect(response.pipe).toHaveBeenCalledWith(stream);
|
|
133
|
-
expect(result).toEqual(undefined);
|
|
134
123
|
createWriteStreamSpy.mockRestore();
|
|
135
124
|
});
|
|
136
125
|
});
|
|
137
126
|
|
|
138
127
|
describe('downloadString', () => {
|
|
139
128
|
it('should throw if unknown encoding specified', async () => {
|
|
140
|
-
|
|
129
|
+
const promise: () => Promise<string> = async () => original.downloadString('http://url', 'wrong_encoding' as unknown as BufferEncoding);
|
|
130
|
+
await expect(promise).rejects.toEqual(new Error('Unknown encoding wrong_encoding'));
|
|
141
131
|
});
|
|
142
132
|
|
|
143
133
|
it('should return string decoded with utf8', async () => {
|
package/src/lib/downloader.ts
CHANGED
|
@@ -5,23 +5,20 @@ import iconv from 'iconv-lite';
|
|
|
5
5
|
|
|
6
6
|
import downloader from './downloader';
|
|
7
7
|
|
|
8
|
-
export { download, downloadString, downloadJSON };
|
|
9
|
-
export default { download, downloadString, downloadJSON };
|
|
10
|
-
|
|
11
8
|
type BufferEncoding = Parameters<Buffer['toString']>[0];
|
|
12
9
|
|
|
13
10
|
function download(url: string): Promise<Buffer>;
|
|
14
|
-
function download(url: string, file: string, options?: { append
|
|
15
|
-
function download(url: string, file?: string, options?: { append
|
|
16
|
-
return new Promise<Buffer |
|
|
17
|
-
let protocol : typeof
|
|
11
|
+
function download(url: string, file: string, options?: { append? : boolean }): Promise<undefined>;
|
|
12
|
+
async function download(url: string, file?: string, options?: { append? : boolean }): Promise<Buffer | undefined> {
|
|
13
|
+
return new Promise<Buffer | undefined>((resolve, reject) => {
|
|
14
|
+
let protocol : typeof http | typeof https;
|
|
18
15
|
|
|
19
16
|
if (url.startsWith('https://')) {
|
|
20
17
|
protocol = https;
|
|
21
18
|
} else if (url.startsWith('http://')) {
|
|
22
19
|
protocol = http;
|
|
23
20
|
} else {
|
|
24
|
-
throw `Unknown protocol in url ${url}, expected one of "http" or "https"
|
|
21
|
+
throw new Error(`Unknown protocol in url ${url}, expected one of "http" or "https"`);
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
const reqOptions = {
|
|
@@ -32,14 +29,14 @@ function download(url: string, file?: string, options?: { append?: boolean }): P
|
|
|
32
29
|
|
|
33
30
|
protocol.get(url, reqOptions, function(res) {
|
|
34
31
|
if (res.statusCode !== 200) {
|
|
35
|
-
reject(`Request to ${url} returned with status code: ${res.statusCode}`);
|
|
32
|
+
reject(new Error(`Request to ${url} returned with status code: ${res.statusCode}`));
|
|
36
33
|
res.resume();
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
const chunks: Uint8Array[] = [];
|
|
40
37
|
|
|
41
38
|
if (typeof file === 'undefined') {
|
|
42
|
-
res.on('data', function(chunk) {
|
|
39
|
+
res.on('data', function(chunk: Uint8Array) {
|
|
43
40
|
chunks.push(chunk);
|
|
44
41
|
});
|
|
45
42
|
|
|
@@ -50,25 +47,28 @@ function download(url: string, file?: string, options?: { append?: boolean }): P
|
|
|
50
47
|
res.pipe(fs.createWriteStream(file, { flags : options?.append ? 'a' : 'w' }));
|
|
51
48
|
|
|
52
49
|
res.on('end', function() {
|
|
53
|
-
resolve();
|
|
50
|
+
resolve(undefined);
|
|
54
51
|
});
|
|
55
52
|
}
|
|
56
53
|
}).on('error', (e) => {
|
|
57
|
-
reject(`Request to ${url} failed with error: ${e.message}`);
|
|
54
|
+
reject(new Error(`Request to ${url} failed with error: ${e.message}`));
|
|
58
55
|
});
|
|
59
56
|
});
|
|
60
57
|
}
|
|
61
58
|
|
|
62
|
-
async function downloadString(url: string, encoding: BufferEncoding = 'utf8') {
|
|
59
|
+
async function downloadString(url: string, encoding: BufferEncoding = 'utf8'): Promise<string> {
|
|
63
60
|
if (!Buffer.isEncoding(encoding)) {
|
|
64
|
-
throw `Unknown encoding ${encoding}
|
|
61
|
+
throw new Error(`Unknown encoding ${String(encoding)}`);
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
const buffer = await downloader.download(url);
|
|
68
65
|
return iconv.decode(buffer, encoding);
|
|
69
66
|
}
|
|
70
67
|
|
|
71
|
-
async function downloadJSON(url: string, encoding: BufferEncoding = 'utf8') {
|
|
68
|
+
async function downloadJSON(url: string, encoding: BufferEncoding = 'utf8'): Promise<unknown> {
|
|
72
69
|
const json = await downloader.downloadString(url, encoding);
|
|
73
|
-
return JSON.parse(json);
|
|
70
|
+
return JSON.parse(json) as unknown;
|
|
74
71
|
}
|
|
72
|
+
|
|
73
|
+
export { download, downloadString, downloadJSON };
|
|
74
|
+
export default { download, downloadString, downloadJSON };
|
package/tsconfig.build.json
CHANGED
package/tsconfig.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "./node_modules/@anmiles/tsconfig/tsconfig.json",
|
|
2
|
+
"extends" : "./node_modules/@anmiles/tsconfig/tsconfig.json",
|
|
3
3
|
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"rootDir": "./src",
|
|
6
|
-
"outDir": "./dist",
|
|
4
|
+
"compilerOptions" : {
|
|
5
|
+
"rootDir" : "./src",
|
|
6
|
+
"outDir" : "./dist",
|
|
7
7
|
},
|
|
8
8
|
|
|
9
|
-
"include": [
|
|
9
|
+
"include" : [
|
|
10
10
|
"src",
|
|
11
11
|
],
|
|
12
12
|
}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
concurrency:
|
|
11
|
-
group: "${{ github.workflow }}-${{ github.ref }}"
|
|
12
|
-
cancel-in-progress: true
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
install:
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
container:
|
|
18
|
-
image: node:18.14
|
|
19
|
-
timeout-minutes: 30
|
|
20
|
-
steps:
|
|
21
|
-
- uses: actions/checkout@v4
|
|
22
|
-
- uses: actions/cache@v4
|
|
23
|
-
with:
|
|
24
|
-
path: node_modules
|
|
25
|
-
key: "node_modules-${{ hashFiles('package-lock.json') }}"
|
|
26
|
-
lookup-only: true
|
|
27
|
-
- run: npm ci
|
|
28
|
-
|
|
29
|
-
build:
|
|
30
|
-
needs: install
|
|
31
|
-
runs-on: ubuntu-latest
|
|
32
|
-
container:
|
|
33
|
-
image: node:18.14
|
|
34
|
-
timeout-minutes: 30
|
|
35
|
-
steps:
|
|
36
|
-
- uses: actions/checkout@v4
|
|
37
|
-
- uses: actions/cache@v4
|
|
38
|
-
with:
|
|
39
|
-
path: node_modules
|
|
40
|
-
key: "node_modules-${{ hashFiles('package-lock.json') }}"
|
|
41
|
-
- run: npm run build:ci
|
|
42
|
-
|
|
43
|
-
lint:
|
|
44
|
-
needs: build
|
|
45
|
-
runs-on: ubuntu-latest
|
|
46
|
-
container:
|
|
47
|
-
image: node:18.14
|
|
48
|
-
timeout-minutes: 30
|
|
49
|
-
steps:
|
|
50
|
-
- uses: actions/checkout@v4
|
|
51
|
-
- uses: actions/cache@v4
|
|
52
|
-
with:
|
|
53
|
-
path: node_modules
|
|
54
|
-
key: "node_modules-${{ hashFiles('package-lock.json') }}"
|
|
55
|
-
- run: npm run lint
|
|
56
|
-
|
|
57
|
-
test:
|
|
58
|
-
needs: build
|
|
59
|
-
runs-on: ubuntu-latest
|
|
60
|
-
container:
|
|
61
|
-
image: node:18.14
|
|
62
|
-
timeout-minutes: 30
|
|
63
|
-
steps:
|
|
64
|
-
- uses: actions/checkout@v4
|
|
65
|
-
- uses: actions/cache@v4
|
|
66
|
-
with:
|
|
67
|
-
path: node_modules
|
|
68
|
-
key: "node_modules-${{ hashFiles('package-lock.json') }}"
|
|
69
|
-
- uses: actions/cache@v4
|
|
70
|
-
with:
|
|
71
|
-
path: coverage
|
|
72
|
-
key: "coverage-${{ hashFiles('package-lock.json') }}"
|
|
73
|
-
lookup-only: true
|
|
74
|
-
- run: npm run test:ci
|
|
75
|
-
|
|
76
|
-
coverage:
|
|
77
|
-
needs:
|
|
78
|
-
- lint
|
|
79
|
-
- test
|
|
80
|
-
runs-on: ubuntu-latest
|
|
81
|
-
container:
|
|
82
|
-
image: node:18.14
|
|
83
|
-
timeout-minutes: 30
|
|
84
|
-
steps:
|
|
85
|
-
- uses: actions/checkout@v4
|
|
86
|
-
- uses: actions/cache@v4
|
|
87
|
-
with:
|
|
88
|
-
path: node_modules
|
|
89
|
-
key: "node_modules-${{ hashFiles('package-lock.json') }}"
|
|
90
|
-
- uses: actions/cache@v4
|
|
91
|
-
with:
|
|
92
|
-
path: coverage
|
|
93
|
-
key: "coverage-${{ hashFiles('package-lock.json') }}"
|
|
94
|
-
- run: npm run test:report:coverage
|