got 14.4.9 → 14.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.js +35 -3
- package/dist/source/core/index.d.ts +6 -4
- package/dist/source/core/index.js +213 -44
- package/dist/source/core/options.d.ts +184 -15
- package/dist/source/core/options.js +188 -61
- package/dist/source/core/utils/get-body-size.js +17 -1
- 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/create.js +9 -1
- package/package.json +13 -10
- 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();
|
|
@@ -27,6 +59,39 @@ const getGlobalDnsCache = () => {
|
|
|
27
59
|
globalDnsCache = new CacheableLookup();
|
|
28
60
|
return globalDnsCache;
|
|
29
61
|
};
|
|
62
|
+
// Detects and wraps QuickLRU v7+ instances to make them compatible with the StorageAdapter interface
|
|
63
|
+
const wrapQuickLruIfNeeded = (value) => {
|
|
64
|
+
// Check if this is QuickLRU v7+ using Symbol.toStringTag and the evict method (added in v7)
|
|
65
|
+
if (value?.[Symbol.toStringTag] === 'QuickLRU' && typeof value.evict === 'function') {
|
|
66
|
+
// QuickLRU v7+ uses set(key, value, {maxAge: number}) but StorageAdapter expects set(key, value, ttl)
|
|
67
|
+
// Wrap it to translate the interface
|
|
68
|
+
return {
|
|
69
|
+
get(key) {
|
|
70
|
+
return value.get(key);
|
|
71
|
+
},
|
|
72
|
+
set(key, cacheValue, ttl) {
|
|
73
|
+
if (ttl === undefined) {
|
|
74
|
+
value.set(key, cacheValue);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
value.set(key, cacheValue, { maxAge: ttl });
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
},
|
|
81
|
+
delete(key) {
|
|
82
|
+
return value.delete(key);
|
|
83
|
+
},
|
|
84
|
+
clear() {
|
|
85
|
+
return value.clear();
|
|
86
|
+
},
|
|
87
|
+
has(key) {
|
|
88
|
+
return value.has(key);
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// QuickLRU v5 and other caches work as-is
|
|
93
|
+
return value;
|
|
94
|
+
};
|
|
30
95
|
const defaultInternals = {
|
|
31
96
|
request: undefined,
|
|
32
97
|
agent: {
|
|
@@ -115,6 +180,8 @@ const defaultInternals = {
|
|
|
115
180
|
calculateDelay: ({ computedValue }) => computedValue,
|
|
116
181
|
backoffLimit: Number.POSITIVE_INFINITY,
|
|
117
182
|
noise: 100,
|
|
183
|
+
// TODO: Change default to `true` in the next major version to fix https://github.com/sindresorhus/got/issues/2243
|
|
184
|
+
enforceRetryRules: false,
|
|
118
185
|
},
|
|
119
186
|
localAddress: undefined,
|
|
120
187
|
method: 'GET',
|
|
@@ -129,6 +196,7 @@ const defaultInternals = {
|
|
|
129
196
|
alpnProtocols: undefined,
|
|
130
197
|
rejectUnauthorized: undefined,
|
|
131
198
|
checkServerIdentity: undefined,
|
|
199
|
+
serverName: undefined,
|
|
132
200
|
certificateAuthority: undefined,
|
|
133
201
|
key: undefined,
|
|
134
202
|
certificate: undefined,
|
|
@@ -143,6 +211,7 @@ const defaultInternals = {
|
|
|
143
211
|
dhparam: undefined,
|
|
144
212
|
ecdhCurve: undefined,
|
|
145
213
|
certificateRevocationLists: undefined,
|
|
214
|
+
secureOptions: undefined,
|
|
146
215
|
},
|
|
147
216
|
encoding: undefined,
|
|
148
217
|
resolveBodyOnly: false,
|
|
@@ -181,6 +250,7 @@ const defaultInternals = {
|
|
|
181
250
|
maxHeaderSize: undefined,
|
|
182
251
|
signal: undefined,
|
|
183
252
|
enableUnixSockets: false,
|
|
253
|
+
strictContentLength: false,
|
|
184
254
|
};
|
|
185
255
|
const cloneInternals = (internals) => {
|
|
186
256
|
const { hooks, retry } = internals;
|
|
@@ -300,9 +370,9 @@ export default class Options {
|
|
|
300
370
|
_merging;
|
|
301
371
|
_init;
|
|
302
372
|
constructor(input, options, defaults) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
373
|
+
assertAny('input', [is.string, is.urlInstance, is.object, is.undefined], input);
|
|
374
|
+
assertAny('options', [is.object, is.undefined], options);
|
|
375
|
+
assertAny('defaults', [is.object, is.undefined], defaults);
|
|
306
376
|
if (input instanceof Options || options instanceof Options) {
|
|
307
377
|
throw new TypeError('The defaults must be passed as the third argument');
|
|
308
378
|
}
|
|
@@ -386,6 +456,10 @@ export default class Options {
|
|
|
386
456
|
if (key === 'url') {
|
|
387
457
|
continue;
|
|
388
458
|
}
|
|
459
|
+
// Never merge `preserveHooks` - it's a control flag, not a persistent option
|
|
460
|
+
if (key === 'preserveHooks') {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
389
463
|
if (!(key in this)) {
|
|
390
464
|
throw new Error(`Unexpected option: ${key}`);
|
|
391
465
|
}
|
|
@@ -416,7 +490,7 @@ export default class Options {
|
|
|
416
490
|
return this._internals.request;
|
|
417
491
|
}
|
|
418
492
|
set request(value) {
|
|
419
|
-
|
|
493
|
+
assertAny('request', [is.function, is.undefined], value);
|
|
420
494
|
this._internals.request = value;
|
|
421
495
|
}
|
|
422
496
|
/**
|
|
@@ -445,14 +519,14 @@ export default class Options {
|
|
|
445
519
|
return this._internals.agent;
|
|
446
520
|
}
|
|
447
521
|
set agent(value) {
|
|
448
|
-
|
|
522
|
+
assertPlainObject('agent', value);
|
|
449
523
|
// eslint-disable-next-line guard-for-in
|
|
450
524
|
for (const key in value) {
|
|
451
525
|
if (!(key in this._internals.agent)) {
|
|
452
526
|
throw new TypeError(`Unexpected agent option: ${key}`);
|
|
453
527
|
}
|
|
454
528
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
455
|
-
|
|
529
|
+
assertAny(`agent.${key}`, [is.object, is.undefined, (v) => v === false], value[key]);
|
|
456
530
|
}
|
|
457
531
|
if (this._merging) {
|
|
458
532
|
Object.assign(this._internals.agent, value);
|
|
@@ -505,14 +579,14 @@ export default class Options {
|
|
|
505
579
|
return this._internals.timeout;
|
|
506
580
|
}
|
|
507
581
|
set timeout(value) {
|
|
508
|
-
|
|
582
|
+
assertPlainObject('timeout', value);
|
|
509
583
|
// eslint-disable-next-line guard-for-in
|
|
510
584
|
for (const key in value) {
|
|
511
585
|
if (!(key in this._internals.timeout)) {
|
|
512
586
|
throw new Error(`Unexpected timeout option: ${key}`);
|
|
513
587
|
}
|
|
514
588
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
515
|
-
|
|
589
|
+
assertAny(`timeout.${key}`, [is.number, is.undefined], value[key]);
|
|
516
590
|
}
|
|
517
591
|
if (this._merging) {
|
|
518
592
|
Object.assign(this._internals.timeout, value);
|
|
@@ -566,7 +640,7 @@ export default class Options {
|
|
|
566
640
|
return this._internals.prefixUrl;
|
|
567
641
|
}
|
|
568
642
|
set prefixUrl(value) {
|
|
569
|
-
|
|
643
|
+
assertAny('prefixUrl', [is.string, is.urlInstance], value);
|
|
570
644
|
if (value === '') {
|
|
571
645
|
this._internals.prefixUrl = '';
|
|
572
646
|
return;
|
|
@@ -590,15 +664,32 @@ export default class Options {
|
|
|
590
664
|
|
|
591
665
|
__Note #4__: This option is not enumerable and will not be merged with the instance defaults.
|
|
592
666
|
|
|
593
|
-
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`.
|
|
667
|
+
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`.
|
|
594
668
|
|
|
595
669
|
Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`.
|
|
670
|
+
|
|
671
|
+
You can use `Iterable` and `AsyncIterable` objects as request body, including Web [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream):
|
|
672
|
+
|
|
673
|
+
@example
|
|
674
|
+
```
|
|
675
|
+
import got from 'got';
|
|
676
|
+
|
|
677
|
+
// Using an async generator
|
|
678
|
+
async function* generateData() {
|
|
679
|
+
yield 'Hello, ';
|
|
680
|
+
yield 'world!';
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
await got.post('https://httpbin.org/anything', {
|
|
684
|
+
body: generateData()
|
|
685
|
+
});
|
|
686
|
+
```
|
|
596
687
|
*/
|
|
597
688
|
get body() {
|
|
598
689
|
return this._internals.body;
|
|
599
690
|
}
|
|
600
691
|
set body(value) {
|
|
601
|
-
|
|
692
|
+
assertAny('body', [is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, is.iterable, is.asyncIterable, isFormData, is.typedArray, is.undefined], value);
|
|
602
693
|
if (is.nodeStream(value)) {
|
|
603
694
|
assert.truthy(value.readable);
|
|
604
695
|
}
|
|
@@ -621,7 +712,7 @@ export default class Options {
|
|
|
621
712
|
return this._internals.form;
|
|
622
713
|
}
|
|
623
714
|
set form(value) {
|
|
624
|
-
|
|
715
|
+
assertAny('form', [is.plainObject, is.undefined], value);
|
|
625
716
|
if (value !== undefined) {
|
|
626
717
|
assert.undefined(this._internals.body);
|
|
627
718
|
assert.undefined(this._internals.json);
|
|
@@ -629,7 +720,9 @@ export default class Options {
|
|
|
629
720
|
this._internals.form = value;
|
|
630
721
|
}
|
|
631
722
|
/**
|
|
632
|
-
JSON body. If the `
|
|
723
|
+
JSON request body. If the `content-type` header is not set, it will be set to `application/json`.
|
|
724
|
+
|
|
725
|
+
__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.
|
|
633
726
|
|
|
634
727
|
__Note #1__: If you provide this option, `got.stream()` will be read-only.
|
|
635
728
|
|
|
@@ -667,7 +760,7 @@ export default class Options {
|
|
|
667
760
|
return this._internals.url;
|
|
668
761
|
}
|
|
669
762
|
set url(value) {
|
|
670
|
-
|
|
763
|
+
assertAny('url', [is.string, is.urlInstance, is.undefined], value);
|
|
671
764
|
if (value === undefined) {
|
|
672
765
|
this._internals.url = undefined;
|
|
673
766
|
return;
|
|
@@ -727,7 +820,7 @@ export default class Options {
|
|
|
727
820
|
return this._internals.cookieJar;
|
|
728
821
|
}
|
|
729
822
|
set cookieJar(value) {
|
|
730
|
-
|
|
823
|
+
assertAny('cookieJar', [is.object, is.undefined], value);
|
|
731
824
|
if (value === undefined) {
|
|
732
825
|
this._internals.cookieJar = undefined;
|
|
733
826
|
return;
|
|
@@ -814,7 +907,7 @@ export default class Options {
|
|
|
814
907
|
return this._internals.searchParams;
|
|
815
908
|
}
|
|
816
909
|
set searchParams(value) {
|
|
817
|
-
|
|
910
|
+
assertAny('searchParams', [is.string, is.object, is.undefined], value);
|
|
818
911
|
const url = this._internals.url;
|
|
819
912
|
if (value === undefined) {
|
|
820
913
|
this._internals.searchParams = undefined;
|
|
@@ -874,7 +967,7 @@ export default class Options {
|
|
|
874
967
|
return this._internals.dnsLookup;
|
|
875
968
|
}
|
|
876
969
|
set dnsLookup(value) {
|
|
877
|
-
|
|
970
|
+
assertAny('dnsLookup', [is.function, is.undefined], value);
|
|
878
971
|
this._internals.dnsLookup = value;
|
|
879
972
|
}
|
|
880
973
|
/**
|
|
@@ -891,7 +984,7 @@ export default class Options {
|
|
|
891
984
|
return this._internals.dnsCache;
|
|
892
985
|
}
|
|
893
986
|
set dnsCache(value) {
|
|
894
|
-
|
|
987
|
+
assertAny('dnsCache', [is.object, is.boolean, is.undefined], value);
|
|
895
988
|
if (value === true) {
|
|
896
989
|
this._internals.dnsCache = getGlobalDnsCache();
|
|
897
990
|
}
|
|
@@ -961,7 +1054,7 @@ export default class Options {
|
|
|
961
1054
|
}
|
|
962
1055
|
const typedKnownHookEvent = knownHookEvent;
|
|
963
1056
|
const hooks = value[typedKnownHookEvent];
|
|
964
|
-
|
|
1057
|
+
assertAny(`hooks.${knownHookEvent}`, [is.array, is.undefined], hooks);
|
|
965
1058
|
if (hooks) {
|
|
966
1059
|
for (const hook of hooks) {
|
|
967
1060
|
assert.function(hook);
|
|
@@ -996,7 +1089,7 @@ export default class Options {
|
|
|
996
1089
|
return this._internals.followRedirect;
|
|
997
1090
|
}
|
|
998
1091
|
set followRedirect(value) {
|
|
999
|
-
|
|
1092
|
+
assertAny('followRedirect', [is.boolean, is.function], value);
|
|
1000
1093
|
this._internals.followRedirect = value;
|
|
1001
1094
|
}
|
|
1002
1095
|
get followRedirects() {
|
|
@@ -1026,7 +1119,7 @@ export default class Options {
|
|
|
1026
1119
|
return this._internals.cache;
|
|
1027
1120
|
}
|
|
1028
1121
|
set cache(value) {
|
|
1029
|
-
|
|
1122
|
+
assertAny('cache', [is.object, is.string, is.boolean, is.undefined], value);
|
|
1030
1123
|
if (value === true) {
|
|
1031
1124
|
this._internals.cache = globalCache;
|
|
1032
1125
|
}
|
|
@@ -1034,7 +1127,7 @@ export default class Options {
|
|
|
1034
1127
|
this._internals.cache = undefined;
|
|
1035
1128
|
}
|
|
1036
1129
|
else {
|
|
1037
|
-
this._internals.cache = value;
|
|
1130
|
+
this._internals.cache = wrapQuickLruIfNeeded(value);
|
|
1038
1131
|
}
|
|
1039
1132
|
}
|
|
1040
1133
|
/**
|
|
@@ -1139,7 +1232,7 @@ export default class Options {
|
|
|
1139
1232
|
return this._internals.headers;
|
|
1140
1233
|
}
|
|
1141
1234
|
set headers(value) {
|
|
1142
|
-
|
|
1235
|
+
assertPlainObject('headers', value);
|
|
1143
1236
|
if (this._merging) {
|
|
1144
1237
|
Object.assign(this._internals.headers, lowercaseKeys(value));
|
|
1145
1238
|
}
|
|
@@ -1261,7 +1354,9 @@ export default class Options {
|
|
|
1261
1354
|
The `calculateDelay` property is a `function` that receives an object with `attemptCount`, `retryOptions`, `error` and `computedValue` properties for current retry count, the retry options, error and default computed value.
|
|
1262
1355
|
The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).
|
|
1263
1356
|
|
|
1264
|
-
|
|
1357
|
+
The `enforceRetryRules` property is a `boolean` that, when set to `true`, enforces the `limit`, `methods`, `statusCodes`, and `errorCodes` options before calling `calculateDelay`. Your `calculateDelay` function is only invoked when a retry is allowed based on these criteria. When `false` (default), `calculateDelay` receives the computed value but can override all retry logic.
|
|
1358
|
+
|
|
1359
|
+
__Note:__ When `enforceRetryRules` is `false`, you must check `computedValue` in your `calculateDelay` function to respect the default retry logic. When `true`, the retry rules are enforced automatically.
|
|
1265
1360
|
|
|
1266
1361
|
By default, it retries *only* on the specified methods, status codes, and on these network errors:
|
|
1267
1362
|
|
|
@@ -1281,14 +1376,15 @@ export default class Options {
|
|
|
1281
1376
|
return this._internals.retry;
|
|
1282
1377
|
}
|
|
1283
1378
|
set retry(value) {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1379
|
+
assertPlainObject('retry', value);
|
|
1380
|
+
assertAny('retry.calculateDelay', [is.function, is.undefined], value.calculateDelay);
|
|
1381
|
+
assertAny('retry.maxRetryAfter', [is.number, is.undefined], value.maxRetryAfter);
|
|
1382
|
+
assertAny('retry.limit', [is.number, is.undefined], value.limit);
|
|
1383
|
+
assertAny('retry.methods', [is.array, is.undefined], value.methods);
|
|
1384
|
+
assertAny('retry.statusCodes', [is.array, is.undefined], value.statusCodes);
|
|
1385
|
+
assertAny('retry.errorCodes', [is.array, is.undefined], value.errorCodes);
|
|
1386
|
+
assertAny('retry.noise', [is.number, is.undefined], value.noise);
|
|
1387
|
+
assertAny('retry.enforceRetryRules', [is.boolean, is.undefined], value.enforceRetryRules);
|
|
1292
1388
|
if (value.noise && Math.abs(value.noise) > 100) {
|
|
1293
1389
|
throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);
|
|
1294
1390
|
}
|
|
@@ -1317,7 +1413,7 @@ export default class Options {
|
|
|
1317
1413
|
return this._internals.localAddress;
|
|
1318
1414
|
}
|
|
1319
1415
|
set localAddress(value) {
|
|
1320
|
-
|
|
1416
|
+
assertAny('localAddress', [is.string, is.undefined], value);
|
|
1321
1417
|
this._internals.localAddress = value;
|
|
1322
1418
|
}
|
|
1323
1419
|
/**
|
|
@@ -1336,7 +1432,7 @@ export default class Options {
|
|
|
1336
1432
|
return this._internals.createConnection;
|
|
1337
1433
|
}
|
|
1338
1434
|
set createConnection(value) {
|
|
1339
|
-
|
|
1435
|
+
assertAny('createConnection', [is.function, is.undefined], value);
|
|
1340
1436
|
this._internals.createConnection = value;
|
|
1341
1437
|
}
|
|
1342
1438
|
/**
|
|
@@ -1348,11 +1444,11 @@ export default class Options {
|
|
|
1348
1444
|
return this._internals.cacheOptions;
|
|
1349
1445
|
}
|
|
1350
1446
|
set cacheOptions(value) {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1447
|
+
assertPlainObject('cacheOptions', value);
|
|
1448
|
+
assertAny('cacheOptions.shared', [is.boolean, is.undefined], value.shared);
|
|
1449
|
+
assertAny('cacheOptions.cacheHeuristic', [is.number, is.undefined], value.cacheHeuristic);
|
|
1450
|
+
assertAny('cacheOptions.immutableMinTimeToLive', [is.number, is.undefined], value.immutableMinTimeToLive);
|
|
1451
|
+
assertAny('cacheOptions.ignoreCargoCult', [is.boolean, is.undefined], value.ignoreCargoCult);
|
|
1356
1452
|
for (const key in value) {
|
|
1357
1453
|
if (!(key in this._internals.cacheOptions)) {
|
|
1358
1454
|
throw new Error(`Cache option \`${key}\` does not exist`);
|
|
@@ -1372,24 +1468,26 @@ export default class Options {
|
|
|
1372
1468
|
return this._internals.https;
|
|
1373
1469
|
}
|
|
1374
1470
|
set https(value) {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1471
|
+
assertPlainObject('https', value);
|
|
1472
|
+
assertAny('https.rejectUnauthorized', [is.boolean, is.undefined], value.rejectUnauthorized);
|
|
1473
|
+
assertAny('https.checkServerIdentity', [is.function, is.undefined], value.checkServerIdentity);
|
|
1474
|
+
assertAny('https.serverName', [is.string, is.undefined], value.serverName);
|
|
1475
|
+
assertAny('https.certificateAuthority', [is.string, is.object, is.array, is.undefined], value.certificateAuthority);
|
|
1476
|
+
assertAny('https.key', [is.string, is.object, is.array, is.undefined], value.key);
|
|
1477
|
+
assertAny('https.certificate', [is.string, is.object, is.array, is.undefined], value.certificate);
|
|
1478
|
+
assertAny('https.passphrase', [is.string, is.undefined], value.passphrase);
|
|
1479
|
+
assertAny('https.pfx', [is.string, is.buffer, is.array, is.undefined], value.pfx);
|
|
1480
|
+
assertAny('https.alpnProtocols', [is.array, is.undefined], value.alpnProtocols);
|
|
1481
|
+
assertAny('https.ciphers', [is.string, is.undefined], value.ciphers);
|
|
1482
|
+
assertAny('https.dhparam', [is.string, is.buffer, is.undefined], value.dhparam);
|
|
1483
|
+
assertAny('https.signatureAlgorithms', [is.string, is.undefined], value.signatureAlgorithms);
|
|
1484
|
+
assertAny('https.minVersion', [is.string, is.undefined], value.minVersion);
|
|
1485
|
+
assertAny('https.maxVersion', [is.string, is.undefined], value.maxVersion);
|
|
1486
|
+
assertAny('https.honorCipherOrder', [is.boolean, is.undefined], value.honorCipherOrder);
|
|
1487
|
+
assertAny('https.tlsSessionLifetime', [is.number, is.undefined], value.tlsSessionLifetime);
|
|
1488
|
+
assertAny('https.ecdhCurve', [is.string, is.undefined], value.ecdhCurve);
|
|
1489
|
+
assertAny('https.certificateRevocationLists', [is.string, is.buffer, is.array, is.undefined], value.certificateRevocationLists);
|
|
1490
|
+
assertAny('https.secureOptions', [is.number, is.undefined], value.secureOptions);
|
|
1393
1491
|
for (const key in value) {
|
|
1394
1492
|
if (!(key in this._internals.https)) {
|
|
1395
1493
|
throw new Error(`HTTPS option \`${key}\` does not exist`);
|
|
@@ -1419,7 +1517,7 @@ export default class Options {
|
|
|
1419
1517
|
if (value === null) {
|
|
1420
1518
|
throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead');
|
|
1421
1519
|
}
|
|
1422
|
-
|
|
1520
|
+
assertAny('encoding', [is.string, is.undefined], value);
|
|
1423
1521
|
this._internals.encoding = value;
|
|
1424
1522
|
}
|
|
1425
1523
|
/**
|
|
@@ -1519,7 +1617,7 @@ export default class Options {
|
|
|
1519
1617
|
return this._internals.maxHeaderSize;
|
|
1520
1618
|
}
|
|
1521
1619
|
set maxHeaderSize(value) {
|
|
1522
|
-
|
|
1620
|
+
assertAny('maxHeaderSize', [is.number, is.undefined], value);
|
|
1523
1621
|
this._internals.maxHeaderSize = value;
|
|
1524
1622
|
}
|
|
1525
1623
|
get enableUnixSockets() {
|
|
@@ -1529,6 +1627,23 @@ export default class Options {
|
|
|
1529
1627
|
assert.boolean(value);
|
|
1530
1628
|
this._internals.enableUnixSockets = value;
|
|
1531
1629
|
}
|
|
1630
|
+
/**
|
|
1631
|
+
Throw an error if the server response's `content-length` header value doesn't match the number of bytes received.
|
|
1632
|
+
|
|
1633
|
+
This is useful for detecting truncated responses and follows RFC 9112 requirements for message completeness.
|
|
1634
|
+
|
|
1635
|
+
__Note__: Responses without a `content-length` header are not validated.
|
|
1636
|
+
__Note__: When enabled and validation fails, a `ReadError` with code `ERR_HTTP_CONTENT_LENGTH_MISMATCH` will be thrown.
|
|
1637
|
+
|
|
1638
|
+
@default false
|
|
1639
|
+
*/
|
|
1640
|
+
get strictContentLength() {
|
|
1641
|
+
return this._internals.strictContentLength;
|
|
1642
|
+
}
|
|
1643
|
+
set strictContentLength(value) {
|
|
1644
|
+
assert.boolean(value);
|
|
1645
|
+
this._internals.strictContentLength = value;
|
|
1646
|
+
}
|
|
1532
1647
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1533
1648
|
toJSON() {
|
|
1534
1649
|
return { ...this._internals };
|
|
@@ -1541,7 +1656,17 @@ export default class Options {
|
|
|
1541
1656
|
const url = internals.url;
|
|
1542
1657
|
let agent;
|
|
1543
1658
|
if (url.protocol === 'https:') {
|
|
1544
|
-
|
|
1659
|
+
if (internals.http2) {
|
|
1660
|
+
// Ensure HTTP/2 agent is configured for connection reuse
|
|
1661
|
+
// If no custom agent.http2 is provided, use the global agent for connection pooling
|
|
1662
|
+
agent = {
|
|
1663
|
+
...internals.agent,
|
|
1664
|
+
http2: internals.agent.http2 ?? http2wrapper.globalAgent,
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
else {
|
|
1668
|
+
agent = internals.agent.https;
|
|
1669
|
+
}
|
|
1545
1670
|
}
|
|
1546
1671
|
else {
|
|
1547
1672
|
agent = internals.agent.http;
|
|
@@ -1567,6 +1692,7 @@ export default class Options {
|
|
|
1567
1692
|
pfx: https.pfx,
|
|
1568
1693
|
rejectUnauthorized: https.rejectUnauthorized,
|
|
1569
1694
|
checkServerIdentity: https.checkServerIdentity ?? checkServerIdentity,
|
|
1695
|
+
servername: https.serverName,
|
|
1570
1696
|
ciphers: https.ciphers,
|
|
1571
1697
|
honorCipherOrder: https.honorCipherOrder,
|
|
1572
1698
|
minVersion: https.minVersion,
|
|
@@ -1576,6 +1702,7 @@ export default class Options {
|
|
|
1576
1702
|
dhparam: https.dhparam,
|
|
1577
1703
|
ecdhCurve: https.ecdhCurve,
|
|
1578
1704
|
crl: https.certificateRevocationLists,
|
|
1705
|
+
secureOptions: https.secureOptions,
|
|
1579
1706
|
// HTTP options
|
|
1580
1707
|
lookup: internals.dnsLookup ?? internals.dnsCache?.lookup,
|
|
1581
1708
|
family: internals.dnsLookupIpVersion,
|
|
@@ -15,8 +15,24 @@ export default async function getBodySize(body, headers) {
|
|
|
15
15
|
if (is.buffer(body)) {
|
|
16
16
|
return body.length;
|
|
17
17
|
}
|
|
18
|
+
if (is.typedArray(body)) {
|
|
19
|
+
return body.byteLength;
|
|
20
|
+
}
|
|
18
21
|
if (isFormData(body)) {
|
|
19
|
-
|
|
22
|
+
try {
|
|
23
|
+
return await promisify(body.getLength.bind(body))();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const typedError = error;
|
|
27
|
+
throw new Error('Cannot determine content-length for form-data with stream(s) of unknown length. '
|
|
28
|
+
+ 'This is a limitation of the `form-data` package. '
|
|
29
|
+
+ 'To fix this, either:\n'
|
|
30
|
+
+ '1. Use the `knownLength` option when appending streams:\n'
|
|
31
|
+
+ ' form.append(\'file\', stream, {knownLength: 12345});\n'
|
|
32
|
+
+ '2. Switch to spec-compliant FormData (formdata-node package)\n'
|
|
33
|
+
+ 'See: https://github.com/form-data/form-data#alternative-submission-methods\n'
|
|
34
|
+
+ `Original error: ${typedError.message}`);
|
|
35
|
+
}
|
|
20
36
|
}
|
|
21
37
|
return undefined;
|
|
22
38
|
}
|
|
@@ -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
|
+
}
|
package/dist/source/create.js
CHANGED
|
@@ -139,7 +139,15 @@ const create = (defaults) => {
|
|
|
139
139
|
}
|
|
140
140
|
else {
|
|
141
141
|
normalizedOptions.merge(optionsToMerge);
|
|
142
|
-
|
|
142
|
+
try {
|
|
143
|
+
assert.any([is.urlInstance, is.undefined], optionsToMerge.url);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (error instanceof Error) {
|
|
147
|
+
error.message = `Option 'pagination.paginate.url': ${error.message}`;
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
143
151
|
if (optionsToMerge.url !== undefined) {
|
|
144
152
|
normalizedOptions.prefixUrl = '';
|
|
145
153
|
normalizedOptions.url = optionsToMerge.url;
|