got 11.6.2 → 11.8.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.
@@ -133,9 +133,10 @@ function asPromise(normalizedOptions) {
133
133
  reject(error);
134
134
  };
135
135
  request.once('error', onError);
136
+ const previousBody = request.options.body;
136
137
  request.once('retry', (newRetryCount, error) => {
137
- var _a;
138
- if (is_1.default.nodeStream((_a = error.request) === null || _a === void 0 ? void 0 : _a.options.body)) {
138
+ var _a, _b;
139
+ if (previousBody === ((_a = error.request) === null || _a === void 0 ? void 0 : _a.options.body) && is_1.default.nodeStream((_b = error.request) === null || _b === void 0 ? void 0 : _b.options.body)) {
139
140
  onError(error);
140
141
  return;
141
142
  }
@@ -11,7 +11,7 @@ const parseBody = (response, responseType, parseJson, encoding) => {
11
11
  return rawBody.length === 0 ? '' : parseJson(rawBody.toString());
12
12
  }
13
13
  if (responseType === 'buffer') {
14
- return Buffer.from(rawBody);
14
+ return rawBody;
15
15
  }
16
16
  throw new types_1.ParseError({
17
17
  message: `Unknown body type '${responseType}'`,
@@ -41,12 +41,8 @@ export interface Agents {
41
41
  }
42
42
  export declare const withoutBody: ReadonlySet<string>;
43
43
  export interface ToughCookieJar {
44
- getCookieString: ((currentUrl: string, options: {
45
- [key: string]: unknown;
46
- }, cb: (err: Error | null, cookies: string) => void) => void) & ((url: string, callback: (error: Error | null, cookieHeader: string) => void) => void);
47
- setCookie: ((cookieOrString: unknown, currentUrl: string, options: {
48
- [key: string]: unknown;
49
- }, cb: (err: Error | null, cookie: unknown) => void) => void) & ((rawCookie: string, url: string, callback: (error: Error | null, result: unknown) => void) => void);
44
+ getCookieString: ((currentUrl: string, options: Record<string, unknown>, cb: (err: Error | null, cookies: string) => void) => void) & ((url: string, callback: (error: Error | null, cookieHeader: string) => void) => void);
45
+ setCookie: ((cookieOrString: unknown, currentUrl: string, options: Record<string, unknown>, cb: (err: Error | null, cookie: unknown) => void) => void) & ((rawCookie: string, url: string, callback: (error: Error | null, result: unknown) => void) => void);
50
46
  }
51
47
  export interface PromiseCookieJar {
52
48
  getCookieString: (url: string) => Promise<string>;
@@ -352,9 +348,7 @@ interface PlainOptions extends URLOptions {
352
348
 
353
349
  __Note #2__: This option is not enumerable and will not be merged with the instance defaults.
354
350
  */
355
- form?: {
356
- [key: string]: any;
357
- };
351
+ form?: Record<string, any>;
358
352
  /**
359
353
  JSON body. If the `Content-Type` header is not set, it will be set to `application/json`.
360
354
 
@@ -362,9 +356,7 @@ interface PlainOptions extends URLOptions {
362
356
 
363
357
  __Note #2__: This option is not enumerable and will not be merged with the instance defaults.
364
358
  */
365
- json?: {
366
- [key: string]: any;
367
- };
359
+ json?: Record<string, any>;
368
360
  /**
369
361
  The URL to request, as a string, a [`https.request` options object](https://nodejs.org/api/https.html#https_https_request_options_callback), or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
370
362
 
@@ -415,9 +407,7 @@ interface PlainOptions extends URLOptions {
415
407
  //=> 'key=a&key=b'
416
408
  ```
417
409
  */
418
- searchParams?: string | {
419
- [key: string]: string | number | boolean | null | undefined;
420
- } | URLSearchParams;
410
+ searchParams?: string | Record<string, string | number | boolean | null | undefined> | URLSearchParams;
421
411
  /**
422
412
  An instance of [`CacheableLookup`](https://github.com/szmarczak/cacheable-lookup) used for making DNS lookups.
423
413
  Useful when making lots of requests to different *public* hostnames.
@@ -738,6 +728,7 @@ export interface HTTPSOptions {
738
728
  The passphrase to decrypt the `options.https.key` (if different keys have different passphrases refer to `options.https.key` documentation).
739
729
  */
740
730
  passphrase?: SecureContextOptions['passphrase'];
731
+ pfx?: SecureContextOptions['pfx'];
741
732
  }
742
733
  interface NormalizedPlainOptions extends PlainOptions {
743
734
  method: Method;
@@ -29,7 +29,7 @@ const is_response_ok_1 = require("./utils/is-response-ok");
29
29
  const deprecation_warning_1 = require("../utils/deprecation-warning");
30
30
  const normalize_arguments_1 = require("../as-promise/normalize-arguments");
31
31
  const calculate_retry_delay_1 = require("./calculate-retry-delay");
32
- const globalDnsCache = new cacheable_lookup_1.default();
32
+ let globalDnsCache;
33
33
  const kRequest = Symbol('request');
34
34
  const kResponse = Symbol('response');
35
35
  const kResponseSize = Symbol('responseSize');
@@ -152,7 +152,7 @@ class RequestError extends Error {
152
152
  }
153
153
  this.timings = (_a = this.request) === null || _a === void 0 ? void 0 : _a.timings;
154
154
  // Recover the original stacktrace
155
- if (!is_1.default.undefined(error.stack)) {
155
+ if (is_1.default.string(error.stack) && is_1.default.string(this.stack)) {
156
156
  const indexOfMessage = this.stack.indexOf(this.message) + this.message.length;
157
157
  const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse();
158
158
  const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse();
@@ -295,18 +295,28 @@ class Request extends stream_1.Duplex {
295
295
  if (json || body || form) {
296
296
  this._lockWrite();
297
297
  }
298
- (async (nonNormalizedOptions) => {
299
- var _a;
298
+ if (exports.kIsNormalizedAlready in options) {
299
+ this.options = options;
300
+ }
301
+ else {
300
302
  try {
301
- if (nonNormalizedOptions.body instanceof fs_1.ReadStream) {
302
- await waitForOpenFile(nonNormalizedOptions.body);
303
- }
304
- if (exports.kIsNormalizedAlready in nonNormalizedOptions) {
305
- this.options = nonNormalizedOptions;
303
+ // @ts-expect-error Common TypeScript bug saying that `this.constructor` is not accessible
304
+ this.options = this.constructor.normalizeArguments(url, options, defaults);
305
+ }
306
+ catch (error) {
307
+ // TODO: Move this to `_destroy()`
308
+ if (is_1.default.nodeStream(options.body)) {
309
+ options.body.destroy();
306
310
  }
307
- else {
308
- // @ts-expect-error Common TypeScript bug saying that `this.constructor` is not accessible
309
- this.options = this.constructor.normalizeArguments(url, nonNormalizedOptions, defaults);
311
+ this.destroy(error);
312
+ return;
313
+ }
314
+ }
315
+ (async () => {
316
+ var _a;
317
+ try {
318
+ if (this.options.body instanceof fs_1.ReadStream) {
319
+ await waitForOpenFile(this.options.body);
310
320
  }
311
321
  const { url: normalizedURL } = this.options;
312
322
  if (!normalizedURL) {
@@ -338,7 +348,7 @@ class Request extends stream_1.Duplex {
338
348
  this.destroy(error);
339
349
  }
340
350
  }
341
- })(options);
351
+ })();
342
352
  }
343
353
  static normalizeArguments(url, options, defaults) {
344
354
  var _a, _b, _c, _d, _e;
@@ -394,6 +404,7 @@ class Request extends stream_1.Duplex {
394
404
  is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.key);
395
405
  is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificate);
396
406
  is_1.assert.any([is_1.default.string, is_1.default.undefined], options.https.passphrase);
407
+ is_1.assert.any([is_1.default.string, is_1.default.buffer, is_1.default.array, is_1.default.undefined], options.https.pfx);
397
408
  }
398
409
  is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cacheOptions);
399
410
  // `options.method`
@@ -472,6 +483,9 @@ class Request extends stream_1.Duplex {
472
483
  options.url = options_to_url_1.default(options.prefixUrl, options);
473
484
  }
474
485
  if (options.url) {
486
+ if ('port' in options) {
487
+ delete options.port;
488
+ }
475
489
  // Make it possible to change `options.prefixUrl`
476
490
  let { prefixUrl } = options;
477
491
  Object.defineProperty(options, 'prefixUrl', {
@@ -572,6 +586,9 @@ class Request extends stream_1.Duplex {
572
586
  options.cacheOptions = { ...options.cacheOptions };
573
587
  // `options.dnsCache`
574
588
  if (options.dnsCache === true) {
589
+ if (!globalDnsCache) {
590
+ globalDnsCache = new cacheable_lookup_1.default();
591
+ }
575
592
  options.dnsCache = globalDnsCache;
576
593
  }
577
594
  else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) {
@@ -614,7 +631,7 @@ class Request extends stream_1.Duplex {
614
631
  if (defaults && !areHooksDefault) {
615
632
  for (const event of exports.knownHookEvents) {
616
633
  const defaultHooks = defaults.hooks[event];
617
- if (defaultHooks.length !== 0) {
634
+ if (defaultHooks.length > 0) {
618
635
  // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044
619
636
  options.hooks[event] = [
620
637
  ...defaults.hooks[event],
@@ -649,6 +666,9 @@ class Request extends stream_1.Duplex {
649
666
  if ('passphrase' in options) {
650
667
  deprecation_warning_1.default('"options.passphrase" was never documented, please use "options.https.passphrase"');
651
668
  }
669
+ if ('pfx' in options) {
670
+ deprecation_warning_1.default('"options.pfx" was never documented, please use "options.https.pfx"');
671
+ }
652
672
  // Other options
653
673
  if ('followRedirects' in options) {
654
674
  throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.');
@@ -826,6 +846,8 @@ class Request extends stream_1.Duplex {
826
846
  if ('form' in options) {
827
847
  delete options.form;
828
848
  }
849
+ this[kBody] = undefined;
850
+ delete options.headers['content-length'];
829
851
  }
830
852
  if (this.redirects.length >= options.maxRedirects) {
831
853
  this._beforeError(new MaxRedirectsError(this));
@@ -850,16 +872,14 @@ class Request extends stream_1.Duplex {
850
872
  delete options.headers.authorization;
851
873
  }
852
874
  if (options.username || options.password) {
853
- // TODO: Fix this ignore.
854
- // @ts-expect-error
855
- delete options.username;
856
- // @ts-expect-error
857
- delete options.password;
858
- }
859
- if ('port' in options) {
860
- delete options.port;
875
+ options.username = '';
876
+ options.password = '';
861
877
  }
862
878
  }
879
+ else {
880
+ redirectUrl.username = options.username;
881
+ redirectUrl.password = options.password;
882
+ }
863
883
  this.redirects.push(redirectString);
864
884
  options.url = redirectUrl;
865
885
  for (const hook of options.hooks.beforeRedirect) {
@@ -933,12 +953,7 @@ class Request extends stream_1.Duplex {
933
953
  request.destroy();
934
954
  // Node.js <= 12.18.2 mistakenly emits the response `end` first.
935
955
  (_a = request.res) === null || _a === void 0 ? void 0 : _a.removeAllListeners('end');
936
- if (error instanceof timed_out_1.TimeoutError) {
937
- error = new TimeoutError(error, this.timings, this);
938
- }
939
- else {
940
- error = new RequestError(error.message, error, this);
941
- }
956
+ error = error instanceof timed_out_1.TimeoutError ? new TimeoutError(error, this.timings, this) : new RequestError(error.message, error, this);
942
957
  this._beforeError(error);
943
958
  });
944
959
  this[kUnproxyEvents] = proxy_events_1.default(request, this, proxiedRequestEvents);
@@ -1026,6 +1041,9 @@ class Request extends stream_1.Duplex {
1026
1041
  break;
1027
1042
  }
1028
1043
  }
1044
+ if (options.body && this[kBody] !== options.body) {
1045
+ this[kBody] = options.body;
1046
+ }
1029
1047
  const { agent, request, timeout, url } = options;
1030
1048
  if (options.dnsCache && !('lookup' in options)) {
1031
1049
  options.lookup = options.dnsCache.lookup;
@@ -1098,6 +1116,9 @@ class Request extends stream_1.Duplex {
1098
1116
  if (options.https.passphrase) {
1099
1117
  requestOptions.passphrase = options.https.passphrase;
1100
1118
  }
1119
+ if (options.https.pfx) {
1120
+ requestOptions.pfx = options.https.pfx;
1121
+ }
1101
1122
  }
1102
1123
  try {
1103
1124
  let requestOrResponse = await fn(url, requestOptions);
@@ -1129,6 +1150,9 @@ class Request extends stream_1.Duplex {
1129
1150
  if (options.https.passphrase) {
1130
1151
  delete requestOptions.passphrase;
1131
1152
  }
1153
+ if (options.https.pfx) {
1154
+ delete requestOptions.pfx;
1155
+ }
1132
1156
  }
1133
1157
  if (isClientRequest(requestOrResponse)) {
1134
1158
  this._onRequest(requestOrResponse);
@@ -1293,7 +1317,7 @@ class Request extends stream_1.Duplex {
1293
1317
  });
1294
1318
  // TODO: What happens if it's from cache? Then this[kRequest] won't be defined.
1295
1319
  this[kRequest].write(chunk, encoding, (error) => {
1296
- if (!error && this._progressCallbacks.length !== 0) {
1320
+ if (!error && this._progressCallbacks.length > 0) {
1297
1321
  this._progressCallbacks.shift()();
1298
1322
  }
1299
1323
  callback(error);
@@ -1357,7 +1381,7 @@ class Request extends stream_1.Duplex {
1357
1381
  */
1358
1382
  get ip() {
1359
1383
  var _a;
1360
- return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket.remoteAddress;
1384
+ return (_a = this.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress;
1361
1385
  }
1362
1386
  /**
1363
1387
  Indicates whether the request has been aborted or not.
@@ -1367,8 +1391,8 @@ class Request extends stream_1.Duplex {
1367
1391
  return ((_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroyed) !== null && _b !== void 0 ? _b : this.destroyed) && !((_c = this[kOriginalResponse]) === null || _c === void 0 ? void 0 : _c.complete);
1368
1392
  }
1369
1393
  get socket() {
1370
- var _a;
1371
- return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket;
1394
+ var _a, _b;
1395
+ return (_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket) !== null && _b !== void 0 ? _b : undefined;
1372
1396
  }
1373
1397
  /**
1374
1398
  Progress event for downloading (receiving a response).
@@ -23,6 +23,9 @@ exports.default = async (body, headers) => {
23
23
  }
24
24
  if (body instanceof fs_1.ReadStream) {
25
25
  const { size } = await statAsync(body.path);
26
+ if (size === 0) {
27
+ return undefined;
28
+ }
26
29
  return size;
27
30
  }
28
31
  return undefined;
@@ -14,7 +14,7 @@ exports.default = (url) => {
14
14
  href: url.href,
15
15
  path: `${url.pathname || ''}${url.search || ''}`
16
16
  };
17
- if (is_1.default.string(url.port) && url.port.length !== 0) {
17
+ if (is_1.default.string(url.port) && url.port.length > 0) {
18
18
  options.port = Number(url.port);
19
19
  }
20
20
  if (url.username || url.password) {
@@ -82,7 +82,7 @@ const create = (defaults) => {
82
82
  return result;
83
83
  }));
84
84
  // Got interface
85
- const got = ((url, options, _defaults) => {
85
+ const got = ((url, options = {}, _defaults) => {
86
86
  var _a, _b;
87
87
  let iteration = 0;
88
88
  const iterateHandlers = (newOptions) => {
@@ -103,7 +103,7 @@ const create = (defaults) => {
103
103
  let initHookError;
104
104
  try {
105
105
  callInitHooks(defaults.options.hooks.init, options);
106
- callInitHooks((_a = options === null || options === void 0 ? void 0 : options.hooks) === null || _a === void 0 ? void 0 : _a.init, options);
106
+ callInitHooks((_a = options.hooks) === null || _a === void 0 ? void 0 : _a.init, options);
107
107
  }
108
108
  catch (error) {
109
109
  initHookError = error;
@@ -117,11 +117,11 @@ const create = (defaults) => {
117
117
  return iterateHandlers(normalizedOptions);
118
118
  }
119
119
  catch (error) {
120
- if (options === null || options === void 0 ? void 0 : options.isStream) {
120
+ if (options.isStream) {
121
121
  throw error;
122
122
  }
123
123
  else {
124
- return create_rejection_1.default(error, defaults.options.hooks.beforeError, (_b = options === null || options === void 0 ? void 0 : options.hooks) === null || _b === void 0 ? void 0 : _b.beforeError);
124
+ return create_rejection_1.default(error, defaults.options.hooks.beforeError, (_b = options.hooks) === null || _b === void 0 ? void 0 : _b.beforeError);
125
125
  }
126
126
  }
127
127
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "11.6.2",
3
+ "version": "11.8.2",
4
4
  "description": "Human-friendly and powerful HTTP request library for Node.js",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
@@ -43,7 +43,7 @@
43
43
  "ky"
44
44
  ],
45
45
  "dependencies": {
46
- "@sindresorhus/is": "^3.1.1",
46
+ "@sindresorhus/is": "^4.0.0",
47
47
  "@szmarczak/http-timer": "^4.0.5",
48
48
  "@types/cacheable-request": "^6.0.1",
49
49
  "@types/responselike": "^1.0.0",
@@ -61,7 +61,7 @@
61
61
  "@sinonjs/fake-timers": "^6.0.1",
62
62
  "@types/benchmark": "^1.0.33",
63
63
  "@types/express": "^4.17.7",
64
- "@types/node": "^14.6.0",
64
+ "@types/node": "^14.14.0",
65
65
  "@types/node-fetch": "^2.5.7",
66
66
  "@types/pem": "^1.9.5",
67
67
  "@types/pify": "^3.0.2",
@@ -87,11 +87,11 @@
87
87
  "pify": "^5.0.0",
88
88
  "sinon": "^9.0.3",
89
89
  "slow-stream": "0.0.4",
90
- "tempy": "^0.6.0",
90
+ "tempy": "^1.0.0",
91
91
  "to-readable-stream": "^2.1.0",
92
92
  "tough-cookie": "^4.0.0",
93
- "typescript": "^4.0.2",
94
- "xo": "^0.33.0"
93
+ "typescript": "4.0.3",
94
+ "xo": "^0.34.1"
95
95
  },
96
96
  "types": "dist/source",
97
97
  "sideEffects": false,
@@ -123,7 +123,7 @@
123
123
  "node/prefer-global/url": "off",
124
124
  "node/prefer-global/url-search-params": "off",
125
125
  "import/no-anonymous-default-export": "off",
126
- "@typescript-eslint/no-invalid-void-type": "off"
126
+ "@typescript-eslint/no-implicit-any-catch": "off"
127
127
  }
128
128
  },
129
129
  "runkitExampleFilename": "./documentation/examples/runkit-example.js"
package/readme.md CHANGED
@@ -107,16 +107,16 @@ const got = require('got');
107
107
  const pipeline = promisify(stream.pipeline);
108
108
 
109
109
  (async () => {
110
- await pipeline(
111
- got.stream('https://sindresorhus.com'),
112
- fs.createWriteStream('index.html')
113
- );
114
-
115
- // For POST, PUT, and PATCH methods `got.stream` returns a `stream.Writable`
116
- await pipeline(
117
- fs.createReadStream('index.html'),
118
- got.stream.post('https://sindresorhus.com')
119
- );
110
+ await pipeline(
111
+ got.stream('https://sindresorhus.com'),
112
+ fs.createWriteStream('index.html')
113
+ );
114
+
115
+ // For POST, PUT, PATCH, and DELETE methods, `got.stream` returns a `stream.Writable`.
116
+ await pipeline(
117
+ fs.createReadStream('index.html'),
118
+ got.stream.post('https://sindresorhus.com')
119
+ );
120
120
  })();
121
121
  ```
122
122
 
@@ -146,7 +146,7 @@ If no protocol is specified, it will throw a `TypeError`.
146
146
 
147
147
  **Note:** The query string is **not** parsed as search params. Example:
148
148
 
149
- ```
149
+ ```js
150
150
  got('https://example.com/?query=a b'); //=> https://example.com/?query=a%20b
151
151
  got('https://example.com/', {searchParams: {query: 'a b'}}); //=> https://example.com/?query=a+b
152
152
 
@@ -306,7 +306,7 @@ Example:
306
306
  const bufferPromise = responsePromise.buffer();
307
307
  const jsonPromise = responsePromise.json();
308
308
 
309
- const [response, buffer, json] = Promise.all([responsePromise, bufferPromise, jsonPromise]);
309
+ const [response, buffer, json] = await Promise.all([responsePromise, bufferPromise, jsonPromise]);
310
310
  // `response` is an instance of Got Response
311
311
  // `buffer` is an instance of Buffer
312
312
  // `json` is an object
@@ -321,6 +321,8 @@ const body = await got(url).json();
321
321
  const body = await got(url, {responseType: 'json', resolveBodyOnly: true});
322
322
  ```
323
323
 
324
+ **Note:** `buffer` will return the raw body buffer. Modifying it will also alter the result of `promise.text()` and `promise.json()`. Before overwritting the buffer, please copy it first via `Buffer.from(buffer)`. See https://github.com/nodejs/node/issues/27080
325
+
324
326
  ###### parseJson
325
327
 
326
328
  Type: `(text: string) => unknown`\
@@ -653,6 +655,15 @@ await got('https://api6.ipify.org', {
653
655
  });
654
656
  ```
655
657
 
658
+ ###### lookup
659
+
660
+ Type: `Function`\
661
+ Default: [`dns.lookup`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback)
662
+
663
+ Custom DNS resolution logic.
664
+
665
+ The function signature is the same as [`dns.lookup`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
666
+
656
667
  ###### request
657
668
 
658
669
  Type: `Function`\
@@ -738,6 +749,24 @@ Default: `[]`
738
749
 
739
750
  Called with [normalized](source/core/index.ts) [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) when you want to create an API client that, for example, uses HMAC-signing.
740
751
 
752
+ **Note:** Changing `options.json` or `options.form` has no effect on the request, you should change `options.body` instead. If needed, update the `options.headers` accordingly. Example:
753
+
754
+ ```js
755
+ const got = require('got');
756
+
757
+ got.post({
758
+ json: {payload: 'old'},
759
+ hooks: {
760
+ beforeRequest: [
761
+ options => {
762
+ options.body = JSON.stringify({payload: 'new'});
763
+ options.headers['content-length'] = options.body.length.toString();
764
+ }
765
+ ]
766
+ }
767
+ });
768
+ ```
769
+
741
770
  **Tip:** You can override the `request` function by returning a [`ClientRequest`-like](https://nodejs.org/api/http.html#http_class_http_clientrequest) instance or a [`IncomingMessage`-like](https://nodejs.org/api/http.html#http_class_http_incomingmessage) instance. This is very useful when creating a custom cache mechanism.
742
771
 
743
772
  ###### hooks.beforeRedirect
@@ -853,12 +882,12 @@ got('https://api.github.com/some-endpoint', {
853
882
  beforeError: [
854
883
  error => {
855
884
  const {response} = error;
856
- if (response && response.body) {
885
+ if (response && response.body) {
857
886
  error.name = 'GitHubError';
858
887
  error.message = `${response.body.message} (${response.statusCode})`;
859
888
  }
860
889
 
861
- return error;
890
+ return error;
862
891
  }
863
892
  ]
864
893
  }
@@ -1022,7 +1051,24 @@ Type: `string`
1022
1051
 
1023
1052
  The passphrase to decrypt the `options.https.key` (if different keys have different passphrases refer to `options.https.key` documentation).
1024
1053
 
1025
- ##### Examples for `https.key`, `https.certificate` and `https.passphrase`
1054
+ ##### https.pfx
1055
+
1056
+ Type: `string | Buffer | Array<string | Buffer | object>`
1057
+
1058
+ [PFX or PKCS12](https://en.wikipedia.org/wiki/PKCS_12) encoded private key and certificate chain. Using `options.https.pfx` is an alternative to providing `options.https.key` and `options.https.certificate` individually. A PFX is usually encrypted, and if it is, `options.https.passphrase` will be used to decrypt it.
1059
+
1060
+ Multiple PFX's can be be provided as an array of unencrypted buffers or an array of objects like:
1061
+
1062
+ ```ts
1063
+ {
1064
+ buffer: string | Buffer,
1065
+ passphrase?: string
1066
+ }
1067
+ ```
1068
+
1069
+ This object form can only occur in an array. If the provided buffers are encrypted, `object.passphrase` can be used to decrypt them. If `object.passphrase` is not provided, `options.https.passphrase` will be used for decryption.
1070
+
1071
+ ##### Examples for `https.key`, `https.certificate`, `https.passphrase`, and `https.pfx`
1026
1072
 
1027
1073
  ```js
1028
1074
  // Single key with certificate
@@ -1069,6 +1115,45 @@ got('https://example.com', {
1069
1115
  ]
1070
1116
  }
1071
1117
  });
1118
+
1119
+ // Single encrypted PFX with passphrase
1120
+ got('https://example.com', {
1121
+ https: {
1122
+ pfx: fs.readFileSync('./fake.pfx'),
1123
+ passphrase: 'passphrase'
1124
+ }
1125
+ });
1126
+
1127
+ // Multiple encrypted PFX's with different passphrases
1128
+ got('https://example.com', {
1129
+ https: {
1130
+ pfx: [
1131
+ {
1132
+ buffer: fs.readFileSync('./key1.pfx'),
1133
+ passphrase: 'passphrase1'
1134
+ },
1135
+ {
1136
+ buffer: fs.readFileSync('./key2.pfx'),
1137
+ passphrase: 'passphrase2'
1138
+ }
1139
+ ]
1140
+ }
1141
+ });
1142
+
1143
+ // Multiple encrypted PFX's with single passphrase
1144
+ got('https://example.com', {
1145
+ https: {
1146
+ passphrase: 'passphrase',
1147
+ pfx: [
1148
+ {
1149
+ buffer: fs.readFileSync('./key1.pfx')
1150
+ },
1151
+ {
1152
+ buffer: fs.readFileSync('./key2.pfx')
1153
+ }
1154
+ ]
1155
+ }
1156
+ });
1072
1157
  ```
1073
1158
 
1074
1159
  ##### https.rejectUnauthorized