got 11.0.0-beta.1 → 11.0.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/dist/source/as-promise/core.d.ts +4 -5
- package/dist/source/as-promise/core.js +28 -19
- package/dist/source/as-promise/index.js +20 -16
- package/dist/source/as-promise/types.d.ts +1 -1
- package/dist/source/as-promise/types.js +3 -2
- package/dist/source/core/index.d.ts +14 -9
- package/dist/source/core/index.js +113 -94
- package/dist/source/core/utils/weakable-map.d.ts +8 -0
- package/dist/source/core/utils/weakable-map.js +29 -0
- package/package.json +3 -3
- package/readme.md +12 -2
|
@@ -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
|
|
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: (
|
|
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:
|
|
12
|
+
_beforeError(error: Error): Promise<void>;
|
|
14
13
|
}
|
|
@@ -1,24 +1,31 @@
|
|
|
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 = (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
+
if (!exports.knownBodyTypes.includes(responseType)) {
|
|
24
|
+
throw new TypeError(`Unknown body type '${responseType}'`);
|
|
25
|
+
}
|
|
19
26
|
}
|
|
20
|
-
|
|
21
|
-
throw new
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new types_1.ParseError(error, response);
|
|
22
29
|
}
|
|
23
30
|
};
|
|
24
31
|
class PromisableRequest extends core_1.default {
|
|
@@ -83,6 +90,10 @@ class PromisableRequest extends core_1.default {
|
|
|
83
90
|
throw new Error('`options.pagination.paginate` must be implemented');
|
|
84
91
|
}
|
|
85
92
|
}
|
|
93
|
+
// JSON mode
|
|
94
|
+
if (options.responseType === 'json' && options.headers.accept === undefined) {
|
|
95
|
+
options.headers.accept = 'application/json';
|
|
96
|
+
}
|
|
86
97
|
return options;
|
|
87
98
|
}
|
|
88
99
|
static mergeOptions(...sources) {
|
|
@@ -93,7 +104,9 @@ class PromisableRequest extends core_1.default {
|
|
|
93
104
|
return mergedOptions;
|
|
94
105
|
}
|
|
95
106
|
async _beforeError(error) {
|
|
96
|
-
|
|
107
|
+
if (!(error instanceof core_1.RequestError)) {
|
|
108
|
+
error = new core_1.RequestError(error.message, error, this);
|
|
109
|
+
}
|
|
97
110
|
try {
|
|
98
111
|
for (const hook of this.options.hooks.beforeError) {
|
|
99
112
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -101,15 +114,11 @@ class PromisableRequest extends core_1.default {
|
|
|
101
114
|
}
|
|
102
115
|
}
|
|
103
116
|
catch (error_) {
|
|
104
|
-
this.destroy(error_);
|
|
117
|
+
this.destroy(new core_1.RequestError(error_.message, error_, this));
|
|
105
118
|
return;
|
|
106
119
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
this.emit('error', error);
|
|
112
|
-
}
|
|
120
|
+
// Let the promise decide whether to abort or not
|
|
121
|
+
this.emit('error', error);
|
|
113
122
|
}
|
|
114
123
|
}
|
|
115
124
|
exports.default = PromisableRequest;
|
|
@@ -20,22 +20,23 @@ const proxiedRequestEvents = [
|
|
|
20
20
|
];
|
|
21
21
|
function asPromise(options) {
|
|
22
22
|
let retryCount = 0;
|
|
23
|
-
let
|
|
23
|
+
let globalRequest;
|
|
24
|
+
let globalResponse;
|
|
24
25
|
const emitter = new events_1.EventEmitter();
|
|
25
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
|
}
|
|
35
36
|
const request = new core_1.default(options.url, options);
|
|
36
|
-
request._throwHttpErrors = throwHttpErrors;
|
|
37
37
|
request._noPipe = true;
|
|
38
38
|
onCancel(() => request.destroy());
|
|
39
|
+
globalRequest = request;
|
|
39
40
|
request.once('response', async (response) => {
|
|
40
41
|
response.retryCount = retryCount;
|
|
41
42
|
if (response.request.aborted) {
|
|
@@ -48,23 +49,24 @@ function asPromise(options) {
|
|
|
48
49
|
return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
|
|
49
50
|
};
|
|
50
51
|
// Download body
|
|
52
|
+
let rawBody;
|
|
51
53
|
try {
|
|
52
|
-
|
|
54
|
+
rawBody = await getStream.buffer(request);
|
|
55
|
+
response.rawBody = rawBody;
|
|
53
56
|
}
|
|
54
57
|
catch (error) {
|
|
55
|
-
request._beforeError(new types_1.ReadError(error,
|
|
58
|
+
request._beforeError(new types_1.ReadError(error, request));
|
|
56
59
|
return;
|
|
57
60
|
}
|
|
58
61
|
// Parse body
|
|
59
62
|
try {
|
|
60
|
-
response.body = core_1.parseBody(
|
|
63
|
+
response.body = core_1.parseBody(response, options.responseType, options.encoding);
|
|
61
64
|
}
|
|
62
65
|
catch (error) {
|
|
63
66
|
// Fallback to `utf8`
|
|
64
|
-
response.body =
|
|
67
|
+
response.body = rawBody.toString();
|
|
65
68
|
if (isOk()) {
|
|
66
|
-
|
|
67
|
-
request._beforeError(parseError);
|
|
69
|
+
request._beforeError(error);
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -103,9 +105,10 @@ function asPromise(options) {
|
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
if (throwHttpErrors && !isOk()) {
|
|
106
|
-
reject(new types_1.HTTPError(response
|
|
108
|
+
reject(new types_1.HTTPError(response));
|
|
107
109
|
return;
|
|
108
110
|
}
|
|
111
|
+
globalResponse = response;
|
|
109
112
|
resolve(options.resolveBodyOnly ? response.body : response);
|
|
110
113
|
});
|
|
111
114
|
request.once('error', (error) => {
|
|
@@ -134,7 +137,7 @@ function asPromise(options) {
|
|
|
134
137
|
catch (error_) {
|
|
135
138
|
// Don't emit the `response` event
|
|
136
139
|
request.destroy();
|
|
137
|
-
reject(new types_1.RequestError(error_.message, error, request
|
|
140
|
+
reject(new types_1.RequestError(error_.message, error, request));
|
|
138
141
|
return;
|
|
139
142
|
}
|
|
140
143
|
if (backoff) {
|
|
@@ -151,7 +154,7 @@ function asPromise(options) {
|
|
|
151
154
|
catch (error_) {
|
|
152
155
|
// Don't emit the `response` event
|
|
153
156
|
request.destroy();
|
|
154
|
-
reject(new types_1.RequestError(error_.message, error, request
|
|
157
|
+
reject(new types_1.RequestError(error_.message, error, request));
|
|
155
158
|
return;
|
|
156
159
|
}
|
|
157
160
|
makeRequest();
|
|
@@ -179,14 +182,15 @@ function asPromise(options) {
|
|
|
179
182
|
};
|
|
180
183
|
const shortcut = (responseType) => {
|
|
181
184
|
const newPromise = (async () => {
|
|
185
|
+
// Wait until downloading has ended
|
|
182
186
|
await promise;
|
|
183
|
-
return core_1.parseBody(
|
|
187
|
+
return core_1.parseBody(globalResponse, responseType, options.encoding);
|
|
184
188
|
})();
|
|
185
189
|
Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise));
|
|
186
190
|
return newPromise;
|
|
187
191
|
};
|
|
188
192
|
promise.json = () => {
|
|
189
|
-
if (
|
|
193
|
+
if (!globalRequest.writableFinished && options.headers.accept === undefined) {
|
|
190
194
|
options.headers.accept = 'application/json';
|
|
191
195
|
}
|
|
192
196
|
return shortcut('json');
|
|
@@ -64,7 +64,7 @@ export interface Defaults extends RequestDefaults {
|
|
|
64
64
|
}
|
|
65
65
|
export declare class ParseError extends RequestError {
|
|
66
66
|
readonly response: Response;
|
|
67
|
-
constructor(error: Error, response: Response
|
|
67
|
+
constructor(error: Error, response: Response);
|
|
68
68
|
}
|
|
69
69
|
export interface CancelableRequest<T extends Response | Response['body'] = Response['body']> extends PCancelable<T>, RequestEvents<CancelableRequest<T>> {
|
|
70
70
|
json<ReturnType>(): CancelableRequest<ReturnType>;
|
|
@@ -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
|
|
18
|
-
|
|
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,8 @@ 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;
|
|
28
30
|
export declare const kIsNormalizedAlready: unique symbol;
|
|
29
31
|
export interface Agents {
|
|
30
32
|
http?: http.Agent;
|
|
@@ -120,7 +122,6 @@ export interface NormalizedOptions extends Options {
|
|
|
120
122
|
cache?: string | CacheableRequest.StorageAdapter;
|
|
121
123
|
throwHttpErrors: boolean;
|
|
122
124
|
dnsCache?: CacheableLookup;
|
|
123
|
-
cacheableRequest?: (options: string | URL | http.RequestOptions, callback?: (response: http.ServerResponse | ResponseLike) => void) => CacheableRequest.Emitter;
|
|
124
125
|
http2: boolean;
|
|
125
126
|
allowGetBody: boolean;
|
|
126
127
|
rejectUnauthorized: boolean;
|
|
@@ -174,6 +175,7 @@ export interface PlainResponse extends IncomingMessageWithTimings {
|
|
|
174
175
|
}
|
|
175
176
|
export interface Response<T = unknown> extends PlainResponse {
|
|
176
177
|
body: T;
|
|
178
|
+
rawBody: Buffer;
|
|
177
179
|
retryCount: number;
|
|
178
180
|
}
|
|
179
181
|
export interface RequestEvents<T> {
|
|
@@ -191,29 +193,29 @@ export declare class RequestError extends Error {
|
|
|
191
193
|
readonly timings?: Timings;
|
|
192
194
|
constructor(message: string, error: Partial<Error & {
|
|
193
195
|
code?: string;
|
|
194
|
-
}>,
|
|
196
|
+
}>, self: Request | NormalizedOptions);
|
|
195
197
|
}
|
|
196
198
|
export declare class MaxRedirectsError extends RequestError {
|
|
197
199
|
readonly response: Response;
|
|
198
|
-
constructor(
|
|
200
|
+
constructor(request: Request);
|
|
199
201
|
}
|
|
200
202
|
export declare class HTTPError extends RequestError {
|
|
201
203
|
readonly response: Response;
|
|
202
|
-
constructor(response: Response
|
|
204
|
+
constructor(response: Response);
|
|
203
205
|
}
|
|
204
206
|
export declare class CacheError extends RequestError {
|
|
205
|
-
constructor(error: Error,
|
|
207
|
+
constructor(error: Error, request: Request);
|
|
206
208
|
}
|
|
207
209
|
export declare class UploadError extends RequestError {
|
|
208
|
-
constructor(error: Error,
|
|
210
|
+
constructor(error: Error, request: Request);
|
|
209
211
|
}
|
|
210
212
|
export declare class TimeoutError extends RequestError {
|
|
211
213
|
readonly timings: Timings;
|
|
212
214
|
readonly event: string;
|
|
213
|
-
constructor(error: TimedOutTimeoutError, timings: Timings,
|
|
215
|
+
constructor(error: TimedOutTimeoutError, timings: Timings, request: Request);
|
|
214
216
|
}
|
|
215
217
|
export declare class ReadError extends RequestError {
|
|
216
|
-
constructor(error: Error,
|
|
218
|
+
constructor(error: Error, request: Request);
|
|
217
219
|
}
|
|
218
220
|
export declare class UnsupportedProtocolError extends RequestError {
|
|
219
221
|
constructor(options: NormalizedOptions);
|
|
@@ -224,6 +226,8 @@ export default class Request extends Duplex implements RequestEvents<Request> {
|
|
|
224
226
|
_cannotHaveBody: boolean;
|
|
225
227
|
[kDownloadedSize]: number;
|
|
226
228
|
[kUploadedSize]: number;
|
|
229
|
+
[kStopReading]: boolean;
|
|
230
|
+
[kTriggerRead]: boolean;
|
|
227
231
|
[kBodySize]?: number;
|
|
228
232
|
[kServerResponsesPiped]: Set<ServerResponse>;
|
|
229
233
|
[kIsFromCache]?: boolean;
|
|
@@ -238,7 +242,6 @@ export default class Request extends Duplex implements RequestEvents<Request> {
|
|
|
238
242
|
requestUrl: string;
|
|
239
243
|
finalized: boolean;
|
|
240
244
|
redirects: string[];
|
|
241
|
-
errored: boolean;
|
|
242
245
|
constructor(url: string | URL, options?: Options, defaults?: Defaults);
|
|
243
246
|
static normalizeArguments(url?: string | URL, options?: Options, defaults?: Defaults): NormalizedOptions;
|
|
244
247
|
_lockWrite(): void;
|
|
@@ -246,6 +249,7 @@ export default class Request extends Duplex implements RequestEvents<Request> {
|
|
|
246
249
|
_finalizeBody(): Promise<void>;
|
|
247
250
|
_onResponse(response: IncomingMessage): Promise<void>;
|
|
248
251
|
_onRequest(request: ClientRequest): void;
|
|
252
|
+
_createCacheableRequest(url: URL, options: RequestOptions): Promise<ClientRequest | ResponseLike>;
|
|
249
253
|
_makeRequest(): Promise<void>;
|
|
250
254
|
_beforeError(error: Error): Promise<void>;
|
|
251
255
|
_read(): void;
|
|
@@ -255,6 +259,7 @@ export default class Request extends Duplex implements RequestEvents<Request> {
|
|
|
255
259
|
_destroy(error: Error | null, callback: (error: Error | null) => void): void;
|
|
256
260
|
get ip(): string | undefined;
|
|
257
261
|
get aborted(): boolean;
|
|
262
|
+
get socket(): Socket | undefined;
|
|
258
263
|
get downloadProgress(): Progress;
|
|
259
264
|
get uploadProgress(): Progress;
|
|
260
265
|
get timings(): Timings | undefined;
|
|
@@ -22,6 +22,7 @@ const proxy_events_1 = require("./utils/proxy-events");
|
|
|
22
22
|
const timed_out_1 = require("./utils/timed-out");
|
|
23
23
|
const url_to_options_1 = require("./utils/url-to-options");
|
|
24
24
|
const options_to_url_1 = require("./utils/options-to-url");
|
|
25
|
+
const weakable_map_1 = require("./utils/weakable-map");
|
|
25
26
|
const kRequest = Symbol('request');
|
|
26
27
|
const kResponse = Symbol('response');
|
|
27
28
|
const kResponseSize = Symbol('responseSize');
|
|
@@ -33,6 +34,8 @@ const kUnproxyEvents = Symbol('unproxyEvents');
|
|
|
33
34
|
const kIsFromCache = Symbol('isFromCache');
|
|
34
35
|
const kCancelTimeouts = Symbol('cancelTimeouts');
|
|
35
36
|
const kStartedReading = Symbol('startedReading');
|
|
37
|
+
const kStopReading = Symbol('stopReading');
|
|
38
|
+
const kTriggerRead = Symbol('triggerRead');
|
|
36
39
|
exports.kIsNormalizedAlready = Symbol('isNormalizedAlready');
|
|
37
40
|
const supportsBrotli = is_1.default.string(process.versions.brotli);
|
|
38
41
|
exports.withoutBody = new Set(['GET', 'HEAD']);
|
|
@@ -49,26 +52,7 @@ function validateSearchParameters(searchParameters) {
|
|
|
49
52
|
function isClientRequest(clientRequest) {
|
|
50
53
|
return is_1.default.object(clientRequest) && !('statusCode' in clientRequest);
|
|
51
54
|
}
|
|
52
|
-
const
|
|
53
|
-
// TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
|
|
54
|
-
Object.assign(options, url_to_options_1.default(url));
|
|
55
|
-
// `http-cache-semantics` checks this
|
|
56
|
-
delete options.url;
|
|
57
|
-
// TODO: `cacheable-request` is incorrectly typed
|
|
58
|
-
const cacheRequest = options.cacheableRequest(options, resolve);
|
|
59
|
-
// Restore options
|
|
60
|
-
options.url = url;
|
|
61
|
-
cacheRequest.once('error', (error) => {
|
|
62
|
-
if (error instanceof CacheableRequest.RequestError) {
|
|
63
|
-
// TODO: `options` should be `normalizedOptions`
|
|
64
|
-
reject(new RequestError(error.message, error, options));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// TODO: `options` should be `normalizedOptions`
|
|
68
|
-
reject(new CacheError(error, options));
|
|
69
|
-
});
|
|
70
|
-
cacheRequest.once('request', resolve);
|
|
71
|
-
});
|
|
55
|
+
const cacheableStore = new weakable_map_1.default();
|
|
72
56
|
const waitForOpenFile = async (file) => new Promise((resolve, reject) => {
|
|
73
57
|
const onError = (error) => {
|
|
74
58
|
reject(error);
|
|
@@ -109,36 +93,34 @@ const setNonEnumerableProperties = (sources, to) => {
|
|
|
109
93
|
Object.defineProperties(to, properties);
|
|
110
94
|
};
|
|
111
95
|
class RequestError extends Error {
|
|
112
|
-
constructor(message, error,
|
|
96
|
+
constructor(message, error, self) {
|
|
113
97
|
var _a;
|
|
114
98
|
super(message);
|
|
115
99
|
Error.captureStackTrace(this, this.constructor);
|
|
116
100
|
this.name = 'RequestError';
|
|
117
101
|
this.code = error.code;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
121
|
-
enumerable: false,
|
|
122
|
-
value: options
|
|
123
|
-
});
|
|
124
|
-
if (requestOrResponse instanceof http_1.IncomingMessage) {
|
|
125
|
-
Object.defineProperty(this, 'response', {
|
|
102
|
+
if (self instanceof Request) {
|
|
103
|
+
Object.defineProperty(this, 'request', {
|
|
126
104
|
enumerable: false,
|
|
127
|
-
value:
|
|
105
|
+
value: self
|
|
128
106
|
});
|
|
129
|
-
Object.defineProperty(this, '
|
|
107
|
+
Object.defineProperty(this, 'response', {
|
|
130
108
|
enumerable: false,
|
|
131
|
-
value:
|
|
109
|
+
value: self[kResponse]
|
|
132
110
|
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
111
|
+
Object.defineProperty(this, 'options', {
|
|
112
|
+
// This fails because of TS 3.7.2 useDefineForClassFields
|
|
113
|
+
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
136
114
|
enumerable: false,
|
|
137
|
-
value:
|
|
115
|
+
value: self.options
|
|
138
116
|
});
|
|
139
|
-
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
Object.defineProperty(this, 'options', {
|
|
120
|
+
// This fails because of TS 3.7.2 useDefineForClassFields
|
|
121
|
+
// Ref: https://github.com/microsoft/TypeScript/issues/34972
|
|
140
122
|
enumerable: false,
|
|
141
|
-
value:
|
|
123
|
+
value: self
|
|
142
124
|
});
|
|
143
125
|
}
|
|
144
126
|
this.timings = (_a = this.request) === null || _a === void 0 ? void 0 : _a.timings;
|
|
@@ -157,44 +139,36 @@ class RequestError extends Error {
|
|
|
157
139
|
}
|
|
158
140
|
exports.RequestError = RequestError;
|
|
159
141
|
class MaxRedirectsError extends RequestError {
|
|
160
|
-
constructor(
|
|
161
|
-
super(`Redirected ${maxRedirects} times. Aborting.`, {},
|
|
142
|
+
constructor(request) {
|
|
143
|
+
super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request);
|
|
162
144
|
this.name = 'MaxRedirectsError';
|
|
163
|
-
Object.defineProperty(this, 'response', {
|
|
164
|
-
enumerable: false,
|
|
165
|
-
value: response
|
|
166
|
-
});
|
|
167
145
|
}
|
|
168
146
|
}
|
|
169
147
|
exports.MaxRedirectsError = MaxRedirectsError;
|
|
170
148
|
class HTTPError extends RequestError {
|
|
171
|
-
constructor(response
|
|
172
|
-
super(`Response code ${response.statusCode} (${response.statusMessage})`, {},
|
|
149
|
+
constructor(response) {
|
|
150
|
+
super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request);
|
|
173
151
|
this.name = 'HTTPError';
|
|
174
|
-
Object.defineProperty(this, 'response', {
|
|
175
|
-
enumerable: false,
|
|
176
|
-
value: response
|
|
177
|
-
});
|
|
178
152
|
}
|
|
179
153
|
}
|
|
180
154
|
exports.HTTPError = HTTPError;
|
|
181
155
|
class CacheError extends RequestError {
|
|
182
|
-
constructor(error,
|
|
183
|
-
super(error.message, error,
|
|
156
|
+
constructor(error, request) {
|
|
157
|
+
super(error.message, error, request);
|
|
184
158
|
this.name = 'CacheError';
|
|
185
159
|
}
|
|
186
160
|
}
|
|
187
161
|
exports.CacheError = CacheError;
|
|
188
162
|
class UploadError extends RequestError {
|
|
189
|
-
constructor(error,
|
|
190
|
-
super(error.message, error,
|
|
163
|
+
constructor(error, request) {
|
|
164
|
+
super(error.message, error, request);
|
|
191
165
|
this.name = 'UploadError';
|
|
192
166
|
}
|
|
193
167
|
}
|
|
194
168
|
exports.UploadError = UploadError;
|
|
195
169
|
class TimeoutError extends RequestError {
|
|
196
|
-
constructor(error, timings,
|
|
197
|
-
super(error.message, error,
|
|
170
|
+
constructor(error, timings, request) {
|
|
171
|
+
super(error.message, error, request);
|
|
198
172
|
this.name = 'TimeoutError';
|
|
199
173
|
this.event = error.event;
|
|
200
174
|
this.timings = timings;
|
|
@@ -202,8 +176,8 @@ class TimeoutError extends RequestError {
|
|
|
202
176
|
}
|
|
203
177
|
exports.TimeoutError = TimeoutError;
|
|
204
178
|
class ReadError extends RequestError {
|
|
205
|
-
constructor(error,
|
|
206
|
-
super(error.message, error,
|
|
179
|
+
constructor(error, request) {
|
|
180
|
+
super(error.message, error, request);
|
|
207
181
|
this.name = 'ReadError';
|
|
208
182
|
}
|
|
209
183
|
}
|
|
@@ -235,7 +209,8 @@ class Request extends stream_1.Duplex {
|
|
|
235
209
|
this.finalized = false;
|
|
236
210
|
this[kServerResponsesPiped] = new Set();
|
|
237
211
|
this.redirects = [];
|
|
238
|
-
this
|
|
212
|
+
this[kStopReading] = false;
|
|
213
|
+
this[kTriggerRead] = false;
|
|
239
214
|
// TODO: Remove this when targeting Node.js >= 12
|
|
240
215
|
this._progressCallbacks = [];
|
|
241
216
|
const unlockWrite = () => this._unlockWrite();
|
|
@@ -421,20 +396,20 @@ class Request extends stream_1.Duplex {
|
|
|
421
396
|
options.url.password = options.password;
|
|
422
397
|
}
|
|
423
398
|
// `options.cookieJar`
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
399
|
+
const { cookieJar } = options;
|
|
400
|
+
if (cookieJar) {
|
|
401
|
+
let { setCookie, getCookieString } = cookieJar;
|
|
402
|
+
is_1.assert.function_(setCookie);
|
|
403
|
+
is_1.assert.function_(getCookieString);
|
|
404
|
+
/* istanbul ignore next: Horrible `tough-cookie` v3 check */
|
|
427
405
|
if (setCookie.length === 4 && getCookieString.length === 0) {
|
|
428
406
|
setCookie = util_1.promisify(setCookie.bind(options.cookieJar));
|
|
429
407
|
getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar));
|
|
408
|
+
options.cookieJar = {
|
|
409
|
+
setCookie: setCookie.bind(cookieJar),
|
|
410
|
+
getCookieString: getCookieString.bind(getCookieString)
|
|
411
|
+
};
|
|
430
412
|
}
|
|
431
|
-
else if (setCookie.length !== 2) {
|
|
432
|
-
throw new TypeError('`options.cookieJar.setCookie` needs to be an async function with 2 arguments');
|
|
433
|
-
}
|
|
434
|
-
else if (getCookieString.length !== 1) {
|
|
435
|
-
throw new TypeError('`options.cookieJar.getCookieString` needs to be an async function with 1 argument');
|
|
436
|
-
}
|
|
437
|
-
options.cookieJar = { setCookie, getCookieString };
|
|
438
413
|
}
|
|
439
414
|
// `options.searchParams`
|
|
440
415
|
if (options.searchParams) {
|
|
@@ -454,9 +429,11 @@ class Request extends stream_1.Duplex {
|
|
|
454
429
|
}
|
|
455
430
|
}
|
|
456
431
|
// `options.cache`
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
432
|
+
const { cache } = options;
|
|
433
|
+
if (cache) {
|
|
434
|
+
if (!cacheableStore.has(cache)) {
|
|
435
|
+
cacheableStore.set(cache, new CacheableRequest(((requestOptions, handler) => requestOptions[kRequest](requestOptions, handler)), cache));
|
|
436
|
+
}
|
|
460
437
|
}
|
|
461
438
|
// `options.dnsCache`
|
|
462
439
|
if (options.dnsCache === true) {
|
|
@@ -632,7 +609,16 @@ class Request extends stream_1.Duplex {
|
|
|
632
609
|
this.emit('downloadProgress', this.downloadProgress);
|
|
633
610
|
});
|
|
634
611
|
response.on('error', (error) => {
|
|
635
|
-
this._beforeError(new ReadError(error,
|
|
612
|
+
this._beforeError(new ReadError(error, this));
|
|
613
|
+
});
|
|
614
|
+
response.once('aborted', () => {
|
|
615
|
+
if (this.aborted) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
this._beforeError(new ReadError({
|
|
619
|
+
name: 'Error',
|
|
620
|
+
message: 'The server aborted the pending request'
|
|
621
|
+
}, this));
|
|
636
622
|
});
|
|
637
623
|
this.emit('downloadProgress', this.downloadProgress);
|
|
638
624
|
const rawCookies = response.headers['set-cookie'];
|
|
@@ -676,7 +662,7 @@ class Request extends stream_1.Duplex {
|
|
|
676
662
|
}
|
|
677
663
|
}
|
|
678
664
|
if (this.redirects.length >= options.maxRedirects) {
|
|
679
|
-
this._beforeError(new MaxRedirectsError(
|
|
665
|
+
this._beforeError(new MaxRedirectsError(this));
|
|
680
666
|
return;
|
|
681
667
|
}
|
|
682
668
|
try {
|
|
@@ -716,14 +702,13 @@ class Request extends stream_1.Duplex {
|
|
|
716
702
|
const limitStatusCode = options.followRedirect ? 299 : 399;
|
|
717
703
|
const isOk = (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
|
|
718
704
|
if (options.throwHttpErrors && !isOk) {
|
|
719
|
-
await this._beforeError(new HTTPError(typedResponse
|
|
705
|
+
await this._beforeError(new HTTPError(typedResponse));
|
|
720
706
|
if (this.destroyed) {
|
|
721
707
|
return;
|
|
722
708
|
}
|
|
723
709
|
}
|
|
724
|
-
// We need to call `_read()` only when the Request stream is flowing
|
|
725
710
|
response.on('readable', () => {
|
|
726
|
-
if (this
|
|
711
|
+
if (this[kTriggerRead]) {
|
|
727
712
|
this._read();
|
|
728
713
|
}
|
|
729
714
|
});
|
|
@@ -762,10 +747,10 @@ class Request extends stream_1.Duplex {
|
|
|
762
747
|
});
|
|
763
748
|
request.once('error', (error) => {
|
|
764
749
|
if (error instanceof timed_out_1.TimeoutError) {
|
|
765
|
-
error = new TimeoutError(error, this.timings,
|
|
750
|
+
error = new TimeoutError(error, this.timings, this);
|
|
766
751
|
}
|
|
767
752
|
else {
|
|
768
|
-
error = new RequestError(error.message, error,
|
|
753
|
+
error = new RequestError(error.message, error, this);
|
|
769
754
|
}
|
|
770
755
|
this._beforeError(error);
|
|
771
756
|
});
|
|
@@ -777,7 +762,7 @@ class Request extends stream_1.Duplex {
|
|
|
777
762
|
if (is_1.default.nodeStream(options.body)) {
|
|
778
763
|
options.body.pipe(currentRequest);
|
|
779
764
|
options.body.once('error', (error) => {
|
|
780
|
-
this._beforeError(new UploadError(error,
|
|
765
|
+
this._beforeError(new UploadError(error, this));
|
|
781
766
|
});
|
|
782
767
|
options.body.once('end', () => {
|
|
783
768
|
delete options.body;
|
|
@@ -797,6 +782,26 @@ class Request extends stream_1.Duplex {
|
|
|
797
782
|
}
|
|
798
783
|
this.emit('request', request);
|
|
799
784
|
}
|
|
785
|
+
async _createCacheableRequest(url, options) {
|
|
786
|
+
return new Promise((resolve, reject) => {
|
|
787
|
+
// TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed
|
|
788
|
+
Object.assign(options, url_to_options_1.default(url));
|
|
789
|
+
// `http-cache-semantics` checks this
|
|
790
|
+
delete options.url;
|
|
791
|
+
// This is ugly
|
|
792
|
+
const cacheRequest = cacheableStore.get(options.cache)(options, resolve);
|
|
793
|
+
// Restore options
|
|
794
|
+
options.url = url;
|
|
795
|
+
cacheRequest.once('error', (error) => {
|
|
796
|
+
if (error instanceof CacheableRequest.CacheError) {
|
|
797
|
+
reject(new CacheError(error, this));
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
reject(error);
|
|
801
|
+
});
|
|
802
|
+
cacheRequest.once('request', resolve);
|
|
803
|
+
});
|
|
804
|
+
}
|
|
800
805
|
async _makeRequest() {
|
|
801
806
|
var _a, _b;
|
|
802
807
|
const { options } = this;
|
|
@@ -853,7 +858,7 @@ class Request extends stream_1.Duplex {
|
|
|
853
858
|
fallbackFn = isHttps ? https.request : http.request;
|
|
854
859
|
}
|
|
855
860
|
const realFn = (_b = options.request, (_b !== null && _b !== void 0 ? _b : fallbackFn));
|
|
856
|
-
const fn = options.
|
|
861
|
+
const fn = options.cache ? this._createCacheableRequest.bind(this) : realFn;
|
|
857
862
|
if (agent && !options.http2) {
|
|
858
863
|
options.agent = agent[isHttps ? 'https' : 'http'];
|
|
859
864
|
}
|
|
@@ -890,21 +895,20 @@ class Request extends stream_1.Duplex {
|
|
|
890
895
|
if (error instanceof RequestError) {
|
|
891
896
|
throw error;
|
|
892
897
|
}
|
|
893
|
-
throw new RequestError(error.message, error,
|
|
898
|
+
throw new RequestError(error.message, error, this);
|
|
894
899
|
}
|
|
895
900
|
}
|
|
896
901
|
async _beforeError(error) {
|
|
897
|
-
this
|
|
902
|
+
this[kStopReading] = true;
|
|
898
903
|
if (!(error instanceof RequestError)) {
|
|
899
|
-
error = new RequestError(error.message, error, this
|
|
904
|
+
error = new RequestError(error.message, error, this);
|
|
900
905
|
}
|
|
901
906
|
try {
|
|
902
907
|
const { response } = error;
|
|
903
|
-
if (response
|
|
904
|
-
response.
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
});
|
|
908
|
+
if (response) {
|
|
909
|
+
response.setEncoding(this._readableState.encoding);
|
|
910
|
+
response.rawBody = await getStream.buffer(response);
|
|
911
|
+
response.body = response.rawBody.toString();
|
|
908
912
|
}
|
|
909
913
|
}
|
|
910
914
|
catch (_) { }
|
|
@@ -915,14 +919,21 @@ class Request extends stream_1.Duplex {
|
|
|
915
919
|
}
|
|
916
920
|
}
|
|
917
921
|
catch (error_) {
|
|
918
|
-
error = new RequestError(error_.message, error_, this
|
|
922
|
+
error = new RequestError(error_.message, error_, this);
|
|
919
923
|
}
|
|
920
924
|
this.destroy(error);
|
|
921
925
|
}
|
|
922
926
|
_read() {
|
|
923
|
-
|
|
927
|
+
this[kTriggerRead] = true;
|
|
928
|
+
const response = this[kResponse];
|
|
929
|
+
if (response && !this[kStopReading]) {
|
|
930
|
+
// We cannot put this in the `if` above
|
|
931
|
+
// because `.read()` also triggers the `end` event
|
|
932
|
+
if (response.readableLength) {
|
|
933
|
+
this[kTriggerRead] = false;
|
|
934
|
+
}
|
|
924
935
|
let data;
|
|
925
|
-
while ((data =
|
|
936
|
+
while ((data = response.read()) !== null) {
|
|
926
937
|
this[kDownloadedSize] += data.length;
|
|
927
938
|
this[kStartedReading] = true;
|
|
928
939
|
const progress = this.downloadProgress;
|
|
@@ -988,8 +999,12 @@ class Request extends stream_1.Duplex {
|
|
|
988
999
|
}
|
|
989
1000
|
}
|
|
990
1001
|
_destroy(error, callback) {
|
|
1002
|
+
var _a;
|
|
991
1003
|
if (kRequest in this) {
|
|
992
|
-
|
|
1004
|
+
// TODO: Remove the next `if` when https://github.com/nodejs/node/issues/32851 gets fixed
|
|
1005
|
+
if (!((_a = this[kResponse]) === null || _a === void 0 ? void 0 : _a.complete)) {
|
|
1006
|
+
this[kRequest].abort();
|
|
1007
|
+
}
|
|
993
1008
|
}
|
|
994
1009
|
else {
|
|
995
1010
|
this.once('finalized', () => {
|
|
@@ -999,7 +1014,7 @@ class Request extends stream_1.Duplex {
|
|
|
999
1014
|
});
|
|
1000
1015
|
}
|
|
1001
1016
|
if (error !== null && !is_1.default.undefined(error) && !(error instanceof RequestError)) {
|
|
1002
|
-
error = new RequestError(error.message, error, this
|
|
1017
|
+
error = new RequestError(error.message, error, this);
|
|
1003
1018
|
}
|
|
1004
1019
|
callback(error);
|
|
1005
1020
|
}
|
|
@@ -1011,6 +1026,10 @@ class Request extends stream_1.Duplex {
|
|
|
1011
1026
|
var _a;
|
|
1012
1027
|
return Boolean((_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.aborted);
|
|
1013
1028
|
}
|
|
1029
|
+
get socket() {
|
|
1030
|
+
var _a;
|
|
1031
|
+
return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket;
|
|
1032
|
+
}
|
|
1014
1033
|
get downloadProgress() {
|
|
1015
1034
|
let percent;
|
|
1016
1035
|
if (this[kResponseSize]) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class WeakableMap {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.weakMap = new WeakMap();
|
|
6
|
+
this.map = new Map();
|
|
7
|
+
}
|
|
8
|
+
set(key, value) {
|
|
9
|
+
if (typeof key === 'object') {
|
|
10
|
+
this.weakMap.set(key, value);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
this.map.set(key, value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
get(key) {
|
|
17
|
+
if (typeof key === 'object') {
|
|
18
|
+
return this.weakMap.get(key);
|
|
19
|
+
}
|
|
20
|
+
return this.map.get(key);
|
|
21
|
+
}
|
|
22
|
+
has(key) {
|
|
23
|
+
if (typeof key === 'object') {
|
|
24
|
+
return this.weakMap.has(key);
|
|
25
|
+
}
|
|
26
|
+
return this.map.has(key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = WeakableMap;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "got",
|
|
3
|
-
"version": "11.0.0
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Human-friendly and powerful HTTP request library for Node.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/got",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@types/node-fetch": "^2.5.5",
|
|
67
67
|
"@types/request": "^2.48.4",
|
|
68
68
|
"@types/sinon": "^9.0.0",
|
|
69
|
-
"@types/tough-cookie": "^
|
|
69
|
+
"@types/tough-cookie": "^4.0.0",
|
|
70
70
|
"@typescript-eslint/eslint-plugin": "^2.27.0",
|
|
71
71
|
"@typescript-eslint/parser": "^2.27.0",
|
|
72
72
|
"ava": "^3.6.0",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"slow-stream": "0.0.4",
|
|
90
90
|
"tempy": "^0.5.0",
|
|
91
91
|
"to-readable-stream": "^2.1.0",
|
|
92
|
-
"tough-cookie": "^
|
|
92
|
+
"tough-cookie": "^4.0.0",
|
|
93
93
|
"typescript": "3.7.5",
|
|
94
94
|
"xo": "^0.29.0"
|
|
95
95
|
},
|
package/readme.md
CHANGED
|
@@ -784,6 +784,12 @@ Type: `string | object | Buffer` *(Depending on `options.responseType`)*
|
|
|
784
784
|
|
|
785
785
|
The result of the request.
|
|
786
786
|
|
|
787
|
+
##### rawBody
|
|
788
|
+
|
|
789
|
+
Type: `Buffer`
|
|
790
|
+
|
|
791
|
+
The raw result of the request.
|
|
792
|
+
|
|
787
793
|
##### url
|
|
788
794
|
|
|
789
795
|
Type: `string`
|
|
@@ -934,6 +940,10 @@ The same as `response.timings`.
|
|
|
934
940
|
|
|
935
941
|
The same as `response.isFromCache`.
|
|
936
942
|
|
|
943
|
+
##### .socket
|
|
944
|
+
|
|
945
|
+
The same as `response.socket`.
|
|
946
|
+
|
|
937
947
|
##### .on('error', error)
|
|
938
948
|
|
|
939
949
|
The emitted `error` is an instance of [`RequestError`](#got.requesterror).
|
|
@@ -1039,7 +1049,7 @@ const mergedHandlers = got.extend({
|
|
|
1039
1049
|
|
|
1040
1050
|
```js
|
|
1041
1051
|
const handler = (options, next) => {
|
|
1042
|
-
if (options.
|
|
1052
|
+
if (options.isStream) {
|
|
1043
1053
|
// It's a Stream
|
|
1044
1054
|
return next(options);
|
|
1045
1055
|
}
|
|
@@ -1311,7 +1321,7 @@ stream.destroy();
|
|
|
1311
1321
|
<a name="cache-adapters"></a>
|
|
1312
1322
|
## Cache
|
|
1313
1323
|
|
|
1314
|
-
Got implements [RFC 7234](
|
|
1324
|
+
Got implements [RFC 7234](https://httpwg.org/specs/rfc7234.html) compliant HTTP caching which works out of the box in-memory and is easily pluggable with a wide range of storage adapters. Fresh cache entries are served directly from the cache, and stale cache entries are revalidated with `If-None-Match`/`If-Modified-Since` headers. You can read more about the underlying cache behavior in the [`cacheable-request` documentation](https://github.com/lukechilds/cacheable-request). For DNS cache, Got uses [`cacheable-lookup`](https://github.com/szmarczak/cacheable-lookup).
|
|
1315
1325
|
|
|
1316
1326
|
You can use the JavaScript `Map` type as an in-memory cache:
|
|
1317
1327
|
|