got 11.0.0-beta.1 → 11.0.3

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.
@@ -1,14 +1,13 @@
1
1
  /// <reference types="node" />
2
2
  import { URL } from 'url';
3
- import { Options, NormalizedOptions, Defaults, ResponseType } from './types';
4
- import Request, { RequestError } from '../core';
3
+ import { Options, NormalizedOptions, Defaults, ResponseType, Response } from './types';
4
+ import Request from '../core';
5
5
  export declare const knownBodyTypes: string[];
6
- export declare const parseBody: (body: Buffer, responseType: ResponseType, encoding?: string | undefined) => unknown;
6
+ export declare const parseBody: (response: Response<unknown>, responseType: ResponseType, encoding?: string | undefined) => unknown;
7
7
  export default class PromisableRequest extends Request {
8
8
  ['constructor']: typeof PromisableRequest;
9
9
  options: NormalizedOptions;
10
- _throwHttpErrors: boolean;
11
10
  static normalizeArguments(url?: string | URL, nonNormalizedOptions?: Options, defaults?: Defaults): NormalizedOptions;
12
11
  static mergeOptions(...sources: Options[]): NormalizedOptions;
13
- _beforeError(error: RequestError): Promise<void>;
12
+ _beforeError(error: Error): Promise<void>;
14
13
  }
@@ -1,24 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const is_1 = require("@sindresorhus/is");
4
+ const types_1 = require("./types");
4
5
  const core_1 = require("../core");
5
6
  if (!core_1.knownHookEvents.includes('beforeRetry')) {
6
7
  core_1.knownHookEvents.push('beforeRetry', 'afterResponse');
7
8
  }
8
9
  exports.knownBodyTypes = ['json', 'buffer', 'text'];
9
10
  // @ts-ignore The error is: Not all code paths return a value.
10
- exports.parseBody = (body, responseType, encoding) => {
11
- if (responseType === 'text') {
12
- return body.toString(encoding);
13
- }
14
- if (responseType === 'json') {
15
- return body.length === 0 ? '' : JSON.parse(body.toString());
16
- }
17
- if (responseType === 'buffer') {
18
- return Buffer.from(body);
11
+ exports.parseBody = (response, responseType, encoding) => {
12
+ const { rawBody } = response;
13
+ try {
14
+ if (responseType === 'text') {
15
+ return rawBody.toString(encoding);
16
+ }
17
+ if (responseType === 'json') {
18
+ return rawBody.length === 0 ? '' : JSON.parse(rawBody.toString());
19
+ }
20
+ if (responseType === 'buffer') {
21
+ return Buffer.from(rawBody);
22
+ }
23
+ throw new types_1.ParseError({
24
+ message: `Unknown body type '${responseType}'`,
25
+ name: 'Error'
26
+ }, response);
19
27
  }
20
- if (!exports.knownBodyTypes.includes(responseType)) {
21
- throw new TypeError(`Unknown body type '${responseType}'`);
28
+ catch (error) {
29
+ throw new types_1.ParseError(error, response);
22
30
  }
23
31
  };
24
32
  class PromisableRequest extends core_1.default {
@@ -83,6 +91,10 @@ class PromisableRequest extends core_1.default {
83
91
  throw new Error('`options.pagination.paginate` must be implemented');
84
92
  }
85
93
  }
94
+ // JSON mode
95
+ if (options.responseType === 'json' && options.headers.accept === undefined) {
96
+ options.headers.accept = 'application/json';
97
+ }
86
98
  return options;
87
99
  }
88
100
  static mergeOptions(...sources) {
@@ -93,23 +105,12 @@ class PromisableRequest extends core_1.default {
93
105
  return mergedOptions;
94
106
  }
95
107
  async _beforeError(error) {
96
- const isHTTPError = error instanceof core_1.HTTPError;
97
- try {
98
- for (const hook of this.options.hooks.beforeError) {
99
- // eslint-disable-next-line no-await-in-loop
100
- error = await hook(error);
101
- }
102
- }
103
- catch (error_) {
104
- this.destroy(error_);
105
- return;
106
- }
107
- if (this._throwHttpErrors && !isHTTPError) {
108
- this.destroy(error);
109
- }
110
- else {
111
- this.emit('error', error);
108
+ if (!(error instanceof core_1.RequestError)) {
109
+ error = new core_1.RequestError(error.message, error, this);
112
110
  }
111
+ // Let the promise decide whether to abort or not
112
+ // It is also responsible for the `beforeError` hook
113
+ this.emit('error', error);
113
114
  }
114
115
  }
115
116
  exports.default = PromisableRequest;
@@ -20,22 +20,37 @@ const proxiedRequestEvents = [
20
20
  ];
21
21
  function asPromise(options) {
22
22
  let retryCount = 0;
23
- let body;
23
+ let globalRequest;
24
+ let globalResponse;
24
25
  const emitter = new events_1.EventEmitter();
25
- const promise = new PCancelable((resolve, reject, onCancel) => {
26
+ const promise = new PCancelable((resolve, _reject, onCancel) => {
26
27
  const makeRequest = () => {
27
- if (options.responseType === 'json' && options.headers.accept === undefined) {
28
- options.headers.accept = 'application/json';
29
- }
30
28
  // Support retries
29
+ // `options.throwHttpErrors` needs to be always true,
30
+ // so the HTTP errors are caught and the request is retried.
31
+ // The error is **eventually** thrown if the user value is true.
31
32
  const { throwHttpErrors } = options;
32
33
  if (!throwHttpErrors) {
33
34
  options.throwHttpErrors = true;
34
35
  }
36
+ // Note from @szmarczak: I think we should use `request.options` instead of the local options
35
37
  const request = new core_1.default(options.url, options);
36
- request._throwHttpErrors = throwHttpErrors;
37
38
  request._noPipe = true;
38
39
  onCancel(() => request.destroy());
40
+ const reject = async (error) => {
41
+ try {
42
+ for (const hook of options.hooks.beforeError) {
43
+ // eslint-disable-next-line no-await-in-loop
44
+ error = await hook(error);
45
+ }
46
+ }
47
+ catch (error_) {
48
+ _reject(new types_1.RequestError(error_.message, error_, request));
49
+ return;
50
+ }
51
+ _reject(error);
52
+ };
53
+ globalRequest = request;
39
54
  request.once('response', async (response) => {
40
55
  response.retryCount = retryCount;
41
56
  if (response.request.aborted) {
@@ -48,23 +63,26 @@ function asPromise(options) {
48
63
  return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
49
64
  };
50
65
  // Download body
66
+ let rawBody;
51
67
  try {
52
- body = await getStream.buffer(request);
68
+ rawBody = await getStream.buffer(request);
69
+ response.rawBody = rawBody;
53
70
  }
54
- catch (error) {
55
- request._beforeError(new types_1.ReadError(error, options, response));
71
+ catch (_) {
72
+ // The same error is caught below.
73
+ // See request.once('error')
56
74
  return;
57
75
  }
58
76
  // Parse body
59
77
  try {
60
- response.body = core_1.parseBody(body, options.responseType, options.encoding);
78
+ response.body = core_1.parseBody(response, options.responseType, options.encoding);
61
79
  }
62
80
  catch (error) {
63
81
  // Fallback to `utf8`
64
- response.body = body.toString('utf8');
82
+ response.body = rawBody.toString();
65
83
  if (isOk()) {
66
- const parseError = new types_1.ParseError(error, response, options);
67
- request._beforeError(parseError);
84
+ // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995
85
+ reject(error);
68
86
  return;
69
87
  }
70
88
  }
@@ -73,7 +91,6 @@ function asPromise(options) {
73
91
  // @ts-ignore TS doesn't notice that CancelableRequest is a Promise
74
92
  // eslint-disable-next-line no-await-in-loop
75
93
  response = await hook(response, async (updatedOptions) => {
76
- request.destroy();
77
94
  const typedOptions = core_1.default.normalizeArguments(undefined, {
78
95
  ...updatedOptions,
79
96
  retry: {
@@ -99,13 +116,15 @@ function asPromise(options) {
99
116
  }
100
117
  }
101
118
  catch (error) {
102
- request._beforeError(error);
119
+ // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995
120
+ reject(new types_1.RequestError(error.message, error, request));
103
121
  return;
104
122
  }
105
123
  if (throwHttpErrors && !isOk()) {
106
- reject(new types_1.HTTPError(response, options));
124
+ reject(new types_1.HTTPError(response));
107
125
  return;
108
126
  }
127
+ globalResponse = response;
109
128
  resolve(options.resolveBodyOnly ? response.body : response);
110
129
  });
111
130
  request.once('error', (error) => {
@@ -134,7 +153,7 @@ function asPromise(options) {
134
153
  catch (error_) {
135
154
  // Don't emit the `response` event
136
155
  request.destroy();
137
- reject(new types_1.RequestError(error_.message, error, request.options));
156
+ reject(new types_1.RequestError(error_.message, error, request));
138
157
  return;
139
158
  }
140
159
  if (backoff) {
@@ -151,7 +170,7 @@ function asPromise(options) {
151
170
  catch (error_) {
152
171
  // Don't emit the `response` event
153
172
  request.destroy();
154
- reject(new types_1.RequestError(error_.message, error, request.options));
173
+ reject(new types_1.RequestError(error_.message, error, request));
155
174
  return;
156
175
  }
157
176
  makeRequest();
@@ -179,14 +198,15 @@ function asPromise(options) {
179
198
  };
180
199
  const shortcut = (responseType) => {
181
200
  const newPromise = (async () => {
201
+ // Wait until downloading has ended
182
202
  await promise;
183
- return core_1.parseBody(body, responseType);
203
+ return core_1.parseBody(globalResponse, responseType, options.encoding);
184
204
  })();
185
205
  Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise));
186
206
  return newPromise;
187
207
  };
188
208
  promise.json = () => {
189
- if (body === undefined && options.headers.accept === undefined) {
209
+ if (!globalRequest.writableFinished && options.headers.accept === undefined) {
190
210
  options.headers.accept = 'application/json';
191
211
  }
192
212
  return shortcut('json');
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import PCancelable = require('p-cancelable');
3
3
  import { CancelError } from 'p-cancelable';
4
- import { Options as RequestOptions, NormalizedOptions as RequestNormalizedOptions, Defaults as RequestDefaults, Hooks as RequestHooks, Response as RequestResponse, RequestError, MaxRedirectsError, CacheError, UploadError, TimeoutError, HTTPError, ReadError, UnsupportedProtocolError, HookEvent as RequestHookEvent, InitHook, BeforeRequestHook, BeforeRedirectHook, BeforeErrorHook, Progress, Headers, RequestFunction, Method, RequestEvents } from '../core';
4
+ import { Options as RequestOptions, NormalizedOptions as RequestNormalizedOptions, Defaults as RequestDefaults, Hooks as RequestHooks, Response as RequestResponse, RequestError, MaxRedirectsError, CacheError, UploadError, TimeoutError, HTTPError, ReadError, UnsupportedProtocolError, HookEvent as RequestHookEvent, InitHook, BeforeRequestHook, BeforeRedirectHook, BeforeErrorHook, Progress, Headers, RequestFunction, Agents, Method, PromiseCookieJar, RequestEvents } from '../core';
5
5
  import PromisableRequest from './core';
6
6
  export declare type ResponseType = 'json' | 'buffer' | 'text';
7
7
  export interface Response<T = unknown> extends RequestResponse<T> {
@@ -35,6 +35,7 @@ export interface PaginationOptions<T> {
35
35
  paginate?: (response: Response, allItems: T[], currentItems: T[]) => Options | false;
36
36
  shouldContinue?: (item: T, allItems: T[], currentItems: T[]) => boolean;
37
37
  countLimit?: number;
38
+ requestLimit?: number;
38
39
  };
39
40
  }
40
41
  export interface Options extends RequestOptions, PaginationOptions<unknown> {
@@ -64,7 +65,7 @@ export interface Defaults extends RequestDefaults {
64
65
  }
65
66
  export declare class ParseError extends RequestError {
66
67
  readonly response: Response;
67
- constructor(error: Error, response: Response, options: NormalizedOptions);
68
+ constructor(error: Error, response: Response);
68
69
  }
69
70
  export interface CancelableRequest<T extends Response | Response['body'] = Response['body']> extends PCancelable<T>, RequestEvents<CancelableRequest<T>> {
70
71
  json<ReturnType>(): CancelableRequest<ReturnType>;
@@ -74,4 +75,4 @@ export interface CancelableRequest<T extends Response | Response['body'] = Respo
74
75
  export declare type HookEvent = RequestHookEvent | 'beforeRetry' | 'afterResponse';
75
76
  export { RequestError, MaxRedirectsError, CacheError, UploadError, TimeoutError, HTTPError, ReadError, UnsupportedProtocolError, CancelError };
76
77
  export { InitHook, BeforeRequestHook, BeforeRedirectHook, BeforeErrorHook };
77
- export { Progress, Headers, RequestFunction };
78
+ export { Progress, Headers, RequestFunction, Agents, Method, PromiseCookieJar };
@@ -14,8 +14,9 @@ exports.HTTPError = core_1.HTTPError;
14
14
  exports.ReadError = core_1.ReadError;
15
15
  exports.UnsupportedProtocolError = core_1.UnsupportedProtocolError;
16
16
  class ParseError extends core_1.RequestError {
17
- constructor(error, response, options) {
18
- super(`${error.message} in "${options.url.toString()}"`, error, options);
17
+ constructor(error, response) {
18
+ const { options } = response.request;
19
+ super(`${error.message} in "${options.url.toString()}"`, error, response.request);
19
20
  this.name = 'ParseError';
20
21
  Object.defineProperty(this, 'response', {
21
22
  enumerable: false,
@@ -25,6 +25,10 @@ declare const kUnproxyEvents: unique symbol;
25
25
  declare const kIsFromCache: unique symbol;
26
26
  declare const kCancelTimeouts: unique symbol;
27
27
  declare const kStartedReading: unique symbol;
28
+ declare const kStopReading: unique symbol;
29
+ declare const kTriggerRead: unique symbol;
30
+ declare const kBody: unique symbol;
31
+ declare const kJobs: unique symbol;
28
32
  export declare const kIsNormalizedAlready: unique symbol;
29
33
  export interface Agents {
30
34
  http?: http.Agent;
@@ -120,7 +124,6 @@ export interface NormalizedOptions extends Options {
120
124
  cache?: string | CacheableRequest.StorageAdapter;
121
125
  throwHttpErrors: boolean;
122
126
  dnsCache?: CacheableLookup;
123
- cacheableRequest?: (options: string | URL | http.RequestOptions, callback?: (response: http.ServerResponse | ResponseLike) => void) => CacheableRequest.Emitter;
124
127
  http2: boolean;
125
128
  allowGetBody: boolean;
126
129
  rejectUnauthorized: boolean;
@@ -174,6 +177,7 @@ export interface PlainResponse extends IncomingMessageWithTimings {
174
177
  }
175
178
  export interface Response<T = unknown> extends PlainResponse {
176
179
  body: T;
180
+ rawBody: Buffer;
177
181
  retryCount: number;
178
182
  }
179
183
  export interface RequestEvents<T> {
@@ -191,29 +195,39 @@ export declare class RequestError extends Error {
191
195
  readonly timings?: Timings;
192
196
  constructor(message: string, error: Partial<Error & {
193
197
  code?: string;
194
- }>, options: NormalizedOptions, requestOrResponse?: Request | Response);
198
+ }>, self: Request | NormalizedOptions);
195
199
  }
196
200
  export declare class MaxRedirectsError extends RequestError {
197
201
  readonly response: Response;
198
- constructor(response: Response, maxRedirects: number, options: NormalizedOptions);
202
+ readonly request: Request;
203
+ readonly timings: Timings;
204
+ constructor(request: Request);
199
205
  }
200
206
  export declare class HTTPError extends RequestError {
201
207
  readonly response: Response;
202
- constructor(response: Response, options: NormalizedOptions);
208
+ readonly request: Request;
209
+ readonly timings: Timings;
210
+ constructor(response: Response);
203
211
  }
204
212
  export declare class CacheError extends RequestError {
205
- constructor(error: Error, options: NormalizedOptions);
213
+ readonly request: Request;
214
+ constructor(error: Error, request: Request);
206
215
  }
207
216
  export declare class UploadError extends RequestError {
208
- constructor(error: Error, options: NormalizedOptions, request: Request);
217
+ readonly request: Request;
218
+ constructor(error: Error, request: Request);
209
219
  }
210
220
  export declare class TimeoutError extends RequestError {
221
+ readonly request: Request;
211
222
  readonly timings: Timings;
212
223
  readonly event: string;
213
- constructor(error: TimedOutTimeoutError, timings: Timings, options: NormalizedOptions);
224
+ constructor(error: TimedOutTimeoutError, timings: Timings, request: Request);
214
225
  }
215
226
  export declare class ReadError extends RequestError {
216
- constructor(error: Error, options: NormalizedOptions, response: Response);
227
+ readonly request: Request;
228
+ readonly response: Response;
229
+ readonly timings: Timings;
230
+ constructor(error: Error, request: Request);
217
231
  }
218
232
  export declare class UnsupportedProtocolError extends RequestError {
219
233
  constructor(options: NormalizedOptions);
@@ -224,6 +238,10 @@ export default class Request extends Duplex implements RequestEvents<Request> {
224
238
  _cannotHaveBody: boolean;
225
239
  [kDownloadedSize]: number;
226
240
  [kUploadedSize]: number;
241
+ [kStopReading]: boolean;
242
+ [kTriggerRead]: boolean;
243
+ [kBody]: Options['body'];
244
+ [kJobs]: Array<() => void>;
227
245
  [kBodySize]?: number;
228
246
  [kServerResponsesPiped]: Set<ServerResponse>;
229
247
  [kIsFromCache]?: boolean;
@@ -236,9 +254,8 @@ export default class Request extends Duplex implements RequestEvents<Request> {
236
254
  _progressCallbacks: Array<() => void>;
237
255
  options: NormalizedOptions;
238
256
  requestUrl: string;
239
- finalized: boolean;
257
+ requestInitialized: boolean;
240
258
  redirects: string[];
241
- errored: boolean;
242
259
  constructor(url: string | URL, options?: Options, defaults?: Defaults);
243
260
  static normalizeArguments(url?: string | URL, options?: Options, defaults?: Defaults): NormalizedOptions;
244
261
  _lockWrite(): void;
@@ -246,6 +263,7 @@ export default class Request extends Duplex implements RequestEvents<Request> {
246
263
  _finalizeBody(): Promise<void>;
247
264
  _onResponse(response: IncomingMessage): Promise<void>;
248
265
  _onRequest(request: ClientRequest): void;
266
+ _createCacheableRequest(url: URL, options: RequestOptions): Promise<ClientRequest | ResponseLike>;
249
267
  _makeRequest(): Promise<void>;
250
268
  _beforeError(error: Error): Promise<void>;
251
269
  _read(): void;
@@ -255,6 +273,7 @@ export default class Request extends Duplex implements RequestEvents<Request> {
255
273
  _destroy(error: Error | null, callback: (error: Error | null) => void): void;
256
274
  get ip(): string | undefined;
257
275
  get aborted(): boolean;
276
+ get socket(): Socket | undefined;
258
277
  get downloadProgress(): Progress;
259
278
  get uploadProgress(): Progress;
260
279
  get timings(): Timings | undefined;