got 9.5.1 → 9.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "9.5.1",
3
+ "version": "9.6.0",
4
4
  "description": "Simplified HTTP requests",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
@@ -47,7 +47,7 @@
47
47
  "url-parse-lax": "^3.0.0"
48
48
  },
49
49
  "devDependencies": {
50
- "ava": "^1.0.1",
50
+ "ava": "^1.1.0",
51
51
  "coveralls": "^3.0.0",
52
52
  "delay": "^4.1.0",
53
53
  "form-data": "^2.3.3",
@@ -61,8 +61,8 @@
61
61
  "slow-stream": "0.0.4",
62
62
  "tempfile": "^2.0.0",
63
63
  "tempy": "^0.2.1",
64
- "tough-cookie": "^2.4.3",
65
- "xo": "^0.23.0"
64
+ "tough-cookie": "^3.0.0",
65
+ "xo": "^0.24.0"
66
66
  },
67
67
  "ava": {
68
68
  "concurrency": 4
package/readme.md CHANGED
@@ -35,7 +35,7 @@ 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
- - [Hooks](https://github.com/sindresorhus/got#hooks)
38
+ - [Hooks](#hooks)
39
39
  - [Instances with custom defaults](#instances)
40
40
  - [Composable](advanced-creation.md#merging-instances)
41
41
  - [Electron support](#useelectronnet)
@@ -351,6 +351,17 @@ Type: `Object<string, Function[]>`
351
351
 
352
352
  Hooks allow modifications during the request lifecycle. Hook functions may be async and are run serially.
353
353
 
354
+ ###### hooks.init
355
+
356
+ Type: `Function[]`<br>
357
+ Default: `[]`
358
+
359
+ Called with plain [request options](#options), right before their normalization. This is especially useful in conjunction with [`got.extend()`](#instances) and [`got.create()`](advanced-creation.md) when the input needs custom handling.
360
+
361
+ See the [Request migration guide](migration-guides.md#breaking-changes) for an example.
362
+
363
+ **Note**: This hook must be synchronous!
364
+
354
365
  ###### hooks.beforeRequest
355
366
 
356
367
  Type: `Function[]`<br>
@@ -447,6 +458,35 @@ const instance = got.extend({
447
458
  });
448
459
  ```
449
460
 
461
+ ###### hooks.beforeError
462
+
463
+ Type: `Function[]`<br>
464
+ Default: `[]`
465
+
466
+ Called with an `Error` instance. The error is passed to the hook right before it's thrown. This is especially useful when you want to have more detailed errors.
467
+
468
+ **Note**: Errors thrown while normalizing input options are thrown directly and not part of this hook.
469
+
470
+ ```js
471
+ const got = require('got');
472
+
473
+ got('api.github.com/some-endpoint', {
474
+ hooks: {
475
+ onError: [
476
+ error => {
477
+ const {response} = error;
478
+ if (response && response.body) {
479
+ error.name = 'GitHubError';
480
+ error.message = `${response.body.message} (${error.statusCode})`;
481
+ }
482
+
483
+ return error;
484
+ }
485
+ ]
486
+ }
487
+ });
488
+ ```
489
+
450
490
  #### Response
451
491
 
452
492
  The response object will typically be a [Node.js HTTP response stream](https://nodejs.org/api/http.html#http_class_http_incomingmessage), however, if returned from the cache it will be a [response-like object](https://github.com/lukechilds/responselike) which behaves in the same way.
@@ -81,6 +81,7 @@ const asPromise = options => {
81
81
 
82
82
  resolve(response);
83
83
  }
84
+
84
85
  return;
85
86
  }
86
87
 
@@ -83,6 +83,7 @@ module.exports = options => {
83
83
 
84
84
  return result;
85
85
  };
86
+
86
87
  proxy.unpipe = stream => {
87
88
  piped.delete(stream);
88
89
  return unpipe(stream);
package/source/errors.js CHANGED
@@ -69,6 +69,7 @@ module.exports.HTTPError = class extends GotError {
69
69
  } else {
70
70
  statusMessage = http.STATUS_CODES[statusCode];
71
71
  }
72
+
72
73
  super(`Response code ${statusCode} (${statusMessage})`, {}, options);
73
74
  this.name = 'HTTPError';
74
75
  this.statusCode = statusCode;
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = [
4
+ 'beforeError',
5
+ 'init',
4
6
  'beforeRequest',
5
7
  'beforeRedirect',
6
8
  'beforeRetry',
@@ -11,8 +11,15 @@ const knownHookEvents = require('./known-hook-events');
11
11
 
12
12
  const retryAfterStatusCodes = new Set([413, 429, 503]);
13
13
 
14
- // `preNormalize` handles static things (lowercasing headers; normalizing baseUrl, timeout, retry)
15
- // While `normalize` does `preNormalize` + handles things which need to be reworked when user changes them
14
+ // `preNormalize` handles static options (e.g. headers).
15
+ // For example, when you create a custom instance and make a request
16
+ // with no static changes, they won't be normalized again.
17
+ //
18
+ // `normalize` operates on dynamic options - they cannot be saved.
19
+ // For example, `body` is everytime different per request.
20
+ // When it's done normalizing the new options, it performs merge()
21
+ // on the prenormalized options and the normalized ones.
22
+
16
23
  const preNormalize = (options, defaults) => {
17
24
  if (is.nullOrUndefined(options.headers)) {
18
25
  options.headers = {};
@@ -49,6 +56,7 @@ const preNormalize = (options, defaults) => {
49
56
  } else if (is.object(options.timeout)) {
50
57
  options.gotTimeout = options.timeout;
51
58
  }
59
+
52
60
  delete options.timeout;
53
61
 
54
62
  const {retry} = options;
@@ -125,6 +133,14 @@ const normalize = (url, options, defaults) => {
125
133
  // Override both null/undefined with default protocol
126
134
  options = merge({path: ''}, url, {protocol: url.protocol || 'https:'}, options);
127
135
 
136
+ for (const hook of options.hooks.init) {
137
+ const called = hook(options);
138
+
139
+ if (is.promise(called)) {
140
+ throw new TypeError('The `init` hook must be a synchronous function');
141
+ }
142
+ }
143
+
128
144
  const {baseUrl} = options;
129
145
  Object.defineProperty(options, 'baseUrl', {
130
146
  set: () => {
@@ -138,6 +154,7 @@ const normalize = (url, options, defaults) => {
138
154
  if (!is.string(query)) {
139
155
  options.query = (new URLSearchParams(query)).toString();
140
156
  }
157
+
141
158
  options.path = `${options.path.split('?')[0]}?${options.query}`;
142
159
  delete options.query;
143
160
  }
@@ -33,6 +33,19 @@ module.exports = (options, input) => {
33
33
  const getCookieString = options.cookieJar ? util.promisify(options.cookieJar.getCookieString.bind(options.cookieJar)) : null;
34
34
  const agents = is.object(options.agent) ? options.agent : null;
35
35
 
36
+ const emitError = async error => {
37
+ try {
38
+ for (const hook of options.hooks.beforeError) {
39
+ // eslint-disable-next-line no-await-in-loop
40
+ error = await hook(error);
41
+ }
42
+
43
+ emitter.emit('error', error);
44
+ } catch (error2) {
45
+ emitter.emit('error', error2);
46
+ }
47
+ };
48
+
36
49
  const get = async options => {
37
50
  const currentUrl = redirectString || requestUrl;
38
51
 
@@ -141,7 +154,7 @@ module.exports = (options, input) => {
141
154
 
142
155
  getResponse(response, options, emitter);
143
156
  } catch (error) {
144
- emitter.emit('error', error);
157
+ emitError(error);
145
158
  }
146
159
  };
147
160
 
@@ -166,7 +179,7 @@ module.exports = (options, input) => {
166
179
  }
167
180
 
168
181
  if (emitter.retry(error) === false) {
169
- emitter.emit('error', error);
182
+ emitError(error);
170
183
  }
171
184
  });
172
185
 
@@ -198,7 +211,7 @@ module.exports = (options, input) => {
198
211
  request.end(uploadComplete);
199
212
  }
200
213
  } catch (error) {
201
- emitter.emit('error', new RequestError(error, options));
214
+ emitError(new RequestError(error, options));
202
215
  }
203
216
  };
204
217
 
@@ -208,9 +221,9 @@ module.exports = (options, input) => {
208
221
 
209
222
  cacheRequest.once('error', error => {
210
223
  if (error instanceof CacheableRequest.RequestError) {
211
- emitter.emit('error', new RequestError(error, options));
224
+ emitError(new RequestError(error, options));
212
225
  } else {
213
- emitter.emit('error', new CacheError(error, options));
226
+ emitError(new CacheError(error, options));
214
227
  }
215
228
  });
216
229
 
@@ -220,7 +233,7 @@ module.exports = (options, input) => {
220
233
  try {
221
234
  handleRequest(fn.request(options, handleResponse));
222
235
  } catch (error) {
223
- emitter.emit('error', new RequestError(error, options));
236
+ emitError(new RequestError(error, options));
224
237
  }
225
238
  }
226
239
  };
@@ -231,7 +244,7 @@ module.exports = (options, input) => {
231
244
  try {
232
245
  backoff = options.retry.retries(++retryCount, error);
233
246
  } catch (error2) {
234
- emitter.emit('error', error2);
247
+ emitError(error2);
235
248
  return;
236
249
  }
237
250
 
@@ -245,7 +258,7 @@ module.exports = (options, input) => {
245
258
 
246
259
  await get(options);
247
260
  } catch (error) {
248
- emitter.emit('error', error);
261
+ emitError(error);
249
262
  }
250
263
  };
251
264
 
@@ -291,7 +304,7 @@ module.exports = (options, input) => {
291
304
 
292
305
  await get(options);
293
306
  } catch (error) {
294
- emitter.emit('error', error);
307
+ emitError(error);
295
308
  }
296
309
  });
297
310