got 14.5.0 → 14.6.1
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.js +46 -10
- package/dist/source/core/diagnostics-channel.d.ts +89 -0
- package/dist/source/core/diagnostics-channel.js +49 -0
- package/dist/source/core/errors.d.ts +14 -1
- package/dist/source/core/errors.js +27 -19
- package/dist/source/core/index.d.ts +9 -1
- package/dist/source/core/index.js +429 -181
- package/dist/source/core/options.d.ts +245 -11
- package/dist/source/core/options.js +194 -68
- package/dist/source/core/response.d.ts +2 -0
- package/dist/source/core/response.js +2 -2
- package/dist/source/core/timed-out.d.ts +1 -0
- package/dist/source/core/timed-out.js +2 -3
- package/dist/source/core/utils/get-body-size.js +4 -2
- package/dist/source/core/utils/is-unix-socket-url.d.ts +16 -0
- package/dist/source/core/utils/is-unix-socket-url.js +21 -0
- package/dist/source/core/utils/weakable-map.d.ts +0 -1
- package/dist/source/core/utils/weakable-map.js +2 -6
- package/dist/source/create.js +9 -1
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +1 -0
- package/package.json +10 -8
- package/readme.md +1 -0
|
@@ -11,11 +11,43 @@ import http2wrapper from 'http2-wrapper';
|
|
|
11
11
|
import { isFormData } from 'form-data-encoder';
|
|
12
12
|
import parseLinkHeader from './parse-link-header.js';
|
|
13
13
|
const [major, minor] = process.versions.node.split('.').map(Number);
|
|
14
|
+
/**
|
|
15
|
+
Generic helper that wraps any assertion function to add context to error messages.
|
|
16
|
+
*/
|
|
17
|
+
function wrapAssertionWithContext(optionName, assertionFn) {
|
|
18
|
+
try {
|
|
19
|
+
assertionFn();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof Error) {
|
|
23
|
+
error.message = `Option '${optionName}': ${error.message}`;
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
Helper function that wraps assert.any() to provide better error messages.
|
|
30
|
+
When assertion fails, it includes the option name in the error message.
|
|
31
|
+
*/
|
|
32
|
+
function assertAny(optionName, validators, value) {
|
|
33
|
+
wrapAssertionWithContext(optionName, () => {
|
|
34
|
+
assert.any(validators, value);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
Helper function that wraps assert.plainObject() to provide better error messages.
|
|
39
|
+
When assertion fails, it includes the option name in the error message.
|
|
40
|
+
*/
|
|
41
|
+
function assertPlainObject(optionName, value) {
|
|
42
|
+
wrapAssertionWithContext(optionName, () => {
|
|
43
|
+
assert.plainObject(value);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
14
46
|
function validateSearchParameters(searchParameters) {
|
|
15
47
|
// eslint-disable-next-line guard-for-in
|
|
16
48
|
for (const key in searchParameters) {
|
|
17
49
|
const value = searchParameters[key];
|
|
18
|
-
|
|
50
|
+
assertAny(`searchParams.${key}`, [is.string, is.number, is.boolean, is.null, is.undefined], value);
|
|
19
51
|
}
|
|
20
52
|
}
|
|
21
53
|
const globalCache = new Map();
|
|
@@ -95,6 +127,7 @@ const defaultInternals = {
|
|
|
95
127
|
beforeError: [],
|
|
96
128
|
beforeRedirect: [],
|
|
97
129
|
beforeRetry: [],
|
|
130
|
+
beforeCache: [],
|
|
98
131
|
afterResponse: [],
|
|
99
132
|
},
|
|
100
133
|
followRedirect: true,
|
|
@@ -105,6 +138,7 @@ const defaultInternals = {
|
|
|
105
138
|
password: '',
|
|
106
139
|
http2: false,
|
|
107
140
|
allowGetBody: false,
|
|
141
|
+
copyPipedHeaders: true,
|
|
108
142
|
headers: {
|
|
109
143
|
'user-agent': 'got (https://github.com/sindresorhus/got)',
|
|
110
144
|
},
|
|
@@ -179,6 +213,7 @@ const defaultInternals = {
|
|
|
179
213
|
dhparam: undefined,
|
|
180
214
|
ecdhCurve: undefined,
|
|
181
215
|
certificateRevocationLists: undefined,
|
|
216
|
+
secureOptions: undefined,
|
|
182
217
|
},
|
|
183
218
|
encoding: undefined,
|
|
184
219
|
resolveBodyOnly: false,
|
|
@@ -217,6 +252,7 @@ const defaultInternals = {
|
|
|
217
252
|
maxHeaderSize: undefined,
|
|
218
253
|
signal: undefined,
|
|
219
254
|
enableUnixSockets: false,
|
|
255
|
+
strictContentLength: false,
|
|
220
256
|
};
|
|
221
257
|
const cloneInternals = (internals) => {
|
|
222
258
|
const { hooks, retry } = internals;
|
|
@@ -240,14 +276,12 @@ const cloneInternals = (internals) => {
|
|
|
240
276
|
beforeError: [...hooks.beforeError],
|
|
241
277
|
beforeRedirect: [...hooks.beforeRedirect],
|
|
242
278
|
beforeRetry: [...hooks.beforeRetry],
|
|
279
|
+
beforeCache: [...hooks.beforeCache],
|
|
243
280
|
afterResponse: [...hooks.afterResponse],
|
|
244
281
|
},
|
|
245
282
|
searchParams: internals.searchParams ? new URLSearchParams(internals.searchParams) : undefined,
|
|
246
283
|
pagination: { ...internals.pagination },
|
|
247
284
|
};
|
|
248
|
-
if (result.url !== undefined) {
|
|
249
|
-
result.prefixUrl = '';
|
|
250
|
-
}
|
|
251
285
|
return result;
|
|
252
286
|
};
|
|
253
287
|
const cloneRaw = (raw) => {
|
|
@@ -305,11 +339,24 @@ const cloneRaw = (raw) => {
|
|
|
305
339
|
if (is.array(hooks.beforeRetry)) {
|
|
306
340
|
result.hooks.beforeRetry = [...hooks.beforeRetry];
|
|
307
341
|
}
|
|
342
|
+
if (is.array(hooks.beforeCache)) {
|
|
343
|
+
result.hooks.beforeCache = [...hooks.beforeCache];
|
|
344
|
+
}
|
|
308
345
|
if (is.array(hooks.afterResponse)) {
|
|
309
346
|
result.hooks.afterResponse = [...hooks.afterResponse];
|
|
310
347
|
}
|
|
311
348
|
}
|
|
312
|
-
|
|
349
|
+
if (raw.searchParams) {
|
|
350
|
+
if (is.string(raw.searchParams)) {
|
|
351
|
+
result.searchParams = raw.searchParams;
|
|
352
|
+
}
|
|
353
|
+
else if (raw.searchParams instanceof URLSearchParams) {
|
|
354
|
+
result.searchParams = new URLSearchParams(raw.searchParams);
|
|
355
|
+
}
|
|
356
|
+
else if (is.object(raw.searchParams)) {
|
|
357
|
+
result.searchParams = { ...raw.searchParams };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
313
360
|
if (is.object(raw.pagination)) {
|
|
314
361
|
result.pagination = { ...raw.pagination };
|
|
315
362
|
}
|
|
@@ -333,19 +380,17 @@ const init = (options, withOptions, self) => {
|
|
|
333
380
|
export default class Options {
|
|
334
381
|
_unixOptions;
|
|
335
382
|
_internals;
|
|
336
|
-
_merging;
|
|
383
|
+
_merging = false;
|
|
337
384
|
_init;
|
|
338
385
|
constructor(input, options, defaults) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
386
|
+
assertAny('input', [is.string, is.urlInstance, is.object, is.undefined], input);
|
|
387
|
+
assertAny('options', [is.object, is.undefined], options);
|
|
388
|
+
assertAny('defaults', [is.object, is.undefined], defaults);
|
|
342
389
|
if (input instanceof Options || options instanceof Options) {
|
|
343
390
|
throw new TypeError('The defaults must be passed as the third argument');
|
|
344
391
|
}
|
|
345
392
|
this._internals = cloneInternals(defaults?._internals ?? defaults ?? defaultInternals);
|
|
346
393
|
this._init = [...(defaults?._init ?? [])];
|
|
347
|
-
this._merging = false;
|
|
348
|
-
this._unixOptions = undefined;
|
|
349
394
|
// This rule allows `finally` to be considered more important.
|
|
350
395
|
// Meaning no matter the error thrown in the `try` block,
|
|
351
396
|
// if `finally` throws then the `finally` error will be thrown.
|
|
@@ -456,7 +501,7 @@ export default class Options {
|
|
|
456
501
|
return this._internals.request;
|
|
457
502
|
}
|
|
458
503
|
set request(value) {
|
|
459
|
-
|
|
504
|
+
assertAny('request', [is.function, is.undefined], value);
|
|
460
505
|
this._internals.request = value;
|
|
461
506
|
}
|
|
462
507
|
/**
|
|
@@ -485,14 +530,14 @@ export default class Options {
|
|
|
485
530
|
return this._internals.agent;
|
|
486
531
|
}
|
|
487
532
|
set agent(value) {
|
|
488
|
-
|
|
533
|
+
assertPlainObject('agent', value);
|
|
489
534
|
// eslint-disable-next-line guard-for-in
|
|
490
535
|
for (const key in value) {
|
|
491
536
|
if (!(key in this._internals.agent)) {
|
|
492
537
|
throw new TypeError(`Unexpected agent option: ${key}`);
|
|
493
538
|
}
|
|
494
539
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
495
|
-
|
|
540
|
+
assertAny(`agent.${key}`, [is.object, is.undefined, (v) => v === false], value[key]);
|
|
496
541
|
}
|
|
497
542
|
if (this._merging) {
|
|
498
543
|
Object.assign(this._internals.agent, value);
|
|
@@ -545,14 +590,14 @@ export default class Options {
|
|
|
545
590
|
return this._internals.timeout;
|
|
546
591
|
}
|
|
547
592
|
set timeout(value) {
|
|
548
|
-
|
|
593
|
+
assertPlainObject('timeout', value);
|
|
549
594
|
// eslint-disable-next-line guard-for-in
|
|
550
595
|
for (const key in value) {
|
|
551
596
|
if (!(key in this._internals.timeout)) {
|
|
552
597
|
throw new Error(`Unexpected timeout option: ${key}`);
|
|
553
598
|
}
|
|
554
599
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
555
|
-
|
|
600
|
+
assertAny(`timeout.${key}`, [is.number, is.undefined], value[key]);
|
|
556
601
|
}
|
|
557
602
|
if (this._merging) {
|
|
558
603
|
Object.assign(this._internals.timeout, value);
|
|
@@ -606,7 +651,7 @@ export default class Options {
|
|
|
606
651
|
return this._internals.prefixUrl;
|
|
607
652
|
}
|
|
608
653
|
set prefixUrl(value) {
|
|
609
|
-
|
|
654
|
+
assertAny('prefixUrl', [is.string, is.urlInstance], value);
|
|
610
655
|
if (value === '') {
|
|
611
656
|
this._internals.prefixUrl = '';
|
|
612
657
|
return;
|
|
@@ -630,7 +675,7 @@ export default class Options {
|
|
|
630
675
|
|
|
631
676
|
__Note #4__: This option is not enumerable and will not be merged with the instance defaults.
|
|
632
677
|
|
|
633
|
-
The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
|
|
678
|
+
The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / typed array ([`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), etc.) / [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
|
|
634
679
|
|
|
635
680
|
Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`.
|
|
636
681
|
|
|
@@ -655,7 +700,7 @@ export default class Options {
|
|
|
655
700
|
return this._internals.body;
|
|
656
701
|
}
|
|
657
702
|
set body(value) {
|
|
658
|
-
|
|
703
|
+
assertAny('body', [is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, is.iterable, is.asyncIterable, isFormData, is.typedArray, is.undefined], value);
|
|
659
704
|
if (is.nodeStream(value)) {
|
|
660
705
|
assert.truthy(value.readable);
|
|
661
706
|
}
|
|
@@ -678,7 +723,7 @@ export default class Options {
|
|
|
678
723
|
return this._internals.form;
|
|
679
724
|
}
|
|
680
725
|
set form(value) {
|
|
681
|
-
|
|
726
|
+
assertAny('form', [is.plainObject, is.undefined], value);
|
|
682
727
|
if (value !== undefined) {
|
|
683
728
|
assert.undefined(this._internals.body);
|
|
684
729
|
assert.undefined(this._internals.json);
|
|
@@ -686,7 +731,9 @@ export default class Options {
|
|
|
686
731
|
this._internals.form = value;
|
|
687
732
|
}
|
|
688
733
|
/**
|
|
689
|
-
JSON body. If the `
|
|
734
|
+
JSON request body. If the `content-type` header is not set, it will be set to `application/json`.
|
|
735
|
+
|
|
736
|
+
__Important__: This option only affects the request body you send to the server. To parse the response as JSON, you must either call `.json()` on the promise or set `responseType: 'json'` in the options.
|
|
690
737
|
|
|
691
738
|
__Note #1__: If you provide this option, `got.stream()` will be read-only.
|
|
692
739
|
|
|
@@ -724,7 +771,7 @@ export default class Options {
|
|
|
724
771
|
return this._internals.url;
|
|
725
772
|
}
|
|
726
773
|
set url(value) {
|
|
727
|
-
|
|
774
|
+
assertAny('url', [is.string, is.urlInstance, is.undefined], value);
|
|
728
775
|
if (value === undefined) {
|
|
729
776
|
this._internals.url = undefined;
|
|
730
777
|
return;
|
|
@@ -732,7 +779,11 @@ export default class Options {
|
|
|
732
779
|
if (is.string(value) && value.startsWith('/')) {
|
|
733
780
|
throw new Error('`url` must not start with a slash');
|
|
734
781
|
}
|
|
735
|
-
|
|
782
|
+
// Detect if URL is already absolute (has a protocol/scheme)
|
|
783
|
+
const valueString = value.toString();
|
|
784
|
+
const isAbsolute = is.urlInstance(value) || /^[a-z][a-z\d+.-]*:/i.test(valueString);
|
|
785
|
+
// Only concatenate prefixUrl if the URL is relative
|
|
786
|
+
const urlString = isAbsolute ? valueString : `${this.prefixUrl}${valueString}`;
|
|
736
787
|
const url = new URL(urlString);
|
|
737
788
|
this._internals.url = url;
|
|
738
789
|
if (url.protocol === 'unix:') {
|
|
@@ -784,7 +835,7 @@ export default class Options {
|
|
|
784
835
|
return this._internals.cookieJar;
|
|
785
836
|
}
|
|
786
837
|
set cookieJar(value) {
|
|
787
|
-
|
|
838
|
+
assertAny('cookieJar', [is.object, is.undefined], value);
|
|
788
839
|
if (value === undefined) {
|
|
789
840
|
this._internals.cookieJar = undefined;
|
|
790
841
|
return;
|
|
@@ -871,7 +922,7 @@ export default class Options {
|
|
|
871
922
|
return this._internals.searchParams;
|
|
872
923
|
}
|
|
873
924
|
set searchParams(value) {
|
|
874
|
-
|
|
925
|
+
assertAny('searchParams', [is.string, is.object, is.undefined], value);
|
|
875
926
|
const url = this._internals.url;
|
|
876
927
|
if (value === undefined) {
|
|
877
928
|
this._internals.searchParams = undefined;
|
|
@@ -931,7 +982,7 @@ export default class Options {
|
|
|
931
982
|
return this._internals.dnsLookup;
|
|
932
983
|
}
|
|
933
984
|
set dnsLookup(value) {
|
|
934
|
-
|
|
985
|
+
assertAny('dnsLookup', [is.function, is.undefined], value);
|
|
935
986
|
this._internals.dnsLookup = value;
|
|
936
987
|
}
|
|
937
988
|
/**
|
|
@@ -948,7 +999,7 @@ export default class Options {
|
|
|
948
999
|
return this._internals.dnsCache;
|
|
949
1000
|
}
|
|
950
1001
|
set dnsCache(value) {
|
|
951
|
-
|
|
1002
|
+
assertAny('dnsCache', [is.object, is.boolean, is.undefined], value);
|
|
952
1003
|
if (value === true) {
|
|
953
1004
|
this._internals.dnsCache = getGlobalDnsCache();
|
|
954
1005
|
}
|
|
@@ -1018,7 +1069,7 @@ export default class Options {
|
|
|
1018
1069
|
}
|
|
1019
1070
|
const typedKnownHookEvent = knownHookEvent;
|
|
1020
1071
|
const hooks = value[typedKnownHookEvent];
|
|
1021
|
-
|
|
1072
|
+
assertAny(`hooks.${knownHookEvent}`, [is.array, is.undefined], hooks);
|
|
1022
1073
|
if (hooks) {
|
|
1023
1074
|
for (const hook of hooks) {
|
|
1024
1075
|
assert.function(hook);
|
|
@@ -1053,7 +1104,7 @@ export default class Options {
|
|
|
1053
1104
|
return this._internals.followRedirect;
|
|
1054
1105
|
}
|
|
1055
1106
|
set followRedirect(value) {
|
|
1056
|
-
|
|
1107
|
+
assertAny('followRedirect', [is.boolean, is.function], value);
|
|
1057
1108
|
this._internals.followRedirect = value;
|
|
1058
1109
|
}
|
|
1059
1110
|
get followRedirects() {
|
|
@@ -1083,7 +1134,7 @@ export default class Options {
|
|
|
1083
1134
|
return this._internals.cache;
|
|
1084
1135
|
}
|
|
1085
1136
|
set cache(value) {
|
|
1086
|
-
|
|
1137
|
+
assertAny('cache', [is.object, is.string, is.boolean, is.undefined], value);
|
|
1087
1138
|
if (value === true) {
|
|
1088
1139
|
this._internals.cache = globalCache;
|
|
1089
1140
|
}
|
|
@@ -1186,6 +1237,62 @@ export default class Options {
|
|
|
1186
1237
|
this._internals.allowGetBody = value;
|
|
1187
1238
|
}
|
|
1188
1239
|
/**
|
|
1240
|
+
Automatically copy headers from piped streams.
|
|
1241
|
+
|
|
1242
|
+
When piping a request into a Got stream (e.g., `request.pipe(got.stream(url))`), this controls whether headers from the source stream are automatically merged into the Got request headers.
|
|
1243
|
+
|
|
1244
|
+
Note: Piped headers overwrite any explicitly set headers with the same name. To override this, either set `copyPipedHeaders` to `false` and manually copy safe headers, or use a `beforeRequest` hook to force specific header values after piping.
|
|
1245
|
+
|
|
1246
|
+
Useful for proxy scenarios, but you may want to disable this to filter out headers like `Host`, `Connection`, `Authorization`, etc.
|
|
1247
|
+
|
|
1248
|
+
@default true
|
|
1249
|
+
|
|
1250
|
+
@example
|
|
1251
|
+
```
|
|
1252
|
+
import got from 'got';
|
|
1253
|
+
import {pipeline} from 'node:stream/promises';
|
|
1254
|
+
|
|
1255
|
+
// Disable automatic header copying and manually copy only safe headers
|
|
1256
|
+
server.get('/proxy', async (request, response) => {
|
|
1257
|
+
const gotStream = got.stream('https://example.com', {
|
|
1258
|
+
copyPipedHeaders: false,
|
|
1259
|
+
headers: {
|
|
1260
|
+
'user-agent': request.headers['user-agent'],
|
|
1261
|
+
'accept': request.headers['accept'],
|
|
1262
|
+
// Explicitly NOT copying host, connection, authorization, etc.
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
await pipeline(request, gotStream, response);
|
|
1267
|
+
});
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
@example
|
|
1271
|
+
```
|
|
1272
|
+
import got from 'got';
|
|
1273
|
+
|
|
1274
|
+
// Override piped headers using beforeRequest hook
|
|
1275
|
+
const gotStream = got.stream('https://example.com', {
|
|
1276
|
+
hooks: {
|
|
1277
|
+
beforeRequest: [
|
|
1278
|
+
options => {
|
|
1279
|
+
// Force specific header values after piping
|
|
1280
|
+
options.headers.host = 'example.com';
|
|
1281
|
+
delete options.headers.authorization;
|
|
1282
|
+
}
|
|
1283
|
+
]
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
```
|
|
1287
|
+
*/
|
|
1288
|
+
get copyPipedHeaders() {
|
|
1289
|
+
return this._internals.copyPipedHeaders;
|
|
1290
|
+
}
|
|
1291
|
+
set copyPipedHeaders(value) {
|
|
1292
|
+
assert.boolean(value);
|
|
1293
|
+
this._internals.copyPipedHeaders = value;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1189
1296
|
Request headers.
|
|
1190
1297
|
|
|
1191
1298
|
Existing headers will be overwritten. Headers set to `undefined` will be omitted.
|
|
@@ -1196,7 +1303,7 @@ export default class Options {
|
|
|
1196
1303
|
return this._internals.headers;
|
|
1197
1304
|
}
|
|
1198
1305
|
set headers(value) {
|
|
1199
|
-
|
|
1306
|
+
assertPlainObject('headers', value);
|
|
1200
1307
|
if (this._merging) {
|
|
1201
1308
|
Object.assign(this._internals.headers, lowercaseKeys(value));
|
|
1202
1309
|
}
|
|
@@ -1340,15 +1447,15 @@ export default class Options {
|
|
|
1340
1447
|
return this._internals.retry;
|
|
1341
1448
|
}
|
|
1342
1449
|
set retry(value) {
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1450
|
+
assertPlainObject('retry', value);
|
|
1451
|
+
assertAny('retry.calculateDelay', [is.function, is.undefined], value.calculateDelay);
|
|
1452
|
+
assertAny('retry.maxRetryAfter', [is.number, is.undefined], value.maxRetryAfter);
|
|
1453
|
+
assertAny('retry.limit', [is.number, is.undefined], value.limit);
|
|
1454
|
+
assertAny('retry.methods', [is.array, is.undefined], value.methods);
|
|
1455
|
+
assertAny('retry.statusCodes', [is.array, is.undefined], value.statusCodes);
|
|
1456
|
+
assertAny('retry.errorCodes', [is.array, is.undefined], value.errorCodes);
|
|
1457
|
+
assertAny('retry.noise', [is.number, is.undefined], value.noise);
|
|
1458
|
+
assertAny('retry.enforceRetryRules', [is.boolean, is.undefined], value.enforceRetryRules);
|
|
1352
1459
|
if (value.noise && Math.abs(value.noise) > 100) {
|
|
1353
1460
|
throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);
|
|
1354
1461
|
}
|
|
@@ -1377,7 +1484,7 @@ export default class Options {
|
|
|
1377
1484
|
return this._internals.localAddress;
|
|
1378
1485
|
}
|
|
1379
1486
|
set localAddress(value) {
|
|
1380
|
-
|
|
1487
|
+
assertAny('localAddress', [is.string, is.undefined], value);
|
|
1381
1488
|
this._internals.localAddress = value;
|
|
1382
1489
|
}
|
|
1383
1490
|
/**
|
|
@@ -1396,7 +1503,7 @@ export default class Options {
|
|
|
1396
1503
|
return this._internals.createConnection;
|
|
1397
1504
|
}
|
|
1398
1505
|
set createConnection(value) {
|
|
1399
|
-
|
|
1506
|
+
assertAny('createConnection', [is.function, is.undefined], value);
|
|
1400
1507
|
this._internals.createConnection = value;
|
|
1401
1508
|
}
|
|
1402
1509
|
/**
|
|
@@ -1408,11 +1515,11 @@ export default class Options {
|
|
|
1408
1515
|
return this._internals.cacheOptions;
|
|
1409
1516
|
}
|
|
1410
1517
|
set cacheOptions(value) {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1518
|
+
assertPlainObject('cacheOptions', value);
|
|
1519
|
+
assertAny('cacheOptions.shared', [is.boolean, is.undefined], value.shared);
|
|
1520
|
+
assertAny('cacheOptions.cacheHeuristic', [is.number, is.undefined], value.cacheHeuristic);
|
|
1521
|
+
assertAny('cacheOptions.immutableMinTimeToLive', [is.number, is.undefined], value.immutableMinTimeToLive);
|
|
1522
|
+
assertAny('cacheOptions.ignoreCargoCult', [is.boolean, is.undefined], value.ignoreCargoCult);
|
|
1416
1523
|
for (const key in value) {
|
|
1417
1524
|
if (!(key in this._internals.cacheOptions)) {
|
|
1418
1525
|
throw new Error(`Cache option \`${key}\` does not exist`);
|
|
@@ -1432,25 +1539,26 @@ export default class Options {
|
|
|
1432
1539
|
return this._internals.https;
|
|
1433
1540
|
}
|
|
1434
1541
|
set https(value) {
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1542
|
+
assertPlainObject('https', value);
|
|
1543
|
+
assertAny('https.rejectUnauthorized', [is.boolean, is.undefined], value.rejectUnauthorized);
|
|
1544
|
+
assertAny('https.checkServerIdentity', [is.function, is.undefined], value.checkServerIdentity);
|
|
1545
|
+
assertAny('https.serverName', [is.string, is.undefined], value.serverName);
|
|
1546
|
+
assertAny('https.certificateAuthority', [is.string, is.object, is.array, is.undefined], value.certificateAuthority);
|
|
1547
|
+
assertAny('https.key', [is.string, is.object, is.array, is.undefined], value.key);
|
|
1548
|
+
assertAny('https.certificate', [is.string, is.object, is.array, is.undefined], value.certificate);
|
|
1549
|
+
assertAny('https.passphrase', [is.string, is.undefined], value.passphrase);
|
|
1550
|
+
assertAny('https.pfx', [is.string, is.buffer, is.array, is.undefined], value.pfx);
|
|
1551
|
+
assertAny('https.alpnProtocols', [is.array, is.undefined], value.alpnProtocols);
|
|
1552
|
+
assertAny('https.ciphers', [is.string, is.undefined], value.ciphers);
|
|
1553
|
+
assertAny('https.dhparam', [is.string, is.buffer, is.undefined], value.dhparam);
|
|
1554
|
+
assertAny('https.signatureAlgorithms', [is.string, is.undefined], value.signatureAlgorithms);
|
|
1555
|
+
assertAny('https.minVersion', [is.string, is.undefined], value.minVersion);
|
|
1556
|
+
assertAny('https.maxVersion', [is.string, is.undefined], value.maxVersion);
|
|
1557
|
+
assertAny('https.honorCipherOrder', [is.boolean, is.undefined], value.honorCipherOrder);
|
|
1558
|
+
assertAny('https.tlsSessionLifetime', [is.number, is.undefined], value.tlsSessionLifetime);
|
|
1559
|
+
assertAny('https.ecdhCurve', [is.string, is.undefined], value.ecdhCurve);
|
|
1560
|
+
assertAny('https.certificateRevocationLists', [is.string, is.buffer, is.array, is.undefined], value.certificateRevocationLists);
|
|
1561
|
+
assertAny('https.secureOptions', [is.number, is.undefined], value.secureOptions);
|
|
1454
1562
|
for (const key in value) {
|
|
1455
1563
|
if (!(key in this._internals.https)) {
|
|
1456
1564
|
throw new Error(`HTTPS option \`${key}\` does not exist`);
|
|
@@ -1480,7 +1588,7 @@ export default class Options {
|
|
|
1480
1588
|
if (value === null) {
|
|
1481
1589
|
throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead');
|
|
1482
1590
|
}
|
|
1483
|
-
|
|
1591
|
+
assertAny('encoding', [is.string, is.undefined], value);
|
|
1484
1592
|
this._internals.encoding = value;
|
|
1485
1593
|
}
|
|
1486
1594
|
/**
|
|
@@ -1580,7 +1688,7 @@ export default class Options {
|
|
|
1580
1688
|
return this._internals.maxHeaderSize;
|
|
1581
1689
|
}
|
|
1582
1690
|
set maxHeaderSize(value) {
|
|
1583
|
-
|
|
1691
|
+
assertAny('maxHeaderSize', [is.number, is.undefined], value);
|
|
1584
1692
|
this._internals.maxHeaderSize = value;
|
|
1585
1693
|
}
|
|
1586
1694
|
get enableUnixSockets() {
|
|
@@ -1590,6 +1698,23 @@ export default class Options {
|
|
|
1590
1698
|
assert.boolean(value);
|
|
1591
1699
|
this._internals.enableUnixSockets = value;
|
|
1592
1700
|
}
|
|
1701
|
+
/**
|
|
1702
|
+
Throw an error if the server response's `content-length` header value doesn't match the number of bytes received.
|
|
1703
|
+
|
|
1704
|
+
This is useful for detecting truncated responses and follows RFC 9112 requirements for message completeness.
|
|
1705
|
+
|
|
1706
|
+
__Note__: Responses without a `content-length` header are not validated.
|
|
1707
|
+
__Note__: When enabled and validation fails, a `ReadError` with code `ERR_HTTP_CONTENT_LENGTH_MISMATCH` will be thrown.
|
|
1708
|
+
|
|
1709
|
+
@default false
|
|
1710
|
+
*/
|
|
1711
|
+
get strictContentLength() {
|
|
1712
|
+
return this._internals.strictContentLength;
|
|
1713
|
+
}
|
|
1714
|
+
set strictContentLength(value) {
|
|
1715
|
+
assert.boolean(value);
|
|
1716
|
+
this._internals.strictContentLength = value;
|
|
1717
|
+
}
|
|
1593
1718
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1594
1719
|
toJSON() {
|
|
1595
1720
|
return { ...this._internals };
|
|
@@ -1648,6 +1773,7 @@ export default class Options {
|
|
|
1648
1773
|
dhparam: https.dhparam,
|
|
1649
1774
|
ecdhCurve: https.ecdhCurve,
|
|
1650
1775
|
crl: https.certificateRevocationLists,
|
|
1776
|
+
secureOptions: https.secureOptions,
|
|
1651
1777
|
// HTTP options
|
|
1652
1778
|
lookup: internals.dnsLookup ?? internals.dnsCache?.lookup,
|
|
1653
1779
|
family: internals.dnsLookupIpVersion,
|
|
@@ -101,6 +101,8 @@ An error to be thrown when server response code is 2xx, and parsing body fails.
|
|
|
101
101
|
Includes a `response` property.
|
|
102
102
|
*/
|
|
103
103
|
export declare class ParseError extends RequestError {
|
|
104
|
+
name: string;
|
|
105
|
+
code: string;
|
|
104
106
|
readonly response: Response;
|
|
105
107
|
constructor(error: Error, response: Response);
|
|
106
108
|
}
|
|
@@ -11,11 +11,11 @@ An error to be thrown when server response code is 2xx, and parsing body fails.
|
|
|
11
11
|
Includes a `response` property.
|
|
12
12
|
*/
|
|
13
13
|
export class ParseError extends RequestError {
|
|
14
|
+
name = 'ParseError';
|
|
15
|
+
code = 'ERR_BODY_PARSE_FAILURE';
|
|
14
16
|
constructor(error, response) {
|
|
15
17
|
const { options } = response.request;
|
|
16
18
|
super(`${error.message} in "${options.url.toString()}"`, error, response.request);
|
|
17
|
-
this.name = 'ParseError';
|
|
18
|
-
this.code = 'ERR_BODY_PARSE_FAILURE';
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
export const parseBody = (response, responseType, parseJson, encoding) => {
|
|
@@ -18,6 +18,7 @@ export type Delays = {
|
|
|
18
18
|
export type ErrorCode = 'ETIMEDOUT' | 'ECONNRESET' | 'EADDRINUSE' | 'ECONNREFUSED' | 'EPIPE' | 'ENOTFOUND' | 'ENETUNREACH' | 'EAI_AGAIN';
|
|
19
19
|
export declare class TimeoutError extends Error {
|
|
20
20
|
event: string;
|
|
21
|
+
name: string;
|
|
21
22
|
code: ErrorCode;
|
|
22
23
|
constructor(threshold: number, event: string);
|
|
23
24
|
}
|
|
@@ -4,12 +4,11 @@ const reentry = Symbol('reentry');
|
|
|
4
4
|
const noop = () => { };
|
|
5
5
|
export class TimeoutError extends Error {
|
|
6
6
|
event;
|
|
7
|
-
|
|
7
|
+
name = 'TimeoutError';
|
|
8
|
+
code = 'ETIMEDOUT';
|
|
8
9
|
constructor(threshold, event) {
|
|
9
10
|
super(`Timeout awaiting '${event}' for ${threshold}ms`);
|
|
10
11
|
this.event = event;
|
|
11
|
-
this.name = 'TimeoutError';
|
|
12
|
-
this.code = 'ETIMEDOUT';
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
14
|
export default function timedOut(request, delays, options) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer';
|
|
2
1
|
import { promisify } from 'node:util';
|
|
3
2
|
import is from '@sindresorhus/is';
|
|
4
3
|
import isFormData from './is-form-data.js';
|
|
@@ -10,11 +9,14 @@ export default async function getBodySize(body, headers) {
|
|
|
10
9
|
return 0;
|
|
11
10
|
}
|
|
12
11
|
if (is.string(body)) {
|
|
13
|
-
return
|
|
12
|
+
return new TextEncoder().encode(body).byteLength;
|
|
14
13
|
}
|
|
15
14
|
if (is.buffer(body)) {
|
|
16
15
|
return body.length;
|
|
17
16
|
}
|
|
17
|
+
if (is.typedArray(body)) {
|
|
18
|
+
return body.byteLength;
|
|
19
|
+
}
|
|
18
20
|
if (isFormData(body)) {
|
|
19
21
|
try {
|
|
20
22
|
return await promisify(body.getLength.bind(body))();
|
|
@@ -1 +1,17 @@
|
|
|
1
1
|
export default function isUnixSocketURL(url: URL): boolean;
|
|
2
|
+
/**
|
|
3
|
+
Extract the socket path from a UNIX socket URL.
|
|
4
|
+
|
|
5
|
+
@example
|
|
6
|
+
```
|
|
7
|
+
getUnixSocketPath(new URL('http://unix/foo:/path'));
|
|
8
|
+
//=> '/foo'
|
|
9
|
+
|
|
10
|
+
getUnixSocketPath(new URL('unix:/foo:/path'));
|
|
11
|
+
//=> '/foo'
|
|
12
|
+
|
|
13
|
+
getUnixSocketPath(new URL('http://example.com'));
|
|
14
|
+
//=> undefined
|
|
15
|
+
```
|
|
16
|
+
*/
|
|
17
|
+
export declare function getUnixSocketPath(url: URL): string | undefined;
|
|
@@ -2,3 +2,24 @@
|
|
|
2
2
|
export default function isUnixSocketURL(url) {
|
|
3
3
|
return url.protocol === 'unix:' || url.hostname === 'unix';
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
Extract the socket path from a UNIX socket URL.
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```
|
|
10
|
+
getUnixSocketPath(new URL('http://unix/foo:/path'));
|
|
11
|
+
//=> '/foo'
|
|
12
|
+
|
|
13
|
+
getUnixSocketPath(new URL('unix:/foo:/path'));
|
|
14
|
+
//=> '/foo'
|
|
15
|
+
|
|
16
|
+
getUnixSocketPath(new URL('http://example.com'));
|
|
17
|
+
//=> undefined
|
|
18
|
+
```
|
|
19
|
+
*/
|
|
20
|
+
export function getUnixSocketPath(url) {
|
|
21
|
+
if (!isUnixSocketURL(url)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`)?.groups?.socketPath;
|
|
25
|
+
}
|