Comparing version 4.1.0 to 4.2.0
/// <reference types="node" /> | ||
import { RequestOptions } from 'http'; | ||
import { URL } from 'url'; | ||
import { PassThrough, Transform } from 'stream'; | ||
@@ -19,2 +20,11 @@ declare namespace Miniget { | ||
} | ||
interface DefaultOptions extends Options { | ||
maxRedirects: number; | ||
maxRetries: number; | ||
maxReconnects: number; | ||
backoff: { | ||
inc: number; | ||
max: number; | ||
}; | ||
} | ||
type defaultOptions = Miniget.Options; | ||
@@ -34,3 +44,3 @@ type MinigetError = Error; | ||
} | ||
declare function Miniget(url: string, options?: Miniget.Options): Miniget.Stream; | ||
declare function Miniget(url: string | URL, options?: Miniget.Options): Miniget.Stream; | ||
declare namespace Miniget { | ||
@@ -47,10 +57,10 @@ var defaultOptions: { | ||
var MinigetError: { | ||
new (message: string, statusCode?: number): { | ||
statusCode: number; | ||
new (message: string, statusCode?: number | undefined): { | ||
statusCode?: number | undefined; | ||
name: string; | ||
message: string; | ||
stack?: string; | ||
stack?: string | undefined; | ||
}; | ||
captureStackTrace(targetObject: object, constructorOpt?: Function): void; | ||
prepareStackTrace?: (err: Error, stackTraces: NodeJS.CallSite[]) => any; | ||
captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void; | ||
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined; | ||
stackTraceLimit: number; | ||
@@ -57,0 +67,0 @@ }; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -54,3 +45,3 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
if ((_a = opts.headers) === null || _a === void 0 ? void 0 : _a.Range) { | ||
let r = /bytes=(\d+)-(\d+)?/.exec(opts.headers.Range + ''); | ||
let r = /bytes=(\d+)-(\d+)?/.exec(`${opts.headers.Range}`); | ||
if (r) { | ||
@@ -64,7 +55,7 @@ rangeStart = parseInt(r[1], 10); | ||
opts.headers = Object.assign({ | ||
'Accept-Encoding': Object.keys(opts.acceptEncoding).join(', ') | ||
'Accept-Encoding': Object.keys(opts.acceptEncoding).join(', '), | ||
}, opts.headers); | ||
} | ||
const downloadHasStarted = () => activeDecodedStream && 0 < downloaded; | ||
const downloadComplete = () => !acceptRanges || downloaded == contentLength; | ||
const downloadHasStarted = () => activeDecodedStream && downloaded > 0; | ||
const downloadComplete = () => !acceptRanges || downloaded === contentLength; | ||
const reconnect = (err) => { | ||
@@ -79,3 +70,3 @@ activeDecodedStream = null; | ||
const reconnectIfEndedEarly = (err) => { | ||
if (options.method != 'HEAD' && !downloadComplete() && reconnects++ < opts.maxReconnects) { | ||
if (options.method !== 'HEAD' && !downloadComplete() && reconnects++ < opts.maxReconnects) { | ||
reconnect(err); | ||
@@ -93,3 +84,3 @@ return true; | ||
} | ||
else if ((!retryOptions.statusCode || retryOptions.err.message === 'ENOTFOUND') && | ||
else if ((!retryOptions.err || retryOptions.err.message === 'ENOTFOUND') && | ||
retries++ < opts.maxRetries) { | ||
@@ -110,6 +101,16 @@ let ms = retryOptions.retryAfter || | ||
const doDownload = () => { | ||
let parsed, httpLib; | ||
let parsed = {}, httpLib; | ||
try { | ||
parsed = url_1.parse(url); | ||
httpLib = httpLibs[parsed.protocol]; | ||
let urlObj = typeof url === 'string' ? new url_1.URL(url) : url; | ||
parsed = Object.assign({}, { | ||
host: urlObj.host, | ||
hostname: urlObj.hostname, | ||
path: urlObj.pathname + urlObj.search + urlObj.hash, | ||
port: urlObj.port, | ||
protocol: urlObj.protocol, | ||
}); | ||
if (urlObj.username) { | ||
parsed.auth = `${urlObj.username}:${urlObj.password}`; | ||
} | ||
httpLib = httpLibs[String(parsed.protocol)]; | ||
} | ||
@@ -120,3 +121,3 @@ catch (err) { | ||
if (!httpLib) { | ||
stream.emit('error', new Miniget.MinigetError('Invalid URL: ' + url)); | ||
stream.emit('error', new Miniget.MinigetError(`Invalid URL: ${url}`)); | ||
return; | ||
@@ -129,3 +130,3 @@ } | ||
parsed.headers = Object.assign({}, parsed.headers, { | ||
Range: `bytes=${start}-${end}` | ||
Range: `bytes=${start}-${end}`, | ||
}); | ||
@@ -142,3 +143,3 @@ } | ||
if (!parsed || parsed.protocol) { | ||
httpLib = httpLibs[parsed === null || parsed === void 0 ? void 0 : parsed.protocol]; | ||
httpLib = httpLibs[String(parsed === null || parsed === void 0 ? void 0 : parsed.protocol)]; | ||
if (!httpLib) { | ||
@@ -150,5 +151,12 @@ stream.emit('error', new Miniget.MinigetError('Invalid URL object from `transform` function')); | ||
} | ||
const onError = (err, statusCode) => { | ||
const onError = (err) => { | ||
if (stream.destroyed || stream.readableEnded) { | ||
return; | ||
} | ||
// Needed for node v10. | ||
if (stream._readableState.ended) { | ||
return; | ||
} | ||
cleanup(); | ||
if (!retryRequest({ err, statusCode })) { | ||
if (!retryRequest({ err })) { | ||
stream.emit('error', err); | ||
@@ -165,8 +173,5 @@ } | ||
const cleanup = () => { | ||
activeRequest.removeListener('error', onError); | ||
activeRequest.removeListener('close', onRequestClose); | ||
activeResponse === null || activeResponse === void 0 ? void 0 : activeResponse.removeListener('data', onData); | ||
activeDecodedStream === null || activeDecodedStream === void 0 ? void 0 : activeDecodedStream.removeListener('end', onEnd); | ||
activeDecodedStream === null || activeDecodedStream === void 0 ? void 0 : activeDecodedStream.removeListener('error', onError); | ||
activeResponse === null || activeResponse === void 0 ? void 0 : activeResponse.removeListener('error', onError); | ||
}; | ||
@@ -191,20 +196,30 @@ const onData = (chunk) => { downloaded += chunk.length; }; | ||
else { | ||
url = res.headers.location; | ||
setTimeout(doDownload, res.headers['retry-after'] ? parseInt(res.headers['retry-after'], 10) * 1000 : 0); | ||
if (res.headers.location) { | ||
url = res.headers.location; | ||
} | ||
else { | ||
let err = new Miniget.MinigetError('Redirect status code given with no location', res.statusCode); | ||
stream.emit('error', err); | ||
cleanup(); | ||
return; | ||
} | ||
setTimeout(doDownload, parseInt(res.headers['retry-after'] || '0', 10) * 1000); | ||
stream.emit('redirect', url); | ||
} | ||
return cleanup(); | ||
cleanup(); | ||
return; | ||
// Check for rate limiting. | ||
} | ||
else if (retryStatusCodes.has(res.statusCode)) { | ||
if (!retryRequest({ retryAfter: parseInt(res.headers['retry-after'], 10) })) { | ||
let err = new Miniget.MinigetError('Status code: ' + res.statusCode, res.statusCode); | ||
if (!retryRequest({ retryAfter: parseInt(res.headers['retry-after'] || '0', 10) })) { | ||
let err = new Miniget.MinigetError(`Status code: ${res.statusCode}`, res.statusCode); | ||
stream.emit('error', err); | ||
} | ||
return cleanup(); | ||
cleanup(); | ||
return; | ||
} | ||
else if (res.statusCode < 200 || 400 <= res.statusCode) { | ||
let err = new Miniget.MinigetError('Status code: ' + res.statusCode, res.statusCode); | ||
else if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 400)) { | ||
let err = new Miniget.MinigetError(`Status code: ${res.statusCode}`, res.statusCode); | ||
if (res.statusCode >= 500) { | ||
onError(err, res.statusCode); | ||
onError(err); | ||
} | ||
@@ -214,3 +229,4 @@ else { | ||
} | ||
return cleanup(); | ||
cleanup(); | ||
return; | ||
} | ||
@@ -221,3 +237,3 @@ activeDecodedStream = res; | ||
let fn = opts.acceptEncoding[enc]; | ||
if (fn != null) { | ||
if (fn) { | ||
activeDecodedStream = activeDecodedStream.pipe(fn()); | ||
@@ -229,3 +245,3 @@ activeDecodedStream.on('error', onError); | ||
if (!contentLength) { | ||
contentLength = parseInt(res.headers['content-length'] + '', 10); | ||
contentLength = parseInt(`${res.headers['content-length']}`, 10); | ||
acceptRanges = res.headers['accept-ranges'] === 'bytes' && | ||
@@ -246,3 +262,3 @@ contentLength > 0 && opts.maxReconnects > 0; | ||
if (stream.destroyed) { | ||
streamDestroy(destroyErr); | ||
streamDestroy(...destroyArgs); | ||
} | ||
@@ -258,3 +274,3 @@ stream.emit('request', activeRequest); | ||
}; | ||
let destroyErr; | ||
let destroyArgs; | ||
const streamDestroy = (err) => { | ||
@@ -266,19 +282,17 @@ activeRequest.destroy(err); | ||
}; | ||
stream._destroy = (err) => { | ||
stream._destroy = (...args) => { | ||
stream.destroyed = true; | ||
if (activeRequest) { | ||
streamDestroy(err); | ||
streamDestroy(...args); | ||
} | ||
else { | ||
destroyErr = err; | ||
destroyArgs = args; | ||
} | ||
}; | ||
stream.text = () => __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
let body = ''; | ||
stream.setEncoding('utf8'); | ||
stream.on('data', (chunk) => body += chunk); | ||
stream.on('end', () => resolve(body)); | ||
stream.on('error', reject); | ||
}); | ||
stream.text = () => new Promise((resolve, reject) => { | ||
let body = ''; | ||
stream.setEncoding('utf8'); | ||
stream.on('data', chunk => body += chunk); | ||
stream.on('end', () => resolve(body)); | ||
stream.on('error', reject); | ||
}); | ||
@@ -285,0 +299,0 @@ process.nextTick(doDownload); |
@@ -11,3 +11,3 @@ { | ||
], | ||
"version": "4.1.0", | ||
"version": "4.2.0", | ||
"repository": { | ||
@@ -26,3 +26,5 @@ "type": "git", | ||
"test": "nyc --extension .ts --reporter=lcov --reporter=text-summary npm run test:unit", | ||
"test:unit": "mocha -- --require ts-node/register test/*-test.ts" | ||
"test:unit": "mocha -- --require ts-node/register test/*-test.ts", | ||
"lint": "eslint ./src ./test", | ||
"lint:fix": "eslint --fix ./src ./test" | ||
}, | ||
@@ -34,2 +36,5 @@ "dependencies": {}, | ||
"@types/sinon": "^9.0.8", | ||
"@typescript-eslint/eslint-plugin": "^4.8.2", | ||
"@typescript-eslint/parser": "^4.8.2", | ||
"eslint": "^7.14.0", | ||
"longjohn": "^0.2.12", | ||
@@ -42,3 +47,3 @@ "mocha": "^7.0.1", | ||
"ts-node": "^8.10.1", | ||
"typescript": "^3.9.3" | ||
"typescript": "^3.9.7" | ||
}, | ||
@@ -45,0 +50,0 @@ "engines": { |
@@ -36,3 +36,3 @@ # node-miniget | ||
Makes a GET request. `options` can have any properties from the [`http.request()` function](https://nodejs.org/api/http.html#http_http_request_options_callback), in addition to | ||
Makes a GET request. `url` can be a string or a `URL` object. `options` can have any properties from the [`http.request()` function](https://nodejs.org/api/http.html#http_http_request_options_callback), in addition to | ||
@@ -39,0 +39,0 @@ * `maxRedirects` - Default is `10`. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29700
351
14