got 11.5.1 → 11.6.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.
Files changed (52) hide show
  1. package/dist/source/as-promise/create-rejection.d.ts +0 -0
  2. package/dist/source/as-promise/create-rejection.js +0 -0
  3. package/dist/source/as-promise/index.d.ts +1 -3
  4. package/dist/source/as-promise/index.js +44 -125
  5. package/dist/source/as-promise/normalize-arguments.d.ts +3 -0
  6. package/dist/source/as-promise/normalize-arguments.js +78 -0
  7. package/dist/source/as-promise/parse-body.d.ts +3 -0
  8. package/dist/source/as-promise/parse-body.js +25 -0
  9. package/dist/source/as-promise/types.d.ts +206 -24
  10. package/dist/source/as-promise/types.js +18 -7
  11. package/dist/source/{as-promise → core}/calculate-retry-delay.d.ts +2 -1
  12. package/dist/source/core/calculate-retry-delay.js +29 -0
  13. package/dist/source/core/index.d.ts +822 -5
  14. package/dist/source/core/index.js +234 -46
  15. package/dist/source/core/utils/dns-ip-version.d.ts +0 -0
  16. package/dist/source/core/utils/dns-ip-version.js +0 -0
  17. package/dist/source/core/utils/get-body-size.d.ts +0 -0
  18. package/dist/source/core/utils/get-body-size.js +0 -0
  19. package/dist/source/core/utils/get-buffer.d.ts +0 -0
  20. package/dist/source/core/utils/get-buffer.js +0 -0
  21. package/dist/source/core/utils/is-form-data.d.ts +0 -0
  22. package/dist/source/core/utils/is-form-data.js +0 -0
  23. package/dist/source/core/utils/is-response-ok.d.ts +2 -0
  24. package/dist/source/core/utils/is-response-ok.js +8 -0
  25. package/dist/source/core/utils/options-to-url.d.ts +0 -0
  26. package/dist/source/core/utils/options-to-url.js +0 -0
  27. package/dist/source/core/utils/proxy-events.d.ts +0 -0
  28. package/dist/source/core/utils/proxy-events.js +0 -0
  29. package/dist/source/core/utils/timed-out.d.ts +0 -0
  30. package/dist/source/core/utils/timed-out.js +0 -0
  31. package/dist/source/core/utils/unhandle.d.ts +0 -0
  32. package/dist/source/core/utils/unhandle.js +0 -0
  33. package/dist/source/core/utils/url-to-options.d.ts +0 -0
  34. package/dist/source/core/utils/url-to-options.js +0 -0
  35. package/dist/source/core/utils/weakable-map.d.ts +0 -0
  36. package/dist/source/core/utils/weakable-map.js +0 -0
  37. package/dist/source/create.d.ts +0 -0
  38. package/dist/source/create.js +22 -14
  39. package/dist/source/index.d.ts +0 -0
  40. package/dist/source/index.js +3 -2
  41. package/dist/source/types.d.ts +240 -1
  42. package/dist/source/types.js +0 -0
  43. package/dist/source/utils/deep-freeze.d.ts +0 -0
  44. package/dist/source/utils/deep-freeze.js +0 -0
  45. package/dist/source/utils/deprecation-warning.d.ts +0 -0
  46. package/dist/source/utils/deprecation-warning.js +0 -0
  47. package/license +0 -0
  48. package/package.json +20 -16
  49. package/readme.md +180 -40
  50. package/dist/source/as-promise/calculate-retry-delay.js +0 -38
  51. package/dist/source/as-promise/core.d.ts +0 -13
  52. package/dist/source/as-promise/core.js +0 -127
@@ -25,7 +25,11 @@ const options_to_url_1 = require("./utils/options-to-url");
25
25
  const weakable_map_1 = require("./utils/weakable-map");
26
26
  const get_buffer_1 = require("./utils/get-buffer");
27
27
  const dns_ip_version_1 = require("./utils/dns-ip-version");
28
+ const is_response_ok_1 = require("./utils/is-response-ok");
28
29
  const deprecation_warning_1 = require("../utils/deprecation-warning");
30
+ const normalize_arguments_1 = require("../as-promise/normalize-arguments");
31
+ const calculate_retry_delay_1 = require("./calculate-retry-delay");
32
+ const globalDnsCache = new cacheable_lookup_1.default();
29
33
  const kRequest = Symbol('request');
30
34
  const kResponse = Symbol('response');
31
35
  const kResponseSize = Symbol('responseSize');
@@ -42,10 +46,19 @@ const kTriggerRead = Symbol('triggerRead');
42
46
  const kBody = Symbol('body');
43
47
  const kJobs = Symbol('jobs');
44
48
  const kOriginalResponse = Symbol('originalResponse');
49
+ const kRetryTimeout = Symbol('retryTimeout');
45
50
  exports.kIsNormalizedAlready = Symbol('isNormalizedAlready');
46
51
  const supportsBrotli = is_1.default.string(process.versions.brotli);
47
52
  exports.withoutBody = new Set(['GET', 'HEAD']);
48
- exports.knownHookEvents = ['init', 'beforeRequest', 'beforeRedirect', 'beforeError'];
53
+ exports.knownHookEvents = [
54
+ 'init',
55
+ 'beforeRequest',
56
+ 'beforeRedirect',
57
+ 'beforeError',
58
+ 'beforeRetry',
59
+ // Promise-Only
60
+ 'afterResponse'
61
+ ];
49
62
  function validateSearchParameters(searchParameters) {
50
63
  // eslint-disable-next-line guard-for-in
51
64
  for (const key in searchParameters) {
@@ -102,6 +115,10 @@ exports.setNonEnumerableProperties = (sources, to) => {
102
115
  }
103
116
  Object.defineProperties(to, properties);
104
117
  };
118
+ /**
119
+ An error to be thrown when a request fails.
120
+ Contains a `code` property with error class code, like `ECONNREFUSED`.
121
+ */
105
122
  class RequestError extends Error {
106
123
  constructor(message, error, self) {
107
124
  var _a;
@@ -148,6 +165,10 @@ class RequestError extends Error {
148
165
  }
149
166
  }
150
167
  exports.RequestError = RequestError;
168
+ /**
169
+ An error to be thrown when the server redirects you more than ten times.
170
+ Includes a `response` property.
171
+ */
151
172
  class MaxRedirectsError extends RequestError {
152
173
  constructor(request) {
153
174
  super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
@@ -155,6 +176,10 @@ class MaxRedirectsError extends RequestError {
155
176
  }
156
177
  }
157
178
  exports.MaxRedirectsError = MaxRedirectsError;
179
+ /**
180
+ An error to be thrown when the server response code is not 2xx nor 3xx if `options.followRedirect` is `true`, but always except for 304.
181
+ Includes a `response` property.
182
+ */
158
183
  class HTTPError extends RequestError {
159
184
  constructor(response) {
160
185
  super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request);
@@ -162,6 +187,10 @@ class HTTPError extends RequestError {
162
187
  }
163
188
  }
164
189
  exports.HTTPError = HTTPError;
190
+ /**
191
+ An error to be thrown when a cache method fails.
192
+ For example, if the database goes down or there's a filesystem error.
193
+ */
165
194
  class CacheError extends RequestError {
166
195
  constructor(error, request) {
167
196
  super(error.message, error, request);
@@ -169,6 +198,9 @@ class CacheError extends RequestError {
169
198
  }
170
199
  }
171
200
  exports.CacheError = CacheError;
201
+ /**
202
+ An error to be thrown when the request body is a stream and an error occurs while reading from that stream.
203
+ */
172
204
  class UploadError extends RequestError {
173
205
  constructor(error, request) {
174
206
  super(error.message, error, request);
@@ -176,6 +208,10 @@ class UploadError extends RequestError {
176
208
  }
177
209
  }
178
210
  exports.UploadError = UploadError;
211
+ /**
212
+ An error to be thrown when the request is aborted due to a timeout.
213
+ Includes an `event` and `timings` property.
214
+ */
179
215
  class TimeoutError extends RequestError {
180
216
  constructor(error, timings, request) {
181
217
  super(error.message, error, request);
@@ -185,6 +221,9 @@ class TimeoutError extends RequestError {
185
221
  }
186
222
  }
187
223
  exports.TimeoutError = TimeoutError;
224
+ /**
225
+ An error to be thrown when reading from response stream fails.
226
+ */
188
227
  class ReadError extends RequestError {
189
228
  constructor(error, request) {
190
229
  super(error.message, error, request);
@@ -192,6 +231,9 @@ class ReadError extends RequestError {
192
231
  }
193
232
  }
194
233
  exports.ReadError = ReadError;
234
+ /**
235
+ An error to be thrown when given an unsupported protocol.
236
+ */
195
237
  class UnsupportedProtocolError extends RequestError {
196
238
  constructor(options) {
197
239
  super(`Unsupported protocol "${options.url.protocol}"`, {}, options);
@@ -210,6 +252,9 @@ const proxiedRequestEvents = [
210
252
  class Request extends stream_1.Duplex {
211
253
  constructor(url, options = {}, defaults) {
212
254
  super({
255
+ // This must be false, to enable throwing after destroy
256
+ // It is used for retry logic in Promise API
257
+ autoDestroy: false,
213
258
  // It needs to be zero because we're just proxying the data to another stream
214
259
  highWaterMark: 0
215
260
  });
@@ -221,6 +266,7 @@ class Request extends stream_1.Duplex {
221
266
  this[kStopReading] = false;
222
267
  this[kTriggerRead] = false;
223
268
  this[kJobs] = [];
269
+ this.retryCount = 0;
224
270
  // TODO: Remove this when targeting Node.js >= 12
225
271
  this._progressCallbacks = [];
226
272
  const unlockWrite = () => this._unlockWrite();
@@ -278,6 +324,8 @@ class Request extends stream_1.Duplex {
278
324
  for (const job of this[kJobs]) {
279
325
  job();
280
326
  }
327
+ // Prevent memory leak
328
+ this[kJobs].length = 0;
281
329
  this.requestInitialized = true;
282
330
  }
283
331
  catch (error) {
@@ -293,7 +341,7 @@ class Request extends stream_1.Duplex {
293
341
  })(options);
294
342
  }
295
343
  static normalizeArguments(url, options, defaults) {
296
- var _a, _b, _c, _d;
344
+ var _a, _b, _c, _d, _e;
297
345
  const rawOptions = options;
298
346
  if (is_1.default.object(url) && !is_1.default.urlInstance(url)) {
299
347
  options = { ...defaults, ...url, ...options };
@@ -347,6 +395,7 @@ class Request extends stream_1.Duplex {
347
395
  is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificate);
348
396
  is_1.assert.any([is_1.default.string, is_1.default.undefined], options.https.passphrase);
349
397
  }
398
+ is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cacheOptions);
350
399
  // `options.method`
351
400
  if (is_1.default.string(options.method)) {
352
401
  options.method = options.method.toUpperCase();
@@ -404,15 +453,15 @@ class Request extends stream_1.Duplex {
404
453
  options.username = (_b = options.username) !== null && _b !== void 0 ? _b : '';
405
454
  options.password = (_c = options.password) !== null && _c !== void 0 ? _c : '';
406
455
  // `options.prefixUrl` & `options.url`
407
- if (options.prefixUrl) {
456
+ if (is_1.default.undefined(options.prefixUrl)) {
457
+ options.prefixUrl = (_d = defaults === null || defaults === void 0 ? void 0 : defaults.prefixUrl) !== null && _d !== void 0 ? _d : '';
458
+ }
459
+ else {
408
460
  options.prefixUrl = options.prefixUrl.toString();
409
461
  if (options.prefixUrl !== '' && !options.prefixUrl.endsWith('/')) {
410
462
  options.prefixUrl += '/';
411
463
  }
412
464
  }
413
- else {
414
- options.prefixUrl = '';
415
- }
416
465
  if (is_1.default.string(options.url)) {
417
466
  if (options.url.startsWith('/')) {
418
467
  throw new Error('`input` must not start with a slash when using `prefixUrl`');
@@ -478,9 +527,7 @@ class Request extends stream_1.Duplex {
478
527
  getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar));
479
528
  options.cookieJar = {
480
529
  setCookie,
481
- // TODO: Fix this when upgrading to TypeScript 4.
482
- // @ts-expect-error TypeScript thinks that promisifying callback(error, string) will result in Promise<void>
483
- getCookieString
530
+ getCookieString: getCookieString
484
531
  };
485
532
  }
486
533
  }
@@ -521,9 +568,11 @@ class Request extends stream_1.Duplex {
521
568
  }), cache));
522
569
  }
523
570
  }
571
+ // `options.cacheOptions`
572
+ options.cacheOptions = { ...options.cacheOptions };
524
573
  // `options.dnsCache`
525
574
  if (options.dnsCache === true) {
526
- options.dnsCache = new cacheable_lookup_1.default();
575
+ options.dnsCache = globalDnsCache;
527
576
  }
528
577
  else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) {
529
578
  throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${is_1.default(options.dnsCache)}`);
@@ -611,10 +660,10 @@ class Request extends stream_1.Duplex {
611
660
  }
612
661
  }
613
662
  }
614
- options.maxRedirects = (_d = options.maxRedirects) !== null && _d !== void 0 ? _d : 0;
663
+ options.maxRedirects = (_e = options.maxRedirects) !== null && _e !== void 0 ? _e : 0;
615
664
  // Set non-enumerable properties
616
665
  exports.setNonEnumerableProperties([defaults, rawOptions], options);
617
- return options;
666
+ return normalize_arguments_1.default(options, defaults);
618
667
  }
619
668
  _lockWrite() {
620
669
  const onLockedWrite = () => {
@@ -716,6 +765,7 @@ class Request extends stream_1.Duplex {
716
765
  typedResponse.request = this;
717
766
  typedResponse.isFromCache = response.fromCache || false;
718
767
  typedResponse.ip = this.ip;
768
+ typedResponse.retryCount = this.retryCount;
719
769
  this[kIsFromCache] = typedResponse.isFromCache;
720
770
  this[kResponseSize] = Number(response.headers['content-length']) || undefined;
721
771
  this[kResponse] = response;
@@ -753,7 +803,7 @@ class Request extends stream_1.Duplex {
753
803
  }
754
804
  if (options.followRedirect && response.headers.location && redirectCodes.has(statusCode)) {
755
805
  // We're being redirected, we don't care about the response.
756
- // It'd be besto to abort the request, but we can't because
806
+ // It'd be best to abort the request, but we can't because
757
807
  // we would have to sacrifice the TCP connection. We don't want that.
758
808
  response.resume();
759
809
  if (this[kRequest]) {
@@ -789,7 +839,7 @@ class Request extends stream_1.Duplex {
789
839
  const redirectString = redirectUrl.toString();
790
840
  decodeURI(redirectString);
791
841
  // Redirecting to a different site, clear sensitive data.
792
- if (redirectUrl.hostname !== url.hostname) {
842
+ if (redirectUrl.hostname !== url.hostname || redirectUrl.port !== url.port) {
793
843
  if ('host' in options.headers) {
794
844
  delete options.headers.host;
795
845
  }
@@ -800,9 +850,15 @@ class Request extends stream_1.Duplex {
800
850
  delete options.headers.authorization;
801
851
  }
802
852
  if (options.username || options.password) {
853
+ // TODO: Fix this ignore.
854
+ // @ts-expect-error
803
855
  delete options.username;
856
+ // @ts-expect-error
804
857
  delete options.password;
805
858
  }
859
+ if ('port' in options) {
860
+ delete options.port;
861
+ }
806
862
  }
807
863
  this.redirects.push(redirectString);
808
864
  options.url = redirectUrl;
@@ -819,16 +875,9 @@ class Request extends stream_1.Duplex {
819
875
  }
820
876
  return;
821
877
  }
822
- const limitStatusCode = options.followRedirect ? 299 : 399;
823
- const isOk = (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
824
- if (options.throwHttpErrors && !isOk) {
825
- // Normally we would have to use `void [await] this._beforeError(error)` everywhere,
826
- // but since there's `void (async () => { ... })()` inside of it, we don't have to.
878
+ if (options.isStream && options.throwHttpErrors && !is_response_ok_1.isResponseOk(typedResponse)) {
827
879
  this._beforeError(new HTTPError(typedResponse));
828
- // This is equivalent to this.destroyed
829
- if (this[kStopReading]) {
830
- return;
831
- }
880
+ return;
832
881
  }
833
882
  response.on('readable', () => {
834
883
  if (this[kTriggerRead]) {
@@ -865,6 +914,7 @@ class Request extends stream_1.Duplex {
865
914
  await this._onResponseBase(response);
866
915
  }
867
916
  catch (error) {
917
+ /* istanbul ignore next: better safe than sorry */
868
918
  this._beforeError(error);
869
919
  }
870
920
  }
@@ -902,9 +952,6 @@ class Request extends stream_1.Duplex {
902
952
  body.once('error', (error) => {
903
953
  this._beforeError(new UploadError(error, this));
904
954
  });
905
- body.once('end', () => {
906
- delete options.body;
907
- });
908
955
  }
909
956
  else {
910
957
  this._unlockWrite();
@@ -925,6 +972,8 @@ class Request extends stream_1.Duplex {
925
972
  // TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
926
973
  Object.assign(options, url_to_options_1.default(url));
927
974
  // `http-cache-semantics` checks this
975
+ // TODO: Fix this ignore.
976
+ // @ts-expect-error
928
977
  delete options.url;
929
978
  let request;
930
979
  // This is ugly
@@ -946,7 +995,7 @@ class Request extends stream_1.Duplex {
946
995
  });
947
996
  }
948
997
  async _makeRequest() {
949
- var _a;
998
+ var _a, _b, _c, _d, _e;
950
999
  const { options } = this;
951
1000
  const { headers } = options;
952
1001
  for (const key in headers) {
@@ -1012,14 +1061,20 @@ class Request extends stream_1.Duplex {
1012
1061
  // Prepare plain HTTP request options
1013
1062
  options[kRequest] = realFn;
1014
1063
  delete options.request;
1064
+ // TODO: Fix this ignore.
1065
+ // @ts-expect-error
1015
1066
  delete options.timeout;
1016
1067
  const requestOptions = options;
1068
+ requestOptions.shared = (_b = options.cacheOptions) === null || _b === void 0 ? void 0 : _b.shared;
1069
+ requestOptions.cacheHeuristic = (_c = options.cacheOptions) === null || _c === void 0 ? void 0 : _c.cacheHeuristic;
1070
+ requestOptions.immutableMinTimeToLive = (_d = options.cacheOptions) === null || _d === void 0 ? void 0 : _d.immutableMinTimeToLive;
1071
+ requestOptions.ignoreCargoCult = (_e = options.cacheOptions) === null || _e === void 0 ? void 0 : _e.ignoreCargoCult;
1017
1072
  // If `dnsLookupIpVersion` is not present do not override `family`
1018
1073
  if (options.dnsLookupIpVersion !== undefined) {
1019
1074
  try {
1020
1075
  requestOptions.family = dns_ip_version_1.dnsLookupIpVersionToFamily(options.dnsLookupIpVersion);
1021
1076
  }
1022
- catch (_b) {
1077
+ catch (_f) {
1023
1078
  throw new Error('Invalid `dnsLookupIpVersion` option value');
1024
1079
  }
1025
1080
  }
@@ -1053,6 +1108,28 @@ class Request extends stream_1.Duplex {
1053
1108
  options.request = request;
1054
1109
  options.timeout = timeout;
1055
1110
  options.agent = agent;
1111
+ // HTTPS options restore
1112
+ if (options.https) {
1113
+ if ('rejectUnauthorized' in options.https) {
1114
+ delete requestOptions.rejectUnauthorized;
1115
+ }
1116
+ if (options.https.checkServerIdentity) {
1117
+ // @ts-expect-error - This one will be removed when we remove the alias.
1118
+ delete requestOptions.checkServerIdentity;
1119
+ }
1120
+ if (options.https.certificateAuthority) {
1121
+ delete requestOptions.ca;
1122
+ }
1123
+ if (options.https.certificate) {
1124
+ delete requestOptions.cert;
1125
+ }
1126
+ if (options.https.key) {
1127
+ delete requestOptions.key;
1128
+ }
1129
+ if (options.https.passphrase) {
1130
+ delete requestOptions.passphrase;
1131
+ }
1132
+ }
1056
1133
  if (isClientRequest(requestOrResponse)) {
1057
1134
  this._onRequest(requestOrResponse);
1058
1135
  // Emit the response after the stream has been ended
@@ -1076,34 +1153,97 @@ class Request extends stream_1.Duplex {
1076
1153
  throw new RequestError(error.message, error, this);
1077
1154
  }
1078
1155
  }
1156
+ async _error(error) {
1157
+ try {
1158
+ for (const hook of this.options.hooks.beforeError) {
1159
+ // eslint-disable-next-line no-await-in-loop
1160
+ error = await hook(error);
1161
+ }
1162
+ }
1163
+ catch (error_) {
1164
+ error = new RequestError(error_.message, error_, this);
1165
+ }
1166
+ this.destroy(error);
1167
+ }
1079
1168
  _beforeError(error) {
1080
- if (this.destroyed) {
1169
+ if (this[kStopReading]) {
1081
1170
  return;
1082
1171
  }
1172
+ const { options } = this;
1173
+ const retryCount = this.retryCount + 1;
1083
1174
  this[kStopReading] = true;
1084
1175
  if (!(error instanceof RequestError)) {
1085
1176
  error = new RequestError(error.message, error, this);
1086
1177
  }
1178
+ const typedError = error;
1179
+ const { response } = typedError;
1087
1180
  void (async () => {
1088
- try {
1089
- const { response } = error;
1090
- if (response) {
1091
- response.setEncoding(this._readableState.encoding);
1181
+ if (response && !response.body) {
1182
+ response.setEncoding(this._readableState.encoding);
1183
+ try {
1092
1184
  response.rawBody = await get_buffer_1.default(response);
1093
1185
  response.body = response.rawBody.toString();
1094
1186
  }
1095
- }
1096
- catch (_a) { }
1097
- try {
1098
- for (const hook of this.options.hooks.beforeError) {
1099
- // eslint-disable-next-line no-await-in-loop
1100
- error = await hook(error);
1187
+ catch (_a) { }
1188
+ }
1189
+ if (this.listenerCount('retry') !== 0) {
1190
+ let backoff;
1191
+ try {
1192
+ let retryAfter;
1193
+ if (response && 'retry-after' in response.headers) {
1194
+ retryAfter = Number(response.headers['retry-after']);
1195
+ if (Number.isNaN(retryAfter)) {
1196
+ retryAfter = Date.parse(response.headers['retry-after']) - Date.now();
1197
+ if (retryAfter <= 0) {
1198
+ retryAfter = 1;
1199
+ }
1200
+ }
1201
+ else {
1202
+ retryAfter *= 1000;
1203
+ }
1204
+ }
1205
+ backoff = await options.retry.calculateDelay({
1206
+ attemptCount: retryCount,
1207
+ retryOptions: options.retry,
1208
+ error: typedError,
1209
+ retryAfter,
1210
+ computedValue: calculate_retry_delay_1.default({
1211
+ attemptCount: retryCount,
1212
+ retryOptions: options.retry,
1213
+ error: typedError,
1214
+ retryAfter,
1215
+ computedValue: 0
1216
+ })
1217
+ });
1218
+ }
1219
+ catch (error_) {
1220
+ void this._error(new RequestError(error_.message, error_, this));
1221
+ return;
1222
+ }
1223
+ if (backoff) {
1224
+ const retry = async () => {
1225
+ try {
1226
+ for (const hook of this.options.hooks.beforeRetry) {
1227
+ // eslint-disable-next-line no-await-in-loop
1228
+ await hook(this.options, typedError, retryCount);
1229
+ }
1230
+ }
1231
+ catch (error_) {
1232
+ void this._error(new RequestError(error_.message, error, this));
1233
+ return;
1234
+ }
1235
+ // Something forced us to abort the retry
1236
+ if (this.destroyed) {
1237
+ return;
1238
+ }
1239
+ this.destroy();
1240
+ this.emit('retry', retryCount, error);
1241
+ };
1242
+ this[kRetryTimeout] = setTimeout(retry, backoff);
1243
+ return;
1101
1244
  }
1102
1245
  }
1103
- catch (error_) {
1104
- error = new RequestError(error_.message, error_, this);
1105
- }
1106
- this.destroy(error);
1246
+ void this._error(typedError);
1107
1247
  })();
1108
1248
  }
1109
1249
  _read() {
@@ -1140,6 +1280,10 @@ class Request extends stream_1.Duplex {
1140
1280
  }
1141
1281
  }
1142
1282
  _writeRequest(chunk, encoding, callback) {
1283
+ if (this[kRequest].destroyed) {
1284
+ // Probably the `ClientRequest` instance will throw
1285
+ return;
1286
+ }
1143
1287
  this._progressCallbacks.push(() => {
1144
1288
  this[kUploadedSize] += Buffer.byteLength(chunk, encoding);
1145
1289
  const progress = this.uploadProgress;
@@ -1190,6 +1334,8 @@ class Request extends stream_1.Duplex {
1190
1334
  _destroy(error, callback) {
1191
1335
  var _a;
1192
1336
  this[kStopReading] = true;
1337
+ // Prevent further retries
1338
+ clearTimeout(this[kRetryTimeout]);
1193
1339
  if (kRequest in this) {
1194
1340
  this[kCancelTimeouts]();
1195
1341
  // TODO: Remove the next `if` when these get fixed:
@@ -1203,10 +1349,19 @@ class Request extends stream_1.Duplex {
1203
1349
  }
1204
1350
  callback(error);
1205
1351
  }
1352
+ get _isAboutToError() {
1353
+ return this[kStopReading];
1354
+ }
1355
+ /**
1356
+ The remote IP address.
1357
+ */
1206
1358
  get ip() {
1207
1359
  var _a;
1208
1360
  return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket.remoteAddress;
1209
1361
  }
1362
+ /**
1363
+ Indicates whether the request has been aborted or not.
1364
+ */
1210
1365
  get aborted() {
1211
1366
  var _a, _b, _c;
1212
1367
  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);
@@ -1215,6 +1370,9 @@ class Request extends stream_1.Duplex {
1215
1370
  var _a;
1216
1371
  return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket;
1217
1372
  }
1373
+ /**
1374
+ Progress event for downloading (receiving a response).
1375
+ */
1218
1376
  get downloadProgress() {
1219
1377
  let percent;
1220
1378
  if (this[kResponseSize]) {
@@ -1232,6 +1390,9 @@ class Request extends stream_1.Duplex {
1232
1390
  total: this[kResponseSize]
1233
1391
  };
1234
1392
  }
1393
+ /**
1394
+ Progress event for uploading (sending a request).
1395
+ */
1235
1396
  get uploadProgress() {
1236
1397
  let percent;
1237
1398
  if (this[kBodySize]) {
@@ -1249,16 +1410,43 @@ class Request extends stream_1.Duplex {
1249
1410
  total: this[kBodySize]
1250
1411
  };
1251
1412
  }
1413
+ /**
1414
+ The object contains the following properties:
1415
+
1416
+ - `start` - Time when the request started.
1417
+ - `socket` - Time when a socket was assigned to the request.
1418
+ - `lookup` - Time when the DNS lookup finished.
1419
+ - `connect` - Time when the socket successfully connected.
1420
+ - `secureConnect` - Time when the socket securely connected.
1421
+ - `upload` - Time when the request finished uploading.
1422
+ - `response` - Time when the request fired `response` event.
1423
+ - `end` - Time when the response fired `end` event.
1424
+ - `error` - Time when the request fired `error` event.
1425
+ - `abort` - Time when the request fired `abort` event.
1426
+ - `phases`
1427
+ - `wait` - `timings.socket - timings.start`
1428
+ - `dns` - `timings.lookup - timings.socket`
1429
+ - `tcp` - `timings.connect - timings.lookup`
1430
+ - `tls` - `timings.secureConnect - timings.connect`
1431
+ - `request` - `timings.upload - (timings.secureConnect || timings.connect)`
1432
+ - `firstByte` - `timings.response - timings.upload`
1433
+ - `download` - `timings.end - timings.response`
1434
+ - `total` - `(timings.end || timings.error || timings.abort) - timings.start`
1435
+
1436
+ If something has not been measured yet, it will be `undefined`.
1437
+
1438
+ __Note__: The time is a `number` representing the milliseconds elapsed since the UNIX epoch.
1439
+ */
1252
1440
  get timings() {
1253
1441
  var _a;
1254
1442
  return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.timings;
1255
1443
  }
1444
+ /**
1445
+ Whether the response was retrieved from the cache.
1446
+ */
1256
1447
  get isFromCache() {
1257
1448
  return this[kIsFromCache];
1258
1449
  }
1259
- get _response() {
1260
- return this[kResponse];
1261
- }
1262
1450
  pipe(destination, options) {
1263
1451
  if (this[kStartedReading]) {
1264
1452
  throw new Error('Failed to pipe. The response has been emitted already.');
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,2 @@
1
+ import { Response } from '..';
2
+ export declare const isResponseOk: (response: Response) => boolean;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isResponseOk = void 0;
4
+ exports.isResponseOk = (response) => {
5
+ const { statusCode } = response;
6
+ const limitStatusCode = response.request.options.followRedirect ? 299 : 399;
7
+ return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
8
+ };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes