got 9.2.1 → 9.3.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "9.2.1",
3
+ "version": "9.3.2",
4
4
  "description": "Simplified HTTP requests",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
@@ -9,7 +9,8 @@
9
9
  "node": ">=8.6"
10
10
  },
11
11
  "scripts": {
12
- "test": "xo && nyc ava"
12
+ "test": "xo && nyc ava",
13
+ "release": "np"
13
14
  },
14
15
  "files": [
15
16
  "source"
@@ -33,28 +34,30 @@
33
34
  "electron"
34
35
  ],
35
36
  "dependencies": {
36
- "@sindresorhus/is": "^0.11.0",
37
+ "@sindresorhus/is": "^0.12.0",
37
38
  "@szmarczak/http-timer": "^1.1.0",
38
- "cacheable-request": "^5.0.0",
39
+ "cacheable-request": "^5.1.0",
39
40
  "decompress-response": "^3.3.0",
40
41
  "duplexer3": "^0.1.4",
41
- "get-stream": "^4.0.0",
42
+ "get-stream": "^4.1.0",
43
+ "lowercase-keys": "^1.0.1",
42
44
  "mimic-response": "^1.0.1",
43
- "p-cancelable": "^0.5.0",
45
+ "p-cancelable": "^1.0.0",
44
46
  "to-readable-stream": "^1.0.0",
45
47
  "url-parse-lax": "^3.0.0"
46
48
  },
47
49
  "devDependencies": {
48
- "ava": "1.0.0-beta.8",
50
+ "ava": "1.0.0-rc.1",
49
51
  "coveralls": "^3.0.0",
50
- "delay": "^4.0.0",
51
- "form-data": "^2.1.1",
52
+ "delay": "^4.1.0",
53
+ "form-data": "^2.3.3",
52
54
  "get-port": "^4.0.0",
53
- "nyc": "^13.0.1",
55
+ "np": "^3.0.4",
56
+ "nyc": "^13.1.0",
54
57
  "p-event": "^2.1.0",
55
- "pem": "^1.4.4",
58
+ "pem": "^1.13.2",
56
59
  "proxyquire": "^2.0.1",
57
- "sinon": "^6.1.0",
60
+ "sinon": "^7.1.0",
58
61
  "slow-stream": "0.0.4",
59
62
  "tempfile": "^2.0.0",
60
63
  "tempy": "^0.2.1",
package/readme.md CHANGED
@@ -35,9 +35,10 @@ Got is for Node.js. For browsers, we recommend [Ky](https://github.com/sindresor
35
35
  - [Errors with metadata](#errors)
36
36
  - [JSON mode](#json)
37
37
  - [WHATWG URL support](#url)
38
- - [Electron support](#useelectronnet)
38
+ - [Hooks](https://github.com/sindresorhus/got#hooks)
39
39
  - [Instances with custom defaults](#instances)
40
40
  - [Composable](advanced-creation.md#merging-instances)
41
+ - [Electron support](#useelectronnet)
41
42
  - [Used by ~2000 packages and ~500K repos](https://github.com/sindresorhus/got/network/dependents)
42
43
  - Actively maintained
43
44
 
@@ -120,7 +121,7 @@ Very useful when used with `got.extend()` to create niche-specific Got instances
120
121
 
121
122
  Can be a string or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
122
123
 
123
- Backslash at the end of `baseUrl` and at the beginning of the `url` argument is optional:
124
+ Slash at the end of `baseUrl` and at the beginning of the `url` argument is optional:
124
125
 
125
126
  ```js
126
127
  await got('hello', {baseUrl: 'https://example.com/v1'});
@@ -202,9 +203,36 @@ Parse response body with `JSON.parse` and set `accept` header to `application/js
202
203
 
203
204
  ###### query
204
205
 
205
- Type: `string` `Object` [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
206
+ Type: `string` `Object<string, string|number>` [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
207
+
208
+ Query string that will be added to the request URL. This will override the query string in `url`.
209
+
210
+ If you need to pass in an array, you can do it using a `URLSearchParams` instance:
211
+
212
+ ```js
213
+ const got = require('got');
214
+
215
+ const query = new URLSearchParams([['key', 'a'], ['key', 'b']]);
216
+
217
+ got('https://example.com', {query});
218
+
219
+ console.log(query.toString());
220
+ //=> 'key=a&key=b'
221
+ ```
222
+
223
+ And if you need a different array format, you could use the [`query-string`](https://github.com/sindresorhus/query-string) package:
224
+
225
+ ```js
226
+ const got = require('got');
227
+ const queryString = require('query-string');
228
+
229
+ const query = queryString.stringify({key: ['a', 'b']}, {arrayFormat: 'bracket'});
230
+
231
+ got('https://example.com', {query});
206
232
 
207
- Query string object that will be added to the request URL. This will override the query string in `url`.
233
+ console.log(query);
234
+ //=> 'key[]=a&key[]=b'
235
+ ```
208
236
 
209
237
  ###### timeout
210
238
 
@@ -236,7 +264,7 @@ An object representing `retries`, `methods`, `statusCodes` and `maxRetryAfter` f
236
264
  If `maxRetryAfter` is set to `undefined`, it will use `options.timeout`.<br>
237
265
  If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request.
238
266
 
239
- Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 0).
267
+ Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 1).
240
268
 
241
269
  The `retries` property can be a `number` or a `function` with `retry` and `error` arguments. The function must return a delay in milliseconds (`0` return value cancels retry).
242
270
 
@@ -316,8 +344,7 @@ got('sindresorhus.com', {
316
344
 
317
345
  ###### hooks
318
346
 
319
- Type: `Object<string, Function[]>`<br>
320
- Default: `{beforeRequest: []}`
347
+ Type: `Object<string, Function[]>`
321
348
 
322
349
  Hooks allow modifications during the request lifecycle. Hook functions may be async and are run serially.
323
350
 
@@ -326,11 +353,96 @@ Hooks allow modifications during the request lifecycle. Hook functions may be as
326
353
  Type: `Function[]`<br>
327
354
  Default: `[]`
328
355
 
329
- Called with the normalized request options. Got will make no further changes to the request before it is sent. This is especially useful in conjunction with [`got.extend()`](#instances) and [`got.create()`](advanced-creation.md) when you want to create an API client that, for example, uses HMAC-signing.
356
+ Called with [normalized](source/normalize-arguments.js) [request options](#options). Got will make no further changes to the request before it is sent. This is especially useful in conjunction with [`got.extend()`](#instances) and [`got.create()`](advanced-creation.md) when you want to create an API client that, for example, uses HMAC-signing.
330
357
 
331
358
  See the [AWS section](#aws) for an example.
332
359
 
333
- **Note**: Modifying the `body` is not recommended because the `content-length` header has already been computed and assigned.
360
+ **Note**: If you modify the `body` you will need to modify the `content-length` header too, because it has already been computed and assigned.
361
+
362
+ ###### hooks.beforeRedirect
363
+
364
+ Type: `Function[]`<br>
365
+ Default: `[]`
366
+
367
+ Called with [normalized](source/normalize-arguments.js) [request options](#options). Got will make no further changes to the request. This is especially useful when you want to avoid dead sites. Example:
368
+
369
+ ```js
370
+ const got = require('got');
371
+
372
+ got('example.com', {
373
+ hooks: {
374
+ beforeRedirect: [
375
+ options => {
376
+ if (options.hostname === 'deadSite') {
377
+ options.hostname = 'fallbackSite';
378
+ }
379
+ }
380
+ ]
381
+ }
382
+ });
383
+ ```
384
+
385
+ ###### hooks.beforeRetry
386
+
387
+ Type: `Function[]`<br>
388
+ Default: `[]`
389
+
390
+ Called with [normalized](source/normalize-arguments.js) [request options](#options), the error and the retry count. Got will make no further changes to the request. This is especially useful when some extra work is required before the next try. Example:
391
+
392
+ ```js
393
+ const got = require('got');
394
+
395
+ got('example.com', {
396
+ hooks: {
397
+ beforeRetry: [
398
+ (options, error, retryCount) => {
399
+ if (error.statusCode === 413) { // Payload too large
400
+ options.body = getNewBody();
401
+ }
402
+ }
403
+ ]
404
+ }
405
+ });
406
+ ```
407
+
408
+ ###### hooks.afterResponse
409
+
410
+ Type: `Function[]`<br>
411
+ Default: `[]`
412
+
413
+ Called with [response object](#response) and a retry function.
414
+
415
+ Each function should return the response. This is especially useful when you want to refresh an access token. Example:
416
+
417
+ ```js
418
+ const got = require('got');
419
+
420
+ const instance = got.extend({
421
+ hooks: {
422
+ afterResponse: [
423
+ (response, retryWithMergedOptions) => {
424
+ if (response.statusCode === 401) { // Unauthorized
425
+ const updatedOptions = {
426
+ headers: {
427
+ token: getNewToken() // Refresh the access token
428
+ }
429
+ };
430
+
431
+ // Save for further requests
432
+ instance.defaults.options = got.mergeOptions(instance.defaults.options, updatedOptions);
433
+
434
+ // Make a new retry
435
+ return retryWithMergedOptions(updatedOptions);
436
+ }
437
+
438
+ // No changes otherwise
439
+ return response;
440
+ }
441
+ ]
442
+ },
443
+ mutableDefaults: true
444
+ });
445
+ ```
334
446
 
335
447
  #### Response
336
448
 
@@ -472,7 +584,7 @@ Sets `options.method` to the method name and makes a request.
472
584
 
473
585
  #### got.extend([options])
474
586
 
475
- Configure a new `got` instance with default `options`. `options` are merged with the parent instance's `defaults.options` using [`got.mergeOptions`](#gotmergeoptionsparentoptions-newoptions).
587
+ Configure a new `got` instance with default `options`. The `options` are merged with the parent instance's `defaults.options` using [`got.mergeOptions`](#gotmergeoptionsparentoptions-newoptions). You can access the resolved options with the `.defaults` property on the instance.
476
588
 
477
589
  ```js
478
590
  const client = got.extend({
@@ -538,9 +650,15 @@ Options are deeply merged to a new object. The value of each key is determined a
538
650
  - If the new property is an `Array`, it overwrites the old one with a deep clone of the new property.
539
651
  - Otherwise, the new value is assigned to the key.
540
652
 
653
+ #### got.defaults
654
+
655
+ Type: `Object`
656
+
657
+ The default Got options.
658
+
541
659
  ## Errors
542
660
 
543
- Each error contains (if available) `statusCode`, `statusMessage`, `host`, `hostname`, `method`, `path`, `protocol` and `url` properties to make debugging easier.
661
+ Each error contains (if available) `body`, `statusCode`, `statusMessage`, `host`, `hostname`, `method`, `path`, `protocol` and `url` properties to make debugging easier.
544
662
 
545
663
  In Promise mode, the `response` is attached to the error.
546
664
 
@@ -670,7 +788,7 @@ You can use the [`tunnel`](https://github.com/koichik/node-tunnel) package with
670
788
 
671
789
  ```js
672
790
  const got = require('got');
673
- const tunnel = require('tunnel-agent');
791
+ const tunnel = require('tunnel');
674
792
 
675
793
  got('sindresorhus.com', {
676
794
  agent: tunnel.httpOverHttp({
@@ -910,7 +1028,7 @@ const h2got = got.extend({request});
910
1028
  | Browser support | ✖ | ✖ | ✔* | ✔ |
911
1029
  | Electron support | ✔ | ✖ | ✖ | ✖ |
912
1030
  | Promise API | ✔ | ✔ | ✔ | ✔ |
913
- | Stream API | ✔ | ✔ || ✖ |
1031
+ | Stream API | ✔ | ✔ | Node.js only | ✖ |
914
1032
  | Request cancelation | ✔ | ✖ | ✖ | ✔ |
915
1033
  | RFC compliant caching | ✔ | ✖ | ✖ | ✖ |
916
1034
  | Cookies (out-of-box) | ✔ | ✔ | ✖ | ✖ |
@@ -5,43 +5,16 @@ const is = require('@sindresorhus/is');
5
5
  const PCancelable = require('p-cancelable');
6
6
  const requestAsEventEmitter = require('./request-as-event-emitter');
7
7
  const {HTTPError, ParseError, ReadError} = require('./errors');
8
+ const {options: mergeOptions} = require('./merge');
9
+ const {reNormalize} = require('./normalize-arguments');
8
10
 
9
- module.exports = options => {
11
+ const asPromise = options => {
10
12
  const proxy = new EventEmitter();
11
13
 
12
14
  const promise = new PCancelable((resolve, reject, onCancel) => {
13
15
  const emitter = requestAsEventEmitter(options);
14
- let cancelOnRequest = false;
15
16
 
16
- onCancel(() => {
17
- cancelOnRequest = true;
18
- });
19
-
20
- emitter.on('request', request => {
21
- if (cancelOnRequest) {
22
- request.abort();
23
- return;
24
- }
25
-
26
- proxy.emit('request', request);
27
-
28
- const uploadComplete = () => {
29
- request.emit('upload-complete');
30
- };
31
-
32
- onCancel(() => {
33
- request.abort();
34
- });
35
-
36
- if (is.nodeStream(options.body)) {
37
- options.body.once('end', uploadComplete);
38
- options.body.pipe(request);
39
- options.body = undefined;
40
- return;
41
- }
42
-
43
- request.end(options.body, uploadComplete);
44
- });
17
+ onCancel(emitter.abort);
45
18
 
46
19
  emitter.on('response', async response => {
47
20
  proxy.emit('response', response);
@@ -56,11 +29,34 @@ module.exports = options => {
56
29
  return;
57
30
  }
58
31
 
59
- const {statusCode} = response;
60
32
  const limitStatusCode = options.followRedirect ? 299 : 399;
61
33
 
62
34
  response.body = data;
63
35
 
36
+ try {
37
+ for (const [index, hook] of Object.entries(options.hooks.afterResponse)) {
38
+ // eslint-disable-next-line no-await-in-loop
39
+ response = await hook(response, updatedOptions => {
40
+ updatedOptions = reNormalize(mergeOptions(options, {
41
+ ...updatedOptions,
42
+ retry: 0,
43
+ throwHttpErrors: false
44
+ }));
45
+
46
+ // Remove any further hooks for that request, because we we'll call them anyway.
47
+ // The loop continues. We don't want duplicates (asPromise recursion).
48
+ updatedOptions.hooks.afterResponse = options.hooks.afterResponse.slice(0, index);
49
+
50
+ return asPromise(updatedOptions);
51
+ });
52
+ }
53
+ } catch (error) {
54
+ reject(error);
55
+ return;
56
+ }
57
+
58
+ const {statusCode} = response;
59
+
64
60
  if (options.json && response.body) {
65
61
  try {
66
62
  response.body = JSON.parse(response.body);
@@ -69,23 +65,22 @@ module.exports = options => {
69
65
  const parseError = new ParseError(error, statusCode, options, data);
70
66
  Object.defineProperty(parseError, 'response', {value: response});
71
67
  reject(parseError);
68
+ return;
72
69
  }
73
70
  }
74
71
  }
75
72
 
76
73
  if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
77
- const error = new HTTPError(statusCode, response.statusMessage, response.headers, options);
74
+ const error = new HTTPError(response, options);
78
75
  Object.defineProperty(error, 'response', {value: response});
79
- emitter.emit('retry', error, retried => {
80
- if (!retried) {
81
- if (options.throwHttpErrors) {
82
- reject(error);
83
- return;
84
- }
85
-
86
- resolve(response);
76
+ if (emitter.retry(error) === false) {
77
+ if (options.throwHttpErrors) {
78
+ reject(error);
79
+ return;
87
80
  }
88
- });
81
+
82
+ resolve(response);
83
+ }
89
84
  return;
90
85
  }
91
86
 
@@ -94,6 +89,7 @@ module.exports = options => {
94
89
 
95
90
  emitter.once('error', reject);
96
91
  [
92
+ 'request',
97
93
  'redirect',
98
94
  'uploadProgress',
99
95
  'downloadProgress'
@@ -107,3 +103,5 @@ module.exports = options => {
107
103
 
108
104
  return promise;
109
105
  };
106
+
107
+ module.exports = asPromise;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
  const {PassThrough} = require('stream');
3
3
  const duplexer3 = require('duplexer3');
4
- const is = require('@sindresorhus/is');
5
4
  const requestAsEventEmitter = require('./request-as-event-emitter');
6
5
  const {HTTPError, ReadError} = require('./errors');
7
6
 
@@ -12,7 +11,7 @@ module.exports = options => {
12
11
  const piped = new Set();
13
12
  let isFinished = false;
14
13
 
15
- options.gotRetry.retries = () => 0;
14
+ options.retry.retries = () => 0;
16
15
 
17
16
  if (options.body) {
18
17
  proxy.write = () => {
@@ -20,33 +19,10 @@ module.exports = options => {
20
19
  };
21
20
  }
22
21
 
23
- const emitter = requestAsEventEmitter(options);
22
+ const emitter = requestAsEventEmitter(options, input);
24
23
 
25
- emitter.on('request', request => {
26
- proxy.emit('request', request);
27
- const uploadComplete = () => {
28
- request.emit('upload-complete');
29
- };
30
-
31
- if (is.nodeStream(options.body)) {
32
- options.body.once('end', uploadComplete);
33
- options.body.pipe(request);
34
- return;
35
- }
36
-
37
- if (options.body) {
38
- request.end(options.body, uploadComplete);
39
- return;
40
- }
41
-
42
- if (options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH') {
43
- input.once('end', uploadComplete);
44
- input.pipe(request);
45
- return;
46
- }
47
-
48
- request.end(uploadComplete);
49
- });
24
+ // Cancels the request
25
+ proxy._destroy = emitter.abort;
50
26
 
51
27
  emitter.on('response', response => {
52
28
  const {statusCode} = response;
@@ -56,7 +32,7 @@ module.exports = options => {
56
32
  });
57
33
 
58
34
  if (options.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
59
- proxy.emit('error', new HTTPError(statusCode, response.statusMessage, response.headers, options), null, response);
35
+ proxy.emit('error', new HTTPError(response, options), null, response);
60
36
  return;
61
37
  }
62
38
 
@@ -70,8 +46,8 @@ module.exports = options => {
70
46
  }
71
47
 
72
48
  for (const [key, value] of Object.entries(response.headers)) {
73
- // Got gives *uncompressed* data. Overriding `content-encoding` header would result in an error.
74
- // It's not possible to decompress uncompressed data, is it?
49
+ // Got gives *decompressed* data. Overriding `content-encoding` header would result in an error.
50
+ // It's not possible to decompress already decompressed data, is it?
75
51
  const allowed = options.decompress ? key !== 'content-encoding' : true;
76
52
  if (allowed) {
77
53
  destination.setHeader(key, value);
@@ -86,6 +62,7 @@ module.exports = options => {
86
62
 
87
63
  [
88
64
  'error',
65
+ 'request',
89
66
  'redirect',
90
67
  'uploadProgress',
91
68
  'downloadProgress'
package/source/create.js CHANGED
@@ -4,11 +4,9 @@ const asStream = require('./as-stream');
4
4
  const asPromise = require('./as-promise');
5
5
  const normalizeArguments = require('./normalize-arguments');
6
6
  const merge = require('./merge');
7
- const deepFreeze = require('./deep-freeze');
8
- const mergeInstances = require('./merge-instances');
7
+ const deepFreeze = require('./utils/deep-freeze');
9
8
 
10
9
  const getPromiseOrStream = options => options.stream ? asStream(options) : asPromise(options);
11
- const mergeOptions = (defaults, options = {}) => merge({}, defaults, options);
12
10
 
13
11
  const aliases = [
14
12
  'get',
@@ -21,7 +19,8 @@ const aliases = [
21
19
 
22
20
  const create = defaults => {
23
21
  defaults = merge({}, defaults);
24
- defaults.options = normalizeArguments.preNormalize(defaults.options);
22
+ normalizeArguments.preNormalize(defaults.options);
23
+
25
24
  if (!defaults.handler) {
26
25
  // This can't be getPromiseOrStream, because when merging
27
26
  // the chain would stop at this point and no further handlers would be called.
@@ -41,12 +40,23 @@ const create = defaults => {
41
40
  }
42
41
 
43
42
  got.create = create;
44
- got.extend = options => create({
45
- options: mergeOptions(defaults.options, options),
46
- handler: defaults.handler
47
- });
43
+ got.extend = options => {
44
+ let mutableDefaults;
45
+ if (options && Reflect.has(options, 'mutableDefaults')) {
46
+ mutableDefaults = options.mutableDefaults;
47
+ delete options.mutableDefaults;
48
+ } else {
49
+ mutableDefaults = defaults.mutableDefaults;
50
+ }
51
+
52
+ return create({
53
+ options: merge.options(defaults.options, options),
54
+ handler: defaults.handler,
55
+ mutableDefaults
56
+ });
57
+ };
48
58
 
49
- got.mergeInstances = (...args) => create(mergeInstances(args));
59
+ got.mergeInstances = (...args) => create(merge.instances(args));
50
60
 
51
61
  got.stream = (url, options) => got(url, {...options, stream: true});
52
62
 
@@ -55,12 +65,12 @@ const create = defaults => {
55
65
  got.stream[method] = (url, options) => got.stream(url, {...options, method});
56
66
  }
57
67
 
58
- Object.assign(got, {...errors, mergeOptions});
68
+ Object.assign(got, {...errors, mergeOptions: merge.options});
59
69
  Object.defineProperty(got, 'defaults', {
60
- value: deepFreeze(defaults),
61
- writable: false,
62
- enumerable: true,
63
- configurable: true
70
+ value: defaults.mutableDefaults ? defaults : deepFreeze(defaults),
71
+ writable: defaults.mutableDefaults,
72
+ configurable: defaults.mutableDefaults,
73
+ enumerable: true
64
74
  });
65
75
 
66
76
  return got;
package/source/errors.js CHANGED
@@ -59,7 +59,10 @@ module.exports.ParseError = class extends GotError {
59
59
  };
60
60
 
61
61
  module.exports.HTTPError = class extends GotError {
62
- constructor(statusCode, statusMessage, headers, opts) {
62
+ constructor(response, opts) {
63
+ const {statusCode} = response;
64
+ let {statusMessage} = response;
65
+
63
66
  if (statusMessage) {
64
67
  statusMessage = statusMessage.replace(/\r?\n/g, ' ').trim();
65
68
  } else {
@@ -69,7 +72,8 @@ module.exports.HTTPError = class extends GotError {
69
72
  this.name = 'HTTPError';
70
73
  this.statusCode = statusCode;
71
74
  this.statusMessage = statusMessage;
72
- this.headers = headers;
75
+ this.headers = response.headers;
76
+ this.body = response.body;
73
77
  }
74
78
  };
75
79
 
@@ -91,10 +95,10 @@ module.exports.UnsupportedProtocolError = class extends GotError {
91
95
  };
92
96
 
93
97
  module.exports.TimeoutError = class extends GotError {
94
- constructor(threshold, event, opts) {
95
- super(`Timeout awaiting '${event}' for ${threshold}ms`, {code: 'ETIMEDOUT'}, opts);
98
+ constructor(error, opts) {
99
+ super(error.message, {code: 'ETIMEDOUT'}, opts);
96
100
  this.name = 'TimeoutError';
97
- this.event = event;
101
+ this.event = error.event;
98
102
  }
99
103
  };
100
104
 
@@ -1,44 +1,15 @@
1
1
  'use strict';
2
- const {Transform} = require('stream');
3
2
  const decompressResponse = require('decompress-response');
4
3
  const is = require('@sindresorhus/is');
5
4
  const mimicResponse = require('mimic-response');
5
+ const progress = require('./progress');
6
6
 
7
- module.exports = (response, options, emitter, redirects) => {
7
+ module.exports = (response, options, emitter) => {
8
8
  const downloadBodySize = Number(response.headers['content-length']) || null;
9
- let downloaded = 0;
10
-
11
- const progressStream = new Transform({
12
- transform(chunk, encoding, callback) {
13
- downloaded += chunk.length;
14
-
15
- const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
16
-
17
- // Let `flush()` be responsible for emitting the last event
18
- if (percent < 1) {
19
- emitter.emit('downloadProgress', {
20
- percent,
21
- transferred: downloaded,
22
- total: downloadBodySize
23
- });
24
- }
25
-
26
- callback(null, chunk);
27
- },
28
-
29
- flush(callback) {
30
- emitter.emit('downloadProgress', {
31
- percent: 1,
32
- transferred: downloaded,
33
- total: downloadBodySize
34
- });
35
-
36
- callback();
37
- }
38
- });
9
+
10
+ const progressStream = progress.download(response, emitter, downloadBodySize);
39
11
 
40
12
  mimicResponse(response, progressStream);
41
- progressStream.redirectUrls = redirects;
42
13
 
43
14
  const newResponse = options.decompress === true &&
44
15
  is.function(decompressResponse) &&
package/source/index.js CHANGED
@@ -24,17 +24,25 @@ const defaults = {
24
24
  504
25
25
  ]
26
26
  },
27
- cache: false,
28
- decompress: true,
29
- useElectronNet: false,
30
- throwHttpErrors: true,
31
27
  headers: {
32
28
  'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`
33
29
  },
34
30
  hooks: {
35
- beforeRequest: []
36
- }
37
- }
31
+ beforeRequest: [],
32
+ beforeRedirect: [],
33
+ beforeRetry: [],
34
+ afterResponse: []
35
+ },
36
+ decompress: true,
37
+ throwHttpErrors: true,
38
+ followRedirect: true,
39
+ stream: false,
40
+ form: false,
41
+ json: false,
42
+ cache: false,
43
+ useElectronNet: false
44
+ },
45
+ mutableDefaults: false
38
46
  };
39
47
 
40
48
  const got = create(defaults);
@@ -1,3 +1,8 @@
1
1
  'use strict';
2
2
 
3
- module.exports = ['beforeRequest'];
3
+ module.exports = [
4
+ 'beforeRequest',
5
+ 'beforeRedirect',
6
+ 'beforeRetry',
7
+ 'afterResponse'
8
+ ];