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.
@@ -7,13 +7,15 @@ import type { Socket } from 'node:net';
7
7
  import CacheableLookup from 'cacheable-lookup';
8
8
  import http2wrapper, { type ClientHttp2Session } from 'http2-wrapper';
9
9
  import { type FormDataLike } from 'form-data-encoder';
10
- import type { StorageAdapter } from 'cacheable-request';
10
+ import type { KeyvStoreAdapter } from 'keyv';
11
+ import type KeyvType from 'keyv';
11
12
  import type ResponseLike from 'responselike';
12
13
  import type { IncomingMessageWithTimings } from '@szmarczak/http-timer';
13
14
  import type { CancelableRequest } from '../as-promise/types.js';
14
15
  import type { PlainResponse, Response } from './response.js';
15
16
  import type { RequestError } from './errors.js';
16
17
  import type { Delays } from './timed-out.js';
18
+ type StorageAdapter = KeyvStoreAdapter | KeyvType | Map<any, any>;
17
19
  type Promisable<T> = T | Promise<T>;
18
20
  export type DnsLookupIpVersion = undefined | 4 | 6;
19
21
  type Except<ObjectType, KeysType extends keyof ObjectType> = Pick<ObjectType, Exclude<keyof ObjectType, KeysType>>;
@@ -37,9 +39,34 @@ export type PromiseCookieJar = {
37
39
  getCookieString: (url: string) => Promise<string>;
38
40
  setCookie: (rawCookie: string, url: string) => Promise<unknown>;
39
41
  };
42
+ /**
43
+ Utility type to override specific properties in a type.
44
+
45
+ Uses `Omit` to remove properties before adding them back to ensure proper type replacement rather than intersection, which handles edge cases with optional/required properties correctly.
46
+ */
47
+ type OverrideProperties<T, U> = Omit<T, keyof U> & U;
48
+ /**
49
+ Represents the runtime state of Options as seen by hooks after normalization.
50
+
51
+ Some Options properties accept multiple input types but are normalized to a single type internally by the Options class setters. This type reflects the actual runtime types that hooks receive, ensuring type safety when accessing options within hook functions.
52
+ */
53
+ export type NormalizedOptions = OverrideProperties<Options, {
54
+ url: URL | undefined;
55
+ dnsCache: CacheableLookup | undefined;
56
+ cache: StorageAdapter | undefined;
57
+ prefixUrl: string;
58
+ }>;
40
59
  export type InitHook = (init: OptionsInit, self: Options) => void;
41
- export type BeforeRequestHook = (options: Options) => Promisable<void | Response | ResponseLike>;
42
- export type BeforeRedirectHook = (updatedOptions: Options, plainResponse: PlainResponse) => Promisable<void>;
60
+ export type BeforeRequestHookContext = {
61
+ /**
62
+ The current retry count.
63
+
64
+ It will be `0` for the initial request and increment for each retry.
65
+ */
66
+ retryCount: number;
67
+ };
68
+ export type BeforeRequestHook = (options: NormalizedOptions, context: BeforeRequestHookContext) => Promisable<void | Response | ResponseLike>;
69
+ export type BeforeRedirectHook = (updatedOptions: NormalizedOptions, plainResponse: PlainResponse) => Promisable<void>;
43
70
  export type BeforeErrorHook = (error: RequestError) => Promisable<RequestError>;
44
71
  export type BeforeRetryHook = (error: RequestError, retryCount: number) => Promisable<void>;
45
72
  export type AfterResponseHook<ResponseType = unknown> = (response: Response<ResponseType>, retryWithMergedOptions: (options: OptionsInit) => never) => Promisable<Response | CancelableRequest<Response>>;
@@ -140,6 +167,8 @@ export type Hooks = {
140
167
  /**
141
168
  Called right before making the request with `options.createNativeRequestOptions()`.
142
169
 
170
+ The second argument is a context object containing request state information.
171
+
143
172
  This hook is especially useful in conjunction with `got.extend()` when you want to sign your request.
144
173
 
145
174
  @default []
@@ -160,7 +189,7 @@ export type Hooks = {
160
189
  json: {payload: 'old'},
161
190
  hooks: {
162
191
  beforeRequest: [
163
- options => {
192
+ (options, context) => {
164
193
  options.body = JSON.stringify({payload: 'new'});
165
194
  options.headers['content-length'] = options.body.length.toString();
166
195
  }
@@ -170,6 +199,28 @@ export type Hooks = {
170
199
  );
171
200
  ```
172
201
 
202
+ **Example using `context.retryCount`:**
203
+
204
+ ```
205
+ import got from 'got';
206
+
207
+ await got('https://httpbin.org/status/500', {
208
+ retry: {
209
+ limit: 2
210
+ },
211
+ hooks: {
212
+ beforeRequest: [
213
+ (options, context) => {
214
+ // Only log on the initial request, not on retries
215
+ if (context.retryCount === 0) {
216
+ console.log('Making initial request');
217
+ }
218
+ }
219
+ ]
220
+ }
221
+ });
222
+ ```
223
+
173
224
  **Tip:**
174
225
  > - You can indirectly override the `request` function by early returning a [`ClientRequest`-like](https://nodejs.org/api/http.html#http_class_http_clientrequest) instance or a [`IncomingMessage`-like](https://nodejs.org/api/http.html#http_class_http_incomingmessage) instance. This is very useful when creating a custom cache mechanism.
175
226
  > - [Read more about this tip](https://github.com/sindresorhus/got/blob/main/documentation/cache.md#advanced-caching-mechanisms).
@@ -272,9 +323,15 @@ export type Hooks = {
272
323
  > - When using the Stream API, this hook is ignored.
273
324
 
274
325
  **Note:**
275
- > - Calling the `retryWithMergedOptions` function will trigger `beforeRetry` hooks. If the retry is successful, all remaining `afterResponse` hooks will be called. In case of an error, `beforeRetry` hooks will be called instead.
326
+ > - Calling the `retryWithMergedOptions` function will trigger `beforeRetry` hooks. By default, remaining `afterResponse` hooks are removed to prevent duplicate execution. To preserve remaining hooks on retry, set `preserveHooks: true` in the options passed to `retryWithMergedOptions`. In case of an error, `beforeRetry` hooks will be called instead.
276
327
  Meanwhile the `init`, `beforeRequest` , `beforeRedirect` as well as already executed `afterResponse` hooks will be skipped.
277
328
 
329
+ **Note:**
330
+ > - To preserve remaining `afterResponse` hooks after calling `retryWithMergedOptions`, set `preserveHooks: true` in the options passed to `retryWithMergedOptions`. This is useful when you want hooks to run on retried requests.
331
+
332
+ **Warning:**
333
+ > - Be cautious when using `preserveHooks: true`. If a hook unconditionally calls `retryWithMergedOptions` with `preserveHooks: true`, it will create an infinite retry loop. Always ensure hooks have proper conditional logic to avoid infinite retries.
334
+
278
335
  @example
279
336
  ```
280
337
  import got from 'got';
@@ -312,6 +369,37 @@ export type Hooks = {
312
369
  mutableDefaults: true
313
370
  });
314
371
  ```
372
+
373
+ @example
374
+ ```
375
+ // Example with preserveHooks
376
+ import got from 'got';
377
+
378
+ const instance = got.extend({
379
+ hooks: {
380
+ afterResponse: [
381
+ (response, retryWithMergedOptions) => {
382
+ if (response.statusCode === 401) {
383
+ return retryWithMergedOptions({
384
+ headers: {
385
+ authorization: getNewToken()
386
+ },
387
+ preserveHooks: true // Keep remaining hooks
388
+ });
389
+ }
390
+
391
+ return response;
392
+ },
393
+ (response) => {
394
+ // This hook will run on the retried request
395
+ // (the original request is interrupted when the first hook triggers a retry)
396
+ console.log('Response received:', response.statusCode);
397
+ return response;
398
+ }
399
+ ]
400
+ }
401
+ });
402
+ ```
315
403
  */
316
404
  afterResponse: AfterResponseHook[];
317
405
  };
@@ -337,7 +425,9 @@ Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.ra
337
425
  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.
338
426
  The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).
339
427
 
340
- __Note:__ When you provide `calculateDelay`, you take full control of retry decisions. The `limit` option is not automatically enforced - you must check `attemptCount` yourself or return `0` when `computedValue` is `0` to respect the default retry logic.
428
+ 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.
429
+
430
+ __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.
341
431
 
342
432
  By default, it retries *only* on the specified methods, status codes, and on these network errors:
343
433
  - `ETIMEDOUT`: One of the [timeout](#timeout) limits were reached.
@@ -362,6 +452,7 @@ export type RetryOptions = {
362
452
  backoffLimit: number;
363
453
  noise: number;
364
454
  maxRetryAfter?: number;
455
+ enforceRetryRules?: boolean;
365
456
  };
366
457
  export type CreateConnectionFunction = (options: NativeRequestOptions, oncreate: (error: NodeJS.ErrnoException, socket: Socket) => void) => Socket;
367
458
  export type CheckServerIdentityFunction = (hostname: string, certificate: DetailedPeerCertificate) => NodeJS.ErrnoException | void;
@@ -381,6 +472,24 @@ export type HttpsOptions = {
381
472
  rejectUnauthorized?: NativeRequestOptions['rejectUnauthorized'];
382
473
  checkServerIdentity?: CheckServerIdentityFunction;
383
474
  /**
475
+ Server name for the [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) TLS extension.
476
+
477
+ This is useful when requesting to servers that don't have a proper domain name but use a certificate with a known CN/SAN.
478
+
479
+ @example
480
+ ```
481
+ import got from 'got';
482
+
483
+ // Request to IP address with specific servername for TLS
484
+ await got('https://192.168.1.100', {
485
+ https: {
486
+ serverName: 'example.com'
487
+ }
488
+ });
489
+ ```
490
+ */
491
+ serverName?: string;
492
+ /**
384
493
  Override the default Certificate Authorities ([from Mozilla](https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReport)).
385
494
 
386
495
  @example
@@ -427,6 +536,27 @@ export type HttpsOptions = {
427
536
  dhparam?: SecureContextOptions['dhparam'];
428
537
  ecdhCurve?: SecureContextOptions['ecdhCurve'];
429
538
  certificateRevocationLists?: SecureContextOptions['crl'];
539
+ /**
540
+ Optionally affect the OpenSSL protocol behavior, which is not usually necessary. This should be used carefully if at all!
541
+
542
+ The value is a numeric bitmask of the `SSL_OP_*` options from OpenSSL.
543
+
544
+ For example, to allow connections to legacy servers that do not support secure renegotiation, you can use `crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT`.
545
+
546
+ @example
547
+ ```
548
+ import crypto from 'node:crypto';
549
+ import got from 'got';
550
+
551
+ // Allow connections to servers with legacy renegotiation
552
+ await got('https://legacy-server.com', {
553
+ https: {
554
+ secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT
555
+ }
556
+ });
557
+ ```
558
+ */
559
+ secureOptions?: number;
430
560
  };
431
561
  export type PaginateData<BodyType, ElementType> = {
432
562
  response: Response<BodyType>;
@@ -553,6 +683,7 @@ export type OptionsError = NodeJS.ErrnoException & {
553
683
  export type OptionsInit = Except<Partial<InternalsType>, 'hooks' | 'retry'> & {
554
684
  hooks?: Partial<Hooks>;
555
685
  retry?: Partial<RetryOptions>;
686
+ preserveHooks?: boolean;
556
687
  };
557
688
  export default class Options {
558
689
  private _unixOptions?;
@@ -674,12 +805,29 @@ export default class Options {
674
805
 
675
806
  __Note #4__: This option is not enumerable and will not be merged with the instance defaults.
676
807
 
677
- 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`.
808
+ 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`.
678
809
 
679
810
  Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`.
811
+
812
+ You can use `Iterable` and `AsyncIterable` objects as request body, including Web [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream):
813
+
814
+ @example
815
+ ```
816
+ import got from 'got';
817
+
818
+ // Using an async generator
819
+ async function* generateData() {
820
+ yield 'Hello, ';
821
+ yield 'world!';
822
+ }
823
+
824
+ await got.post('https://httpbin.org/anything', {
825
+ body: generateData()
826
+ });
827
+ ```
680
828
  */
681
- get body(): string | Buffer | Readable | Generator | AsyncGenerator | FormDataLike | undefined;
682
- set body(value: string | Buffer | Readable | Generator | AsyncGenerator | FormDataLike | undefined);
829
+ get body(): string | Buffer | Readable | Generator | AsyncGenerator | Iterable<unknown> | AsyncIterable<unknown> | FormDataLike | ArrayBufferView | undefined;
830
+ set body(value: string | Buffer | Readable | Generator | AsyncGenerator | Iterable<unknown> | AsyncIterable<unknown> | FormDataLike | ArrayBufferView | undefined);
683
831
  /**
684
832
  The form body is converted to a query string using [`(new URLSearchParams(object)).toString()`](https://nodejs.org/api/url.html#url_constructor_new_urlsearchparams_obj).
685
833
 
@@ -692,7 +840,9 @@ export default class Options {
692
840
  get form(): Record<string, any> | undefined;
693
841
  set form(value: Record<string, any> | undefined);
694
842
  /**
695
- JSON body. If the `Content-Type` header is not set, it will be set to `application/json`.
843
+ JSON request body. If the `content-type` header is not set, it will be set to `application/json`.
844
+
845
+ __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.
696
846
 
697
847
  __Note #1__: If you provide this option, `got.stream()` will be read-only.
698
848
 
@@ -1007,7 +1157,9 @@ export default class Options {
1007
1157
  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.
1008
1158
  The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).
1009
1159
 
1010
- __Note:__ When you provide `calculateDelay`, you take full control of retry decisions. The `limit` option is not automatically enforced - you must check `attemptCount` yourself or return `0` when `computedValue` is `0` to respect the default retry logic.
1160
+ 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.
1161
+
1162
+ __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.
1011
1163
 
1012
1164
  By default, it retries *only* on the specified methods, status codes, and on these network errors:
1013
1165
 
@@ -1122,6 +1274,18 @@ export default class Options {
1122
1274
  set maxHeaderSize(value: number | undefined);
1123
1275
  get enableUnixSockets(): boolean;
1124
1276
  set enableUnixSockets(value: boolean);
1277
+ /**
1278
+ Throw an error if the server response's `content-length` header value doesn't match the number of bytes received.
1279
+
1280
+ This is useful for detecting truncated responses and follows RFC 9112 requirements for message completeness.
1281
+
1282
+ __Note__: Responses without a `content-length` header are not validated.
1283
+ __Note__: When enabled and validation fails, a `ReadError` with code `ERR_HTTP_CONTENT_LENGTH_MISMATCH` will be thrown.
1284
+
1285
+ @default false
1286
+ */
1287
+ get strictContentLength(): boolean;
1288
+ set strictContentLength(value: boolean);
1125
1289
  toJSON(): {
1126
1290
  headers: Headers;
1127
1291
  timeout: Delays;
@@ -1135,7 +1299,7 @@ export default class Options {
1135
1299
  h2session: ClientHttp2Session | undefined;
1136
1300
  decompress: boolean;
1137
1301
  prefixUrl: string | URL;
1138
- body: string | Buffer | Readable | Generator | AsyncGenerator | FormDataLike | undefined;
1302
+ body: string | Buffer | Readable | Generator | AsyncGenerator | Iterable<unknown> | AsyncIterable<unknown> | FormDataLike | ArrayBufferView | undefined;
1139
1303
  form: Record<string, any> | undefined;
1140
1304
  url: string | URL | undefined;
1141
1305
  cookieJar: PromiseCookieJar | ToughCookieJar | undefined;
@@ -1168,6 +1332,7 @@ export default class Options {
1168
1332
  setHost: boolean;
1169
1333
  maxHeaderSize: number | undefined;
1170
1334
  enableUnixSockets: boolean;
1335
+ strictContentLength: boolean;
1171
1336
  };
1172
1337
  createNativeRequestOptions(): {
1173
1338
  ALPNProtocols: string[] | undefined;
@@ -1178,6 +1343,7 @@ export default class Options {
1178
1343
  pfx: PfxType;
1179
1344
  rejectUnauthorized: boolean | undefined;
1180
1345
  checkServerIdentity: CheckServerIdentityFunction | typeof checkServerIdentity;
1346
+ servername: string | undefined;
1181
1347
  ciphers: string | undefined;
1182
1348
  honorCipherOrder: boolean | undefined;
1183
1349
  minVersion: import("tls").SecureVersion | undefined;
@@ -1187,6 +1353,7 @@ export default class Options {
1187
1353
  dhparam: string | Buffer<ArrayBufferLike> | undefined;
1188
1354
  ecdhCurve: string | undefined;
1189
1355
  crl: string | Buffer<ArrayBufferLike> | (string | Buffer<ArrayBufferLike>)[] | undefined;
1356
+ secureOptions: number | undefined;
1190
1357
  lookup: {
1191
1358
  (hostname: string, family: import("cacheable-lookup").IPFamily, callback: (error: NodeJS.ErrnoException | null, address: string, family: import("cacheable-lookup").IPFamily) => void): void;
1192
1359
  (hostname: string, callback: (error: NodeJS.ErrnoException | null, address: string, family: import("cacheable-lookup").IPFamily) => void): void;
@@ -1196,7 +1363,11 @@ export default class Options {
1196
1363
  (hostname: string, options: import("cacheable-lookup").LookupOptions, callback: (error: NodeJS.ErrnoException | null, address: string, family: import("cacheable-lookup").IPFamily) => void): void;
1197
1364
  } | undefined;
1198
1365
  family: DnsLookupIpVersion;
1199
- agent: false | http.Agent | Agents | undefined;
1366
+ agent: false | http.Agent | {
1367
+ http2: {};
1368
+ http?: HttpAgent | false;
1369
+ https?: HttpsAgent | false;
1370
+ } | undefined;
1200
1371
  setHost: boolean;
1201
1372
  method: Method;
1202
1373
  maxHeaderSize: number | undefined;
@@ -1229,11 +1400,9 @@ export default class Options {
1229
1400
  clientCertEngine?: string | undefined;
1230
1401
  privateKeyEngine?: string | undefined;
1231
1402
  privateKeyIdentifier?: string | undefined;
1232
- secureOptions?: number | undefined;
1233
1403
  secureProtocol?: string | undefined;
1234
1404
  sessionIdContext?: string | undefined;
1235
1405
  ticketKeys?: Buffer | undefined;
1236
- servername?: string | undefined;
1237
1406
  shared?: boolean;
1238
1407
  cacheHeuristic?: number;
1239
1408
  immutableMinTimeToLive?: number;