got 11.4.0 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/source/as-promise/index.d.ts +1 -3
- package/dist/source/as-promise/index.js +56 -117
- package/dist/source/as-promise/normalize-arguments.d.ts +3 -0
- package/dist/source/as-promise/normalize-arguments.js +78 -0
- package/dist/source/as-promise/parse-body.d.ts +3 -0
- package/dist/source/as-promise/parse-body.js +25 -0
- package/dist/source/as-promise/types.d.ts +235 -58
- package/dist/source/as-promise/types.js +29 -16
- package/dist/source/{as-promise → core}/calculate-retry-delay.d.ts +2 -1
- package/dist/source/core/calculate-retry-delay.js +29 -0
- package/dist/source/core/index.d.ts +851 -28
- package/dist/source/core/index.js +291 -55
- package/dist/source/core/utils/dns-ip-version.js +1 -0
- package/dist/source/core/utils/get-body-size.d.ts +2 -4
- package/dist/source/core/utils/is-form-data.d.ts +2 -2
- package/dist/source/core/utils/is-response-ok.d.ts +2 -0
- package/dist/source/core/utils/is-response-ok.js +8 -0
- package/dist/source/core/utils/options-to-url.d.ts +0 -1
- package/dist/source/core/utils/timed-out.js +1 -0
- package/dist/source/core/utils/url-to-options.d.ts +0 -1
- package/dist/source/core/utils/weakable-map.d.ts +1 -1
- package/dist/source/create.js +42 -13
- package/dist/source/index.js +16 -6
- package/dist/source/types.d.ts +245 -8
- package/dist/source/utils/deep-freeze.d.ts +1 -1
- package/dist/source/utils/deprecation-warning.js +1 -1
- package/package.json +30 -29
- package/readme.md +171 -35
- package/dist/source/as-promise/calculate-retry-delay.js +0 -38
- package/dist/source/as-promise/core.d.ts +0 -13
- package/dist/source/as-promise/core.js +0 -124
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { NormalizedOptions, CancelableRequest } from './types';
|
|
2
|
-
|
|
3
|
-
export default function asPromise<T>(options: NormalizedOptions): CancelableRequest<T>;
|
|
2
|
+
export default function asPromise<T>(normalizedOptions: NormalizedOptions): CancelableRequest<T>;
|
|
4
3
|
export * from './types';
|
|
5
|
-
export { PromisableRequest };
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
5
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
13
|
const events_1 = require("events");
|
|
14
|
+
const is_1 = require("@sindresorhus/is");
|
|
7
15
|
const PCancelable = require("p-cancelable");
|
|
8
|
-
const calculate_retry_delay_1 = require("./calculate-retry-delay");
|
|
9
16
|
const types_1 = require("./types");
|
|
10
|
-
const
|
|
11
|
-
|
|
17
|
+
const parse_body_1 = require("./parse-body");
|
|
18
|
+
const core_1 = require("../core");
|
|
12
19
|
const proxy_events_1 = require("../core/utils/proxy-events");
|
|
13
20
|
const get_buffer_1 = require("../core/utils/get-buffer");
|
|
21
|
+
const is_response_ok_1 = require("../core/utils/is-response-ok");
|
|
14
22
|
const proxiedRequestEvents = [
|
|
15
23
|
'request',
|
|
16
24
|
'response',
|
|
@@ -18,85 +26,63 @@ const proxiedRequestEvents = [
|
|
|
18
26
|
'uploadProgress',
|
|
19
27
|
'downloadProgress'
|
|
20
28
|
];
|
|
21
|
-
function asPromise(
|
|
22
|
-
let retryCount = 0;
|
|
29
|
+
function asPromise(normalizedOptions) {
|
|
23
30
|
let globalRequest;
|
|
24
31
|
let globalResponse;
|
|
25
32
|
const emitter = new events_1.EventEmitter();
|
|
26
|
-
const promise = new PCancelable((resolve,
|
|
27
|
-
const makeRequest = () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// so the HTTP errors are caught and the request is retried.
|
|
31
|
-
// The error is **eventually** thrown if the user value is true.
|
|
32
|
-
const { throwHttpErrors } = options;
|
|
33
|
-
if (!throwHttpErrors) {
|
|
34
|
-
options.throwHttpErrors = true;
|
|
35
|
-
}
|
|
36
|
-
// Note from @szmarczak: I think we should use `request.options` instead of the local options
|
|
37
|
-
const request = new core_1.default(options.url, options);
|
|
33
|
+
const promise = new PCancelable((resolve, reject, onCancel) => {
|
|
34
|
+
const makeRequest = (retryCount) => {
|
|
35
|
+
const request = new core_1.default(undefined, normalizedOptions);
|
|
36
|
+
request.retryCount = retryCount;
|
|
38
37
|
request._noPipe = true;
|
|
39
38
|
onCancel(() => request.destroy());
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
};
|
|
39
|
+
onCancel.shouldReject = false;
|
|
40
|
+
onCancel(() => reject(new types_1.CancelError(request)));
|
|
53
41
|
globalRequest = request;
|
|
54
|
-
|
|
42
|
+
request.once('response', async (response) => {
|
|
55
43
|
var _a;
|
|
56
44
|
response.retryCount = retryCount;
|
|
57
45
|
if (response.request.aborted) {
|
|
58
46
|
// Canceled while downloading - will throw a `CancelError` or `TimeoutError` error
|
|
59
47
|
return;
|
|
60
48
|
}
|
|
61
|
-
const isOk = () => {
|
|
62
|
-
const { statusCode } = response;
|
|
63
|
-
const limitStatusCode = options.followRedirect ? 299 : 399;
|
|
64
|
-
return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304;
|
|
65
|
-
};
|
|
66
49
|
// Download body
|
|
67
50
|
let rawBody;
|
|
68
51
|
try {
|
|
69
52
|
rawBody = await get_buffer_1.default(request);
|
|
70
53
|
response.rawBody = rawBody;
|
|
71
54
|
}
|
|
72
|
-
catch (
|
|
55
|
+
catch (_b) {
|
|
73
56
|
// The same error is caught below.
|
|
74
57
|
// See request.once('error')
|
|
75
58
|
return;
|
|
76
59
|
}
|
|
60
|
+
if (request._isAboutToError) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
77
63
|
// Parse body
|
|
78
64
|
const contentEncoding = ((_a = response.headers['content-encoding']) !== null && _a !== void 0 ? _a : '').toLowerCase();
|
|
79
65
|
const isCompressed = ['gzip', 'deflate', 'br'].includes(contentEncoding);
|
|
66
|
+
const { options } = request;
|
|
80
67
|
if (isCompressed && !options.decompress) {
|
|
81
68
|
response.body = rawBody;
|
|
82
69
|
}
|
|
83
70
|
else {
|
|
84
71
|
try {
|
|
85
|
-
response.body =
|
|
72
|
+
response.body = parse_body_1.default(response, options.responseType, options.parseJson, options.encoding);
|
|
86
73
|
}
|
|
87
74
|
catch (error) {
|
|
88
75
|
// Fallback to `utf8`
|
|
89
76
|
response.body = rawBody.toString();
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
reject(error);
|
|
77
|
+
if (is_response_ok_1.isResponseOk(response)) {
|
|
78
|
+
request._beforeError(error);
|
|
93
79
|
return;
|
|
94
80
|
}
|
|
95
81
|
}
|
|
96
82
|
}
|
|
97
83
|
try {
|
|
98
84
|
for (const [index, hook] of options.hooks.afterResponse.entries()) {
|
|
99
|
-
// @ts-
|
|
85
|
+
// @ts-expect-error TS doesn't notice that CancelableRequest is a Promise
|
|
100
86
|
// eslint-disable-next-line no-await-in-loop
|
|
101
87
|
response = await hook(response, async (updatedOptions) => {
|
|
102
88
|
const typedOptions = core_1.default.normalizeArguments(undefined, {
|
|
@@ -124,89 +110,40 @@ function asPromise(options) {
|
|
|
124
110
|
}
|
|
125
111
|
}
|
|
126
112
|
catch (error) {
|
|
127
|
-
|
|
128
|
-
reject(new types_1.RequestError(error.message, error, request));
|
|
113
|
+
request._beforeError(new types_1.RequestError(error.message, error, request));
|
|
129
114
|
return;
|
|
130
115
|
}
|
|
131
|
-
if (
|
|
132
|
-
|
|
116
|
+
if (!is_response_ok_1.isResponseOk(response)) {
|
|
117
|
+
request._beforeError(new types_1.HTTPError(response));
|
|
133
118
|
return;
|
|
134
119
|
}
|
|
135
120
|
globalResponse = response;
|
|
136
|
-
resolve(options.resolveBodyOnly ? response.body : response);
|
|
137
|
-
};
|
|
138
|
-
const onError =
|
|
121
|
+
resolve(request.options.resolveBodyOnly ? response.body : response);
|
|
122
|
+
});
|
|
123
|
+
const onError = (error) => {
|
|
139
124
|
if (promise.isCanceled) {
|
|
140
125
|
return;
|
|
141
126
|
}
|
|
142
|
-
|
|
143
|
-
|
|
127
|
+
const { options } = request;
|
|
128
|
+
if (error instanceof types_1.HTTPError && !options.throwHttpErrors) {
|
|
129
|
+
const { response } = error;
|
|
130
|
+
resolve(request.options.resolveBodyOnly ? response.body : response);
|
|
144
131
|
return;
|
|
145
132
|
}
|
|
146
|
-
request.off('response', onResponse);
|
|
147
|
-
let backoff;
|
|
148
|
-
retryCount++;
|
|
149
|
-
try {
|
|
150
|
-
backoff = await options.retry.calculateDelay({
|
|
151
|
-
attemptCount: retryCount,
|
|
152
|
-
retryOptions: options.retry,
|
|
153
|
-
error,
|
|
154
|
-
computedValue: calculate_retry_delay_1.default({
|
|
155
|
-
attemptCount: retryCount,
|
|
156
|
-
retryOptions: options.retry,
|
|
157
|
-
error,
|
|
158
|
-
computedValue: 0
|
|
159
|
-
})
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
catch (error_) {
|
|
163
|
-
// Don't emit the `response` event
|
|
164
|
-
request.destroy();
|
|
165
|
-
reject(new types_1.RequestError(error_.message, error, request));
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (backoff) {
|
|
169
|
-
// Don't emit the `response` event
|
|
170
|
-
request.destroy();
|
|
171
|
-
const retry = async () => {
|
|
172
|
-
options.throwHttpErrors = throwHttpErrors;
|
|
173
|
-
try {
|
|
174
|
-
for (const hook of options.hooks.beforeRetry) {
|
|
175
|
-
// eslint-disable-next-line no-await-in-loop
|
|
176
|
-
await hook(options, error, retryCount);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
catch (error_) {
|
|
180
|
-
// Don't emit the `response` event
|
|
181
|
-
request.destroy();
|
|
182
|
-
reject(new types_1.RequestError(error_.message, error, request));
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
makeRequest();
|
|
186
|
-
};
|
|
187
|
-
setTimeout(retry, backoff);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
// The retry has not been made
|
|
191
|
-
retryCount--;
|
|
192
|
-
if (error instanceof types_1.HTTPError) {
|
|
193
|
-
// The error will be handled by the `response` event
|
|
194
|
-
onResponse(request._response);
|
|
195
|
-
// Reattach the error handler, because there may be a timeout later.
|
|
196
|
-
process.nextTick(() => {
|
|
197
|
-
request.once('error', onError);
|
|
198
|
-
});
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
// Don't emit the `response` event
|
|
202
|
-
request.destroy();
|
|
203
133
|
reject(error);
|
|
204
134
|
};
|
|
205
|
-
request.once('response', onResponse);
|
|
206
135
|
request.once('error', onError);
|
|
136
|
+
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)) {
|
|
139
|
+
onError(error);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
makeRequest(newRetryCount);
|
|
143
|
+
});
|
|
207
144
|
proxy_events_1.default(request, emitter, proxiedRequestEvents);
|
|
208
145
|
};
|
|
209
|
-
makeRequest();
|
|
146
|
+
makeRequest(0);
|
|
210
147
|
});
|
|
211
148
|
promise.on = (event, fn) => {
|
|
212
149
|
emitter.on(event, fn);
|
|
@@ -216,14 +153,16 @@ function asPromise(options) {
|
|
|
216
153
|
const newPromise = (async () => {
|
|
217
154
|
// Wait until downloading has ended
|
|
218
155
|
await promise;
|
|
219
|
-
|
|
156
|
+
const { options } = globalResponse.request;
|
|
157
|
+
return parse_body_1.default(globalResponse, responseType, options.parseJson, options.encoding);
|
|
220
158
|
})();
|
|
221
159
|
Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise));
|
|
222
160
|
return newPromise;
|
|
223
161
|
};
|
|
224
162
|
promise.json = () => {
|
|
225
|
-
|
|
226
|
-
|
|
163
|
+
const { headers } = globalRequest.options;
|
|
164
|
+
if (!globalRequest.writableFinished && headers.accept === undefined) {
|
|
165
|
+
headers.accept = 'application/json';
|
|
227
166
|
}
|
|
228
167
|
return shortcut('json');
|
|
229
168
|
};
|
|
@@ -232,4 +171,4 @@ function asPromise(options) {
|
|
|
232
171
|
return promise;
|
|
233
172
|
}
|
|
234
173
|
exports.default = asPromise;
|
|
235
|
-
|
|
174
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const is_1 = require("@sindresorhus/is");
|
|
4
|
+
const normalizeArguments = (options, defaults) => {
|
|
5
|
+
if (is_1.default.null_(options.encoding)) {
|
|
6
|
+
throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead');
|
|
7
|
+
}
|
|
8
|
+
is_1.assert.any([is_1.default.string, is_1.default.undefined], options.encoding);
|
|
9
|
+
is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.resolveBodyOnly);
|
|
10
|
+
is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.methodRewriting);
|
|
11
|
+
is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.isStream);
|
|
12
|
+
is_1.assert.any([is_1.default.string, is_1.default.undefined], options.responseType);
|
|
13
|
+
// `options.responseType`
|
|
14
|
+
if (options.responseType === undefined) {
|
|
15
|
+
options.responseType = 'text';
|
|
16
|
+
}
|
|
17
|
+
// `options.retry`
|
|
18
|
+
const { retry } = options;
|
|
19
|
+
if (defaults) {
|
|
20
|
+
options.retry = { ...defaults.retry };
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
options.retry = {
|
|
24
|
+
calculateDelay: retryObject => retryObject.computedValue,
|
|
25
|
+
limit: 0,
|
|
26
|
+
methods: [],
|
|
27
|
+
statusCodes: [],
|
|
28
|
+
errorCodes: [],
|
|
29
|
+
maxRetryAfter: undefined
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (is_1.default.object(retry)) {
|
|
33
|
+
options.retry = {
|
|
34
|
+
...options.retry,
|
|
35
|
+
...retry
|
|
36
|
+
};
|
|
37
|
+
options.retry.methods = [...new Set(options.retry.methods.map(method => method.toUpperCase()))];
|
|
38
|
+
options.retry.statusCodes = [...new Set(options.retry.statusCodes)];
|
|
39
|
+
options.retry.errorCodes = [...new Set(options.retry.errorCodes)];
|
|
40
|
+
}
|
|
41
|
+
else if (is_1.default.number(retry)) {
|
|
42
|
+
options.retry.limit = retry;
|
|
43
|
+
}
|
|
44
|
+
if (is_1.default.undefined(options.retry.maxRetryAfter)) {
|
|
45
|
+
options.retry.maxRetryAfter = Math.min(
|
|
46
|
+
// TypeScript is not smart enough to handle `.filter(x => is.number(x))`.
|
|
47
|
+
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
|
|
48
|
+
...[options.timeout.request, options.timeout.connect].filter(is_1.default.number));
|
|
49
|
+
}
|
|
50
|
+
// `options.pagination`
|
|
51
|
+
if (is_1.default.object(options.pagination)) {
|
|
52
|
+
if (defaults) {
|
|
53
|
+
options.pagination = {
|
|
54
|
+
...defaults.pagination,
|
|
55
|
+
...options.pagination
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const { pagination } = options;
|
|
59
|
+
if (!is_1.default.function_(pagination.transform)) {
|
|
60
|
+
throw new Error('`options.pagination.transform` must be implemented');
|
|
61
|
+
}
|
|
62
|
+
if (!is_1.default.function_(pagination.shouldContinue)) {
|
|
63
|
+
throw new Error('`options.pagination.shouldContinue` must be implemented');
|
|
64
|
+
}
|
|
65
|
+
if (!is_1.default.function_(pagination.filter)) {
|
|
66
|
+
throw new TypeError('`options.pagination.filter` must be implemented');
|
|
67
|
+
}
|
|
68
|
+
if (!is_1.default.function_(pagination.paginate)) {
|
|
69
|
+
throw new Error('`options.pagination.paginate` must be implemented');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// JSON mode
|
|
73
|
+
if (options.responseType === 'json' && options.headers.accept === undefined) {
|
|
74
|
+
options.headers.accept = 'application/json';
|
|
75
|
+
}
|
|
76
|
+
return options;
|
|
77
|
+
};
|
|
78
|
+
exports.default = normalizeArguments;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ResponseType, Response, ParseJsonFunction } from './types';
|
|
2
|
+
declare const parseBody: (response: Response, responseType: ResponseType, parseJson: ParseJsonFunction, encoding?: "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex" | undefined) => unknown;
|
|
3
|
+
export default parseBody;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const types_1 = require("./types");
|
|
4
|
+
const parseBody = (response, responseType, parseJson, encoding) => {
|
|
5
|
+
const { rawBody } = response;
|
|
6
|
+
try {
|
|
7
|
+
if (responseType === 'text') {
|
|
8
|
+
return rawBody.toString(encoding);
|
|
9
|
+
}
|
|
10
|
+
if (responseType === 'json') {
|
|
11
|
+
return rawBody.length === 0 ? '' : parseJson(rawBody.toString());
|
|
12
|
+
}
|
|
13
|
+
if (responseType === 'buffer') {
|
|
14
|
+
return Buffer.from(rawBody);
|
|
15
|
+
}
|
|
16
|
+
throw new types_1.ParseError({
|
|
17
|
+
message: `Unknown body type '${responseType}'`,
|
|
18
|
+
name: 'Error'
|
|
19
|
+
}, response);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new types_1.ParseError(error, response);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.default = parseBody;
|