got 15.0.0 → 15.0.2

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.
@@ -24,97 +24,105 @@ export default function asPromise(firstRequest) {
24
24
  request.retryCount = retryCount;
25
25
  request._noPipe = true;
26
26
  globalRequest = request;
27
- request.once('response', async (response) => {
28
- // Parse body
29
- const contentEncoding = (response.headers['content-encoding'] ?? '').toLowerCase();
30
- const isCompressed = compressedEncodings.has(contentEncoding);
31
- const { options } = request;
32
- if (isCompressed && !options.decompress) {
33
- response.body = response.rawBody;
34
- }
35
- else {
36
- try {
37
- response.body = parseBody(response, options.responseType, options.parseJson, options.encoding);
27
+ request.once('response', (response) => {
28
+ void (async () => {
29
+ // Parse body
30
+ const contentEncoding = (response.headers['content-encoding'] ?? '').toLowerCase();
31
+ const isCompressed = compressedEncodings.has(contentEncoding);
32
+ const { options } = request;
33
+ if (isCompressed && !options.decompress) {
34
+ response.body = response.rawBody;
38
35
  }
39
- catch (error) {
40
- // Fall back to `utf8`
36
+ else {
41
37
  try {
42
- response.body = decodeUint8Array(response.rawBody);
38
+ response.body = parseBody(response, options.responseType, options.parseJson, options.encoding);
43
39
  }
44
40
  catch (error) {
45
- request._beforeError(new ParseError(normalizeError(error), response));
46
- return;
47
- }
48
- if (isResponseOk(response)) {
49
- request._beforeError(normalizeError(error));
50
- return;
51
- }
52
- }
53
- }
54
- try {
55
- const hooks = options.hooks.afterResponse;
56
- for (const [index, hook] of hooks.entries()) {
57
- const previousUrl = options.url ? new URL(options.url) : undefined;
58
- const previousState = previousUrl ? snapshotCrossOriginState(options) : undefined;
59
- const requestOptions = response.request.options;
60
- const responseSnapshot = response;
61
- // @ts-expect-error TS doesn't notice that RequestPromise is a Promise
62
- // eslint-disable-next-line no-await-in-loop
63
- response = await requestOptions.trackStateMutations(async (changedState) => hook(responseSnapshot, async (updatedOptions) => {
64
- const preserveHooks = updatedOptions.preserveHooks ?? false;
65
- const reusesRequestOptions = updatedOptions === requestOptions;
66
- const hasExplicitBody = reusesRequestOptions
67
- ? changedState.has('body') || changedState.has('json') || changedState.has('form')
68
- : (Object.hasOwn(updatedOptions, 'body') && updatedOptions.body !== undefined)
69
- || (Object.hasOwn(updatedOptions, 'json') && updatedOptions.json !== undefined)
70
- || (Object.hasOwn(updatedOptions, 'form') && updatedOptions.form !== undefined);
71
- if (hasExplicitBody && !reusesRequestOptions) {
72
- options.clearBody();
41
+ // Fall back to `utf8`
42
+ try {
43
+ response.body = decodeUint8Array(response.rawBody);
73
44
  }
74
- if (!reusesRequestOptions) {
75
- options.merge(updatedOptions);
45
+ catch (error) {
46
+ request._beforeError(new ParseError(normalizeError(error), response));
47
+ return;
76
48
  }
77
- if (updatedOptions.url) {
78
- const nextUrl = reusesRequestOptions
79
- ? options.url
80
- : applyUrlOverride(options, updatedOptions.url, updatedOptions);
81
- if (previousUrl) {
82
- if (reusesRequestOptions && !isSameOrigin(previousUrl, nextUrl)) {
83
- options.stripUnchangedCrossOriginState(previousState, changedState, { clearBody: !hasExplicitBody });
84
- }
85
- else {
86
- options.stripSensitiveHeaders(previousUrl, nextUrl, updatedOptions);
87
- if (!isSameOrigin(previousUrl, nextUrl) && !hasExplicitBody) {
88
- options.clearBody();
49
+ if (isResponseOk(response)) {
50
+ request._beforeError(normalizeError(error));
51
+ return;
52
+ }
53
+ }
54
+ }
55
+ try {
56
+ const hooks = options.hooks.afterResponse;
57
+ for (const [index, hook] of hooks.entries()) {
58
+ const previousUrl = options.url ? new URL(options.url) : undefined;
59
+ const previousState = previousUrl ? snapshotCrossOriginState(options) : undefined;
60
+ const requestOptions = response.request.options;
61
+ const responseSnapshot = response;
62
+ // @ts-expect-error TS doesn't notice that RequestPromise is a Promise
63
+ // eslint-disable-next-line no-await-in-loop
64
+ response = await requestOptions.trackStateMutations(async (changedState) => hook(responseSnapshot, async (updatedOptions) => {
65
+ const preserveHooks = updatedOptions.preserveHooks ?? false;
66
+ const reusesRequestOptions = updatedOptions === requestOptions;
67
+ const hasExplicitBody = reusesRequestOptions
68
+ ? changedState.has('body') || changedState.has('json') || changedState.has('form')
69
+ : (Object.hasOwn(updatedOptions, 'body') && updatedOptions.body !== undefined)
70
+ || (Object.hasOwn(updatedOptions, 'json') && updatedOptions.json !== undefined)
71
+ || (Object.hasOwn(updatedOptions, 'form') && updatedOptions.form !== undefined);
72
+ const clearsCookieJar = Object.hasOwn(updatedOptions, 'cookieJar') && updatedOptions.cookieJar === undefined;
73
+ if (hasExplicitBody && !reusesRequestOptions) {
74
+ options.clearBody();
75
+ }
76
+ if (!reusesRequestOptions && clearsCookieJar) {
77
+ options.cookieJar = undefined;
78
+ }
79
+ if (!reusesRequestOptions) {
80
+ options.merge(updatedOptions);
81
+ options.syncCookieHeaderAfterMerge(previousState, updatedOptions.headers);
82
+ }
83
+ options.clearUnchangedCookieHeader(previousState, reusesRequestOptions ? changedState : undefined);
84
+ if (updatedOptions.url) {
85
+ const nextUrl = reusesRequestOptions
86
+ ? options.url
87
+ : applyUrlOverride(options, updatedOptions.url, updatedOptions);
88
+ if (previousUrl) {
89
+ if (reusesRequestOptions && !isSameOrigin(previousUrl, nextUrl)) {
90
+ options.stripUnchangedCrossOriginState(previousState, changedState, { clearBody: !hasExplicitBody });
91
+ }
92
+ else {
93
+ options.stripSensitiveHeaders(previousUrl, nextUrl, updatedOptions);
94
+ if (!isSameOrigin(previousUrl, nextUrl) && !hasExplicitBody) {
95
+ options.clearBody();
96
+ }
89
97
  }
90
98
  }
91
99
  }
100
+ // Remove any further hooks for that request, because we'll call them anyway.
101
+ // The loop continues. We don't want duplicates (asPromise recursion).
102
+ // Unless preserveHooks is true, in which case we keep the remaining hooks.
103
+ if (!preserveHooks) {
104
+ options.hooks.afterResponse = options.hooks.afterResponse.slice(0, index);
105
+ }
106
+ throw new RetryError(request);
107
+ }));
108
+ if (!(is.object(response) && is.number(response.statusCode) && 'body' in response)) {
109
+ throw new TypeError('The `afterResponse` hook returned an invalid value');
92
110
  }
93
- // Remove any further hooks for that request, because we'll call them anyway.
94
- // The loop continues. We don't want duplicates (asPromise recursion).
95
- // Unless preserveHooks is true, in which case we keep the remaining hooks.
96
- if (!preserveHooks) {
97
- options.hooks.afterResponse = options.hooks.afterResponse.slice(0, index);
98
- }
99
- throw new RetryError(request);
100
- }));
101
- if (!(is.object(response) && is.number(response.statusCode) && 'body' in response)) {
102
- throw new TypeError('The `afterResponse` hook returned an invalid value');
103
111
  }
104
112
  }
105
- }
106
- catch (error) {
107
- request._beforeError(normalizeError(error));
108
- return;
109
- }
110
- globalResponse = response;
111
- if (!isResponseOk(response)) {
112
- request._beforeError(new HTTPError(response));
113
- return;
114
- }
115
- request.destroy();
116
- promiseSettled = true;
117
- resolve(request.options.resolveBodyOnly ? response.body : response);
113
+ catch (error) {
114
+ request._beforeError(normalizeError(error));
115
+ return;
116
+ }
117
+ globalResponse = response;
118
+ if (!isResponseOk(response)) {
119
+ request._beforeError(new HTTPError(response));
120
+ return;
121
+ }
122
+ request.destroy();
123
+ promiseSettled = true;
124
+ resolve(request.options.resolveBodyOnly ? response.body : response);
125
+ })();
118
126
  });
119
127
  let handledFinalError = false;
120
128
  const onError = (error) => {
@@ -191,7 +199,7 @@ export default function asPromise(firstRequest) {
191
199
  const { options } = globalResponse.request;
192
200
  if (responseType === 'text') {
193
201
  const text = decodeUint8Array(globalResponse.rawBody, options.encoding);
194
- return (isUtf8Encoding(options.encoding) ? text.replace(/^\uFEFF/u, '') : text);
202
+ return (isUtf8Encoding(options.encoding) ? text.replace(/^\u{FEFF}/v, '') : text);
195
203
  }
196
204
  return parseBody(globalResponse, responseType, options.parseJson, options.encoding);
197
205
  })();
@@ -41,13 +41,13 @@ export class RequestError extends Error {
41
41
  // Recover the original stacktrace
42
42
  if (is.string(error.stack) && is.string(this.stack)) {
43
43
  const indexOfMessage = this.stack.indexOf(this.message) + this.message.length;
44
- const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse();
45
- const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse();
44
+ const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').toReversed();
45
+ const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').toReversed();
46
46
  // Remove duplicated traces
47
47
  while (errorStackTrace.length > 0 && errorStackTrace[0] === thisStackTrace[0]) {
48
48
  thisStackTrace.shift();
49
49
  }
50
- this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`;
50
+ this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.toReversed().join('\n')}${errorStackTrace.toReversed().join('\n')}`;
51
51
  }
52
52
  }
53
53
  }
@@ -725,6 +725,40 @@ export default class Request extends Duplex {
725
725
  }, this));
726
726
  }
727
727
  });
728
+ let canFinalizeResponse = false;
729
+ const handleResponseEnd = () => {
730
+ if (!canFinalizeResponse
731
+ || !response.readableEnded) {
732
+ return;
733
+ }
734
+ canFinalizeResponse = false;
735
+ if (this._stopReading) {
736
+ return;
737
+ }
738
+ // Validate content-length if it was provided
739
+ // Per RFC 9112: "If the sender closes the connection before the indicated number
740
+ // of octets are received, the recipient MUST consider the message to be incomplete"
741
+ if (this._checkContentLengthMismatch()) {
742
+ return;
743
+ }
744
+ this._responseSize = this._downloadedSize;
745
+ this.emit('downloadProgress', this.downloadProgress);
746
+ // Publish response end event
747
+ publishResponseEnd({
748
+ requestId: this._requestId,
749
+ url: typedResponse.url,
750
+ statusCode,
751
+ bodySize: this._downloadedSize,
752
+ timings: this.timings,
753
+ });
754
+ this.push(null);
755
+ };
756
+ if (!shouldFollowRedirect) {
757
+ // `set-cookie` handling below awaits the cookie jar. A fast response can fully
758
+ // end during that await, so we need to observe `end` early without completing
759
+ // the outward stream until cookie handling has finished.
760
+ response.once('end', handleResponseEnd);
761
+ }
728
762
  const noPipeCookieJarRawBodyPromise = this._noPipe
729
763
  && is.object(options.cookieJar)
730
764
  && !isRedirect
@@ -828,6 +862,7 @@ export default class Request extends Duplex {
828
862
  }
829
863
  return changedState;
830
864
  });
865
+ updatedOptions.clearUnchangedCookieHeader(preHookState, changedState);
831
866
  // If a beforeRedirect hook changed the URL to a different origin,
832
867
  // strip sensitive headers that were preserved for the original origin.
833
868
  // When isDifferentOrigin was already true, headers were already stripped above.
@@ -836,15 +871,7 @@ export default class Request extends Duplex {
836
871
  const hookUrl = updatedOptions.url;
837
872
  if (!isSameOrigin(state.url, hookUrl)) {
838
873
  this._stripUnchangedCrossOriginState(updatedOptions, hookUrl, shouldDropBody, {
839
- headers: state.headers,
840
- username: state.username,
841
- password: state.password,
842
- body: state.body,
843
- json: state.json,
844
- form: state.form,
845
- bodySnapshot: state.bodySnapshot,
846
- jsonSnapshot: state.jsonSnapshot,
847
- formSnapshot: state.formSnapshot,
874
+ ...state,
848
875
  changedState,
849
876
  preserveUsername: hasExplicitCredentialInUrlChange(changedState, hookUrl, 'username')
850
877
  || isCrossOriginCredentialChanged(state.url, hookUrl, 'username'),
@@ -870,6 +897,8 @@ export default class Request extends Duplex {
870
897
  }
871
898
  return;
872
899
  }
900
+ canFinalizeResponse = true;
901
+ handleResponseEnd();
873
902
  // `HTTPError`s always have `error.response.body` defined.
874
903
  // Therefore, we cannot retry if `options.throwHttpErrors` is false.
875
904
  // On the last retry, if `options.throwHttpErrors` is false, we would need to return the body,
@@ -894,32 +923,6 @@ export default class Request extends Duplex {
894
923
  }
895
924
  }
896
925
  }
897
- // Set up end listener AFTER redirect check to avoid emitting progress for redirect responses
898
- let responseEndHandled = false;
899
- const handleResponseEnd = () => {
900
- if (responseEndHandled) {
901
- return;
902
- }
903
- responseEndHandled = true;
904
- // Validate content-length if it was provided
905
- // Per RFC 9112: "If the sender closes the connection before the indicated number
906
- // of octets are received, the recipient MUST consider the message to be incomplete"
907
- if (this._checkContentLengthMismatch()) {
908
- return;
909
- }
910
- this._responseSize = this._downloadedSize;
911
- this.emit('downloadProgress', this.downloadProgress);
912
- // Publish response end event
913
- publishResponseEnd({
914
- requestId: this._requestId,
915
- url: typedResponse.url,
916
- statusCode,
917
- bodySize: this._downloadedSize,
918
- timings: this.timings,
919
- });
920
- this.push(null);
921
- };
922
- response.once('end', handleResponseEnd);
923
926
  this.emit('downloadProgress', this.downloadProgress);
924
927
  response.on('readable', () => {
925
928
  if (this._triggerRead) {
@@ -1319,7 +1322,8 @@ export default class Request extends Duplex {
1319
1322
  try {
1320
1323
  const result = iterableBody.return();
1321
1324
  if (result instanceof Promise) {
1322
- result.catch(noop); // eslint-disable-line promise/prefer-await-to-then
1325
+ // eslint-disable-next-line promise/prefer-await-to-then
1326
+ result.catch(noop);
1323
1327
  }
1324
1328
  }
1325
1329
  catch { }
@@ -1493,28 +1497,30 @@ export default class Request extends Duplex {
1493
1497
  });
1494
1498
  let request;
1495
1499
  // TODO: Fix `cacheable-response`. This is ugly.
1496
- const cacheRequest = cacheableStore.get(options.cache)(options, async (response) => {
1497
- response._readableState.autoDestroy = false;
1498
- if (request) {
1499
- const fix = () => {
1500
- // For ResponseLike objects from cache, set complete to true if not already set.
1501
- // For real HTTP responses, copy from the underlying response.
1502
- if (response.req) {
1503
- response.complete = response.req.res.complete;
1504
- }
1505
- else if (response.complete === undefined) {
1506
- // ResponseLike from cache should have complete = true
1507
- response.complete = true;
1508
- }
1509
- };
1510
- response.prependOnceListener('end', fix);
1511
- fix();
1512
- (await request).emit('cacheableResponse', response);
1513
- }
1514
- resolve(response);
1500
+ const cacheRequest = cacheableStore.get(options.cache)(options, (response) => {
1501
+ void (async () => {
1502
+ response._readableState.autoDestroy = false;
1503
+ if (request) {
1504
+ const fix = () => {
1505
+ // For ResponseLike objects from cache, set complete to true if not already set.
1506
+ // For real HTTP responses, copy from the underlying response.
1507
+ if (response.req) {
1508
+ response.complete = response.req.res.complete;
1509
+ }
1510
+ else if (response.complete === undefined) {
1511
+ // ResponseLike from cache should have complete = true
1512
+ response.complete = true;
1513
+ }
1514
+ };
1515
+ response.prependOnceListener('end', fix);
1516
+ fix();
1517
+ (await request).emit('cacheableResponse', response);
1518
+ }
1519
+ resolve(response);
1520
+ })();
1515
1521
  });
1516
1522
  cacheRequest.once('error', reject);
1517
- cacheRequest.once('request', async (requestOrPromise) => {
1523
+ cacheRequest.once('request', (requestOrPromise) => {
1518
1524
  request = requestOrPromise;
1519
1525
  resolve(request);
1520
1526
  });
@@ -1522,17 +1528,46 @@ export default class Request extends Duplex {
1522
1528
  }
1523
1529
  async _makeRequest() {
1524
1530
  const { options } = this;
1525
- const headers = options.getInternalHeaders();
1526
- const { username, password } = options;
1527
- const cookieJar = options.cookieJar;
1528
- for (const key in headers) {
1529
- if (is.undefined(headers[key])) {
1530
- options.deleteInternalHeader(key);
1531
+ const initialHeaders = options.getInternalHeaders();
1532
+ const explicitAuthorizationHeader = options.isHeaderExplicitlySet('authorization') ? initialHeaders.authorization : undefined;
1533
+ const explicitCookieHeader = options.isHeaderExplicitlySet('cookie') ? initialHeaders.cookie : undefined;
1534
+ const authorizationWasInitiallyOmitted = options.isHeaderExplicitlySet('authorization') && is.undefined(initialHeaders.authorization);
1535
+ const cookieWasInitiallyOmitted = options.isHeaderExplicitlySet('cookie') && is.undefined(initialHeaders.cookie);
1536
+ const shouldDeleteGeneratedHeader = (currentHeader, generatedHeader) => currentHeader === generatedHeader || is.undefined(currentHeader);
1537
+ const syncGeneratedHeader = (name, { currentHeader, explicitHeader, nextHeader, staleGeneratedHeader, }) => {
1538
+ if (!is.undefined(nextHeader)) {
1539
+ options.setInternalHeader(name, nextHeader);
1540
+ }
1541
+ else if (!is.undefined(explicitHeader) && currentHeader === staleGeneratedHeader) {
1542
+ options.setInternalHeader(name, explicitHeader);
1543
+ }
1544
+ else if (shouldDeleteGeneratedHeader(currentHeader, staleGeneratedHeader)) {
1545
+ options.deleteInternalHeader(name);
1546
+ }
1547
+ };
1548
+ const getAuthorizationHeader = (username, password, isExplicitlyOmitted) => !isExplicitlyOmitted && (username || password)
1549
+ ? `Basic ${stringToBase64(`${username}:${password}`)}`
1550
+ : undefined;
1551
+ const sanitizeHeaders = () => {
1552
+ const currentHeaders = options.getInternalHeaders();
1553
+ for (const key in currentHeaders) {
1554
+ if (is.undefined(currentHeaders[key])) {
1555
+ options.deleteInternalHeader(key);
1556
+ }
1557
+ else if (is.null(currentHeaders[key])) {
1558
+ throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`);
1559
+ }
1531
1560
  }
1532
- else if (is.null(headers[key])) {
1533
- throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`);
1561
+ return currentHeaders;
1562
+ };
1563
+ const getCookieHeader = async (cookieJar) => {
1564
+ if (!cookieJar) {
1565
+ return undefined;
1534
1566
  }
1535
- }
1567
+ const cookieString = await cookieJar.getCookieString(options.url.toString());
1568
+ return is.nonEmptyString(cookieString) ? cookieString : undefined;
1569
+ };
1570
+ const headers = sanitizeHeaders();
1536
1571
  if (options.decompress && is.undefined(headers['accept-encoding'])) {
1537
1572
  const encodings = ['gzip', 'deflate'];
1538
1573
  if (supportsBrotli) {
@@ -1543,34 +1578,93 @@ export default class Request extends Duplex {
1543
1578
  }
1544
1579
  options.setInternalHeader('accept-encoding', encodings.join(', '));
1545
1580
  }
1546
- if (username || password) {
1547
- const credentials = stringToBase64(`${username}:${password}`);
1548
- options.setInternalHeader('authorization', `Basic ${credentials}`);
1581
+ const { username, password } = options;
1582
+ const cookieJar = options.cookieJar;
1583
+ const generatedAuthorizationHeader = getAuthorizationHeader(username, password, authorizationWasInitiallyOmitted);
1584
+ let generatedCookieHeader;
1585
+ if (!is.undefined(generatedAuthorizationHeader)) {
1586
+ options.setInternalHeader('authorization', generatedAuthorizationHeader);
1549
1587
  }
1550
- // Set cookies
1551
- if (cookieJar) {
1552
- const cookieString = await cookieJar.getCookieString(options.url.toString());
1553
- if (is.nonEmptyString(cookieString)) {
1554
- options.setInternalHeader('cookie', cookieString);
1588
+ if (!cookieWasInitiallyOmitted) {
1589
+ generatedCookieHeader = await getCookieHeader(cookieJar);
1590
+ if (!is.undefined(generatedCookieHeader)) {
1591
+ options.setInternalHeader('cookie', generatedCookieHeader);
1555
1592
  }
1556
1593
  }
1557
1594
  let request;
1558
- for (const hook of options.hooks.beforeRequest) {
1559
- // eslint-disable-next-line no-await-in-loop
1560
- const result = await hook(options, { retryCount: this.retryCount });
1561
- if (!is.undefined(result)) {
1562
- // @ts-expect-error Skip the type mismatch to support abstract responses
1563
- request = () => result;
1564
- break;
1595
+ let shouldOmitRequestUrlCredentials = false;
1596
+ const changedState = await options.trackStateMutations(async (changedState) => {
1597
+ for (const hook of options.hooks.beforeRequest) {
1598
+ // eslint-disable-next-line no-await-in-loop
1599
+ const result = await hook(options, { retryCount: this.retryCount });
1600
+ if (!is.undefined(result)) {
1601
+ // @ts-expect-error Skip the type mismatch to support abstract responses
1602
+ request = () => result;
1603
+ break;
1604
+ }
1605
+ }
1606
+ return changedState;
1607
+ });
1608
+ if (request === undefined) {
1609
+ const currentHeaders = options.getInternalHeaders();
1610
+ // `headers.authorization = undefined` / `headers.cookie = undefined` is an
1611
+ // explicit opt-out. Respect that instead of regenerating values from URL
1612
+ // credentials or the cookie jar later in request setup.
1613
+ const isHeaderExplicitlyOmitted = (header) => options.isHeaderExplicitlySet(header) && is.undefined(currentHeaders[header]);
1614
+ const authorizationWasExplicitlyOmitted = isHeaderExplicitlyOmitted('authorization');
1615
+ const cookieWasExplicitlyOmitted = isHeaderExplicitlyOmitted('cookie');
1616
+ const currentAuthorizationHeader = currentHeaders.authorization;
1617
+ const currentCookieHeader = currentHeaders.cookie;
1618
+ sanitizeHeaders();
1619
+ if (!is.undefined(currentHeaders['transfer-encoding']) && !is.undefined(currentHeaders['content-length'])) {
1620
+ options.deleteInternalHeader('content-length');
1621
+ }
1622
+ if (authorizationWasExplicitlyOmitted) {
1623
+ shouldOmitRequestUrlCredentials = true;
1624
+ options.deleteInternalHeader('authorization');
1625
+ if (changedState.has('authorization') && is.undefined(explicitAuthorizationHeader) && !authorizationWasInitiallyOmitted) {
1626
+ delete options.headers.authorization;
1627
+ }
1628
+ }
1629
+ const authorizationHeader = getAuthorizationHeader(options.username, options.password, authorizationWasExplicitlyOmitted);
1630
+ const cookieJar = options.cookieJar;
1631
+ if (changedState.has('authorization')) {
1632
+ // A beforeRequest hook intentionally set the outgoing Authorization header.
1633
+ }
1634
+ else {
1635
+ syncGeneratedHeader('authorization', {
1636
+ currentHeader: currentAuthorizationHeader,
1637
+ explicitHeader: explicitAuthorizationHeader,
1638
+ nextHeader: authorizationHeader,
1639
+ staleGeneratedHeader: generatedAuthorizationHeader,
1640
+ });
1641
+ }
1642
+ if (cookieWasExplicitlyOmitted) {
1643
+ options.deleteInternalHeader('cookie');
1644
+ if (changedState.has('cookie') && is.undefined(explicitCookieHeader) && !cookieWasInitiallyOmitted) {
1645
+ delete options.headers.cookie;
1646
+ }
1647
+ }
1648
+ else if (changedState.has('cookie')) {
1649
+ // A beforeRequest hook intentionally set the outgoing Cookie header.
1650
+ }
1651
+ else {
1652
+ syncGeneratedHeader('cookie', {
1653
+ currentHeader: currentCookieHeader,
1654
+ explicitHeader: explicitCookieHeader,
1655
+ nextHeader: await getCookieHeader(cookieJar),
1656
+ staleGeneratedHeader: generatedCookieHeader,
1657
+ });
1565
1658
  }
1566
- }
1567
- if (!is.undefined(headers['transfer-encoding']) && !is.undefined(headers['content-length'])) {
1568
- // TODO: Throw instead of silently dropping `content-length` in the next major version.
1569
- options.deleteInternalHeader('content-length');
1570
1659
  }
1571
1660
  request ??= options.getRequestFunction();
1572
- const url = options.url;
1661
+ const url = shouldOmitRequestUrlCredentials
1662
+ ? new URL(stripUrlAuth(options.url))
1663
+ : options.url;
1573
1664
  this._requestOptions = options.createNativeRequestOptions();
1665
+ if (shouldOmitRequestUrlCredentials) {
1666
+ this._requestOptions.auth = undefined;
1667
+ }
1574
1668
  if (options.cache) {
1575
1669
  this._requestOptions._request = request;
1576
1670
  this._requestOptions.cache = options.cache;
@@ -31,6 +31,8 @@ export type Agents = {
31
31
  export type Headers = Record<string, string | string[] | undefined>;
32
32
  export type CrossOriginState = {
33
33
  headers: Headers;
34
+ hadCookieJar: boolean;
35
+ cookieWasExplicitlySet: boolean;
34
36
  username: string;
35
37
  password: string;
36
38
  body: unknown;
@@ -91,20 +93,20 @@ export type Hooks = {
91
93
 
92
94
  @default []
93
95
 
94
- **Note:**
96
+ Note:
95
97
  > - This hook must be synchronous.
96
98
 
97
- **Note:**
99
+ Note:
98
100
  > - This is called every time options are merged.
99
101
 
100
- **Note:**
102
+ Note:
101
103
  > - The `options` object may not have the `url` property. To modify it, use a `beforeRequest` hook instead.
102
104
 
103
- **Note:**
105
+ Note:
104
106
  > - This hook is called when a new instance of `Options` is created.
105
107
  > - Do not confuse this with the creation of `Request` or `got(…)`.
106
108
 
107
- **Note:**
109
+ Note:
108
110
  > - When using `got(url)` or `got(url, undefined, defaults)` this hook will **not** be called.
109
111
 
110
112
  This is especially useful in conjunction with `got.extend()` when the input needs custom handling.
@@ -183,10 +185,10 @@ export type Hooks = {
183
185
 
184
186
  @default []
185
187
 
186
- **Note:**
188
+ Note:
187
189
  > - Got will make no further changes to the request before it is sent.
188
190
 
189
- **Note:**
191
+ Note:
190
192
  > - Changing `options.json` or `options.form` has no effect on the request. You should change `options.body` instead. If needed, update the `options.headers` accordingly.
191
193
 
192
194
  @example
@@ -209,7 +211,7 @@ export type Hooks = {
209
211
  );
210
212
  ```
211
213
 
212
- **Example using `context.retryCount`:**
214
+ Example using `context.retryCount`:
213
215
 
214
216
  ```
215
217
  import got from 'got';
@@ -231,7 +233,7 @@ export type Hooks = {
231
233
  });
232
234
  ```
233
235
 
234
- **Tip:**
236
+ Tip:
235
237
  > - 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.
236
238
  > - [Read more about this tip](https://github.com/sindresorhus/got/blob/main/documentation/cache.md#advanced-caching-mechanisms).
237
239
  */
@@ -241,7 +243,7 @@ export type Hooks = {
241
243
 
242
244
  @default []
243
245
 
244
- **Tip:**
246
+ Tip:
245
247
  > - This is especially useful when you want to avoid dead sites.
246
248
 
247
249
  @example
@@ -326,13 +328,13 @@ export type Hooks = {
326
328
 
327
329
  @default []
328
330
 
329
- **Note:**
331
+ Note:
330
332
  > - When using the Stream API, this hook is ignored.
331
333
 
332
- **Note:**
334
+ Note:
333
335
  > - When retrying, the `beforeRequest` hook is called afterwards.
334
336
 
335
- **Note:**
337
+ Note:
336
338
  > - If no retry occurs, the `beforeError` hook is called instead.
337
339
 
338
340
  This hook is especially useful when you want to retrieve the cause of a retry.
@@ -361,31 +363,31 @@ export type Hooks = {
361
363
 
362
364
  @default []
363
365
 
364
- **Return value:**
366
+ Return value:
365
367
  > - `false` - Prevent caching (remaining hooks are skipped)
366
368
  > - `void`/`undefined` - Use default caching behavior (mutations take effect)
367
369
 
368
- **Modifying the response:**
370
+ Modifying the response:
369
371
  > - Hooks can directly mutate response properties like `headers`, `statusCode`, and `statusMessage`
370
372
  > - Mutations to `response.headers` affect how the caching layer decides whether to cache the response and for how long
371
373
  > - Changes are applied to what gets cached
372
374
 
373
- **Note:**
375
+ Note:
374
376
  > - This hook is only called when the `cache` option is enabled.
375
377
 
376
- **Note:**
378
+ Note:
377
379
  > - This hook must be synchronous. It cannot return a Promise. If you need async logic to determine caching behavior, use a `beforeRequest` hook instead.
378
380
 
379
- **Note:**
381
+ Note:
380
382
  > - When returning `false`, remaining hooks are skipped and the response will not be cached.
381
383
 
382
- **Note:**
384
+ Note:
383
385
  > - Returning anything other than `false` or `undefined` will throw a TypeError.
384
386
 
385
- **Note:**
387
+ Note:
386
388
  > - If a hook throws an error, it will be propagated and the request will fail. This is consistent with how other hooks in Got handle errors.
387
389
 
388
- **Note:**
390
+ Note:
389
391
  > - At this stage, the response body has not been read yet - it's still a stream. Properties like `response.body` and `response.rawBody` are not available. You can only inspect/modify response headers and status code.
390
392
 
391
393
  @example
@@ -425,17 +427,17 @@ export type Hooks = {
425
427
 
426
428
  @default []
427
429
 
428
- **Note:**
430
+ Note:
429
431
  > - When using the Stream API, this hook is ignored.
430
432
 
431
- **Note:**
433
+ Note:
432
434
  > - 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.
433
435
  Meanwhile the `init`, `beforeRequest` , `beforeRedirect` as well as already executed `afterResponse` hooks will be skipped.
434
436
 
435
- **Note:**
437
+ Note:
436
438
  > - 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.
437
439
 
438
- **Warning:**
440
+ Warning:
439
441
  > - 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.
440
442
 
441
443
  @example
@@ -788,7 +790,7 @@ export declare function applyUrlOverride(options: Options, url: string | URL, {
788
790
  All parsing methods supported by Got.
789
791
  */
790
792
  export type ResponseType = 'json' | 'buffer' | 'text';
791
- type OptionsToSkip = 'searchParameters' | 'followRedirects' | 'auth' | 'toJSON' | 'merge' | 'isHeaderExplicitlySet' | 'shouldCopyPipedHeader' | 'setPipedHeader' | 'getInternalHeaders' | 'setInternalHeader' | 'deleteInternalHeader' | 'trackStateMutations' | 'clearBody' | 'stripUnchangedCrossOriginState' | 'stripSensitiveHeaders' | 'createNativeRequestOptions' | 'getRequestFunction' | 'freeze';
793
+ type OptionsToSkip = 'searchParameters' | 'followRedirects' | 'auth' | 'toJSON' | 'merge' | 'isHeaderExplicitlySet' | 'shouldCopyPipedHeader' | 'setPipedHeader' | 'getInternalHeaders' | 'setInternalHeader' | 'deleteInternalHeader' | 'trackStateMutations' | 'clearBody' | 'clearUnchangedCookieHeader' | 'restoreCookieHeader' | 'syncCookieHeaderAfterMerge' | 'stripUnchangedCrossOriginState' | 'stripSensitiveHeaders' | 'createNativeRequestOptions' | 'getRequestFunction' | 'freeze';
792
794
  export type InternalsType = Except<Options, OptionsToSkip>;
793
795
  export type OptionsError = NodeJS.ErrnoException & {
794
796
  options?: Options;
@@ -1226,6 +1228,9 @@ export default class Options {
1226
1228
  deleteInternalHeader(name: string): void;
1227
1229
  trackStateMutations<Value>(operation: (changedState: Set<string>) => Promisable<Value>): Promise<Value>;
1228
1230
  clearBody(): void;
1231
+ clearUnchangedCookieHeader(previousState: CrossOriginState | undefined, changedState?: Set<string>): void;
1232
+ restoreCookieHeader(previousState: CrossOriginState | undefined, headers?: Headers): void;
1233
+ syncCookieHeaderAfterMerge(previousState: CrossOriginState | undefined, headers?: Headers): void;
1229
1234
  stripUnchangedCrossOriginState(previousState: CrossOriginState, changedState: Set<string>, { clearBody }?: {
1230
1235
  clearBody?: boolean;
1231
1236
  }): void;
@@ -68,8 +68,8 @@ function hasCredentialInUrl(url, credential) {
68
68
  }
69
69
  export const hasExplicitCredentialInUrlChange = (changedState, url, credential) => (changedState.has(credential)
70
70
  || (changedState.has('url') && url?.[credential] !== ''));
71
- const hasProtocolSlashes = (value) => /^[a-z][a-z\d+.-]*:\/\//i.test(value);
72
- const hasHttpProtocolWithoutSlashes = (value) => /^https?:(?!\/\/)/i.test(value);
71
+ const hasProtocolSlashes = (value) => /^[a-z][\d+\-.a-z]*:\/\//iv.test(value);
72
+ const hasHttpProtocolWithoutSlashes = (value) => /^https?:(?!\/\/)/iv.test(value);
73
73
  export function applyUrlOverride(options, url, { username, password } = {}) {
74
74
  if (is.string(url) && options.url) {
75
75
  url = new URL(url, options.url).toString();
@@ -486,7 +486,7 @@ export default class Options {
486
486
  // would get merged. Instead we set the `searchParams` first, then
487
487
  // `url.searchParams` is overwritten as expected.
488
488
  //
489
- /* eslint-disable no-unsafe-finally */
489
+ /* eslint-disable no-unsafe-finally -- `finally` is used intentionally here to ensure `url` is always set last, overwriting any merged searchParams */
490
490
  try {
491
491
  if (is.plainObject(input)) {
492
492
  try {
@@ -912,16 +912,14 @@ export default class Options {
912
912
  this.#internals.cookieJar = undefined;
913
913
  return;
914
914
  }
915
- let { setCookie, getCookieString } = value;
915
+ const { setCookie, getCookieString } = value;
916
916
  assert.function(setCookie);
917
917
  assert.function(getCookieString);
918
918
  /* istanbul ignore next: Horrible `tough-cookie` v3 check */
919
919
  if (setCookie.length === 4 && getCookieString.length === 0) {
920
- setCookie = promisify(setCookie.bind(value));
921
- getCookieString = promisify(getCookieString.bind(value));
922
920
  this.#internals.cookieJar = {
923
- setCookie,
924
- getCookieString: getCookieString,
921
+ setCookie: promisify(setCookie.bind(value)),
922
+ getCookieString: promisify(getCookieString.bind(value)),
925
923
  };
926
924
  }
927
925
  else {
@@ -1408,6 +1406,35 @@ export default class Options {
1408
1406
  this.deleteInternalHeader(header);
1409
1407
  }
1410
1408
  }
1409
+ clearUnchangedCookieHeader(previousState, changedState) {
1410
+ if (previousState?.hadCookieJar
1411
+ && this.cookieJar === undefined
1412
+ && !this.isHeaderExplicitlySet('cookie')
1413
+ && !changedState?.has('cookie')
1414
+ && this.headers.cookie === previousState.headers.cookie) {
1415
+ this.deleteInternalHeader('cookie');
1416
+ }
1417
+ }
1418
+ restoreCookieHeader(previousState, headers) {
1419
+ if (!previousState) {
1420
+ return;
1421
+ }
1422
+ if (Object.hasOwn(headers ?? {}, 'cookie')) {
1423
+ return;
1424
+ }
1425
+ if (previousState.cookieWasExplicitlySet) {
1426
+ this.headers.cookie = previousState.headers.cookie;
1427
+ return;
1428
+ }
1429
+ delete this.headers.cookie;
1430
+ if (previousState.headers.cookie !== undefined) {
1431
+ this.setInternalHeader('cookie', previousState.headers.cookie);
1432
+ }
1433
+ }
1434
+ syncCookieHeaderAfterMerge(previousState, headers) {
1435
+ this.restoreCookieHeader(previousState, headers);
1436
+ this.clearUnchangedCookieHeader(previousState);
1437
+ }
1411
1438
  stripUnchangedCrossOriginState(previousState, changedState, { clearBody = true } = {}) {
1412
1439
  const headers = this.getInternalHeaders();
1413
1440
  const url = this.#internals.url;
@@ -1792,11 +1819,11 @@ export default class Options {
1792
1819
  this.#internals.resolveBodyOnly = value;
1793
1820
  }
1794
1821
  /**
1795
- @internal
1796
1822
  Returns a `Stream` instead of a `Promise`.
1797
1823
  Set internally by `got.stream()`.
1798
1824
 
1799
1825
  @default false
1826
+ @internal
1800
1827
  */
1801
1828
  get isStream() {
1802
1829
  return this.#internals.isStream;
@@ -1945,7 +1972,7 @@ export default class Options {
1945
1972
  }
1946
1973
  let unixSocketGroups;
1947
1974
  if (unixSocketPath !== undefined) {
1948
- unixSocketGroups = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`)?.groups;
1975
+ unixSocketGroups = /^(?<socketPath>[^:]+):(?<path>.+)$/v.exec(`${url.pathname}${url.search}`)?.groups;
1949
1976
  }
1950
1977
  const unixOptions = unixSocketGroups
1951
1978
  ? { socketPath: unixSocketGroups.socketPath, path: unixSocketGroups.path, host: '' }
@@ -2113,6 +2140,8 @@ export default class Options {
2113
2140
  }
2114
2141
  export const snapshotCrossOriginState = (options) => ({
2115
2142
  headers: { ...options.getInternalHeaders() },
2143
+ hadCookieJar: options.cookieJar !== undefined,
2144
+ cookieWasExplicitlySet: options.isHeaderExplicitlySet('cookie'),
2116
2145
  username: options.username,
2117
2146
  password: options.password,
2118
2147
  body: options.body,
@@ -1,9 +1,56 @@
1
+ const splitHeaderValue = (value, separator) => {
2
+ const values = [];
3
+ let current = '';
4
+ let inQuotes = false;
5
+ let inReference = false;
6
+ let isEscaped = false;
7
+ for (const character of value) {
8
+ if (inQuotes && isEscaped) {
9
+ current += character;
10
+ isEscaped = false;
11
+ continue;
12
+ }
13
+ if (inQuotes && character === '\\') {
14
+ current += character;
15
+ isEscaped = true;
16
+ continue;
17
+ }
18
+ if (character === '"') {
19
+ inQuotes = !inQuotes;
20
+ current += character;
21
+ continue;
22
+ }
23
+ if (!inQuotes && character === '<') {
24
+ inReference = true;
25
+ current += character;
26
+ continue;
27
+ }
28
+ if (!inQuotes && character === '>') {
29
+ inReference = false;
30
+ current += character;
31
+ continue;
32
+ }
33
+ // Link headers use both quoted strings and <URI-reference> values, so raw
34
+ // splitting on `,` / `;` would break valid values containing those characters.
35
+ if (!inQuotes && !inReference && character === separator) {
36
+ values.push(current);
37
+ current = '';
38
+ continue;
39
+ }
40
+ current += character;
41
+ }
42
+ if (inQuotes || isEscaped) {
43
+ throw new Error(`Failed to parse Link header: ${value}`);
44
+ }
45
+ values.push(current);
46
+ return values;
47
+ };
1
48
  export default function parseLinkHeader(link) {
2
49
  const parsed = [];
3
- const items = link.split(',');
50
+ const items = splitHeaderValue(link, ',');
4
51
  for (const item of items) {
5
52
  // https://tools.ietf.org/html/rfc5988#section-5
6
- const [rawUriReference, ...rawLinkParameters] = item.split(';');
53
+ const [rawUriReference, ...rawLinkParameters] = splitHeaderValue(item, ';');
7
54
  const trimmedUriReference = rawUriReference.trim();
8
55
  // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
9
56
  if (trimmedUriReference[0] !== '<' || trimmedUriReference.at(-1) !== '>') {
@@ -11,6 +58,9 @@ export default function parseLinkHeader(link) {
11
58
  }
12
59
  const reference = trimmedUriReference.slice(1, -1);
13
60
  const parameters = {};
61
+ if (reference.includes('<') || reference.includes('>')) {
62
+ throw new Error(`Invalid format of the Link header reference: ${trimmedUriReference}`);
63
+ }
14
64
  if (rawLinkParameters.length === 0) {
15
65
  throw new Error(`Unexpected end of Link header parameters: ${rawLinkParameters.join(';')}`);
16
66
  }
@@ -81,7 +81,7 @@ export default function timedOut(request, delays, options) {
81
81
  const { socketPath } = request;
82
82
  /* istanbul ignore next: hard to test */
83
83
  if (socket.connecting) {
84
- const hasPath = Boolean(socketPath ?? net.isIP(hostname ?? host ?? '') !== 0);
84
+ const hasPath = Boolean(socketPath ?? (net.isIP(hostname ?? host ?? '') !== 0));
85
85
  if (hasLookup && !hasPath && socket.address().address === undefined) {
86
86
  const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup');
87
87
  once(socket, 'lookup', cancelTimeout);
@@ -1,4 +1,4 @@
1
- export default function isUnixSocketURL(url: URL): boolean;
1
+ export default function isUnixSocketUrl(url: URL): boolean;
2
2
  /**
3
3
  Extract the socket path from a UNIX socket URL.
4
4
 
@@ -1,5 +1,4 @@
1
- // eslint-disable-next-line @typescript-eslint/naming-convention
2
- export default function isUnixSocketURL(url) {
1
+ export default function isUnixSocketUrl(url) {
3
2
  return url.protocol === 'unix:' || url.hostname === 'unix';
4
3
  }
5
4
  /**
@@ -18,8 +17,8 @@ getUnixSocketPath(new URL('http://example.com'));
18
17
  ```
19
18
  */
20
19
  export function getUnixSocketPath(url) {
21
- if (!isUnixSocketURL(url)) {
20
+ if (!isUnixSocketUrl(url)) {
22
21
  return undefined;
23
22
  }
24
- return /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`)?.groups?.socketPath;
23
+ return /^(?<socketPath>[^:]+):/v.exec(`${url.pathname}${url.search}`)?.groups?.socketPath;
25
24
  }
@@ -180,6 +180,7 @@ const create = (defaults) => {
180
180
  }
181
181
  if (optionsToMerge === response.request.options) {
182
182
  normalizedOptions = response.request.options;
183
+ normalizedOptions.clearUnchangedCookieHeader(previousState, changedState);
183
184
  if (previousUrl) {
184
185
  const nextUrl = normalizedOptions.url;
185
186
  if (nextUrl && !isSameOrigin(previousUrl, nextUrl)) {
@@ -192,10 +193,15 @@ const create = (defaults) => {
192
193
  const hasExplicitBody = (Object.hasOwn(optionsToMerge, 'body') && optionsToMerge.body !== undefined)
193
194
  || (Object.hasOwn(optionsToMerge, 'json') && optionsToMerge.json !== undefined)
194
195
  || (Object.hasOwn(optionsToMerge, 'form') && optionsToMerge.form !== undefined);
196
+ const clearsCookieJar = Object.hasOwn(optionsToMerge, 'cookieJar') && optionsToMerge.cookieJar === undefined;
195
197
  if (hasExplicitBody) {
196
198
  normalizedOptions.clearBody();
197
199
  }
200
+ if (clearsCookieJar) {
201
+ normalizedOptions.cookieJar = undefined;
202
+ }
198
203
  normalizedOptions.merge(optionsToMerge);
204
+ normalizedOptions.syncCookieHeaderAfterMerge(previousState, optionsToMerge.headers);
199
205
  try {
200
206
  assert.any([is.string, is.urlInstance, is.undefined], optionsToMerge.url);
201
207
  }
@@ -59,10 +59,9 @@ export type ExtendOptions = {
59
59
  */
60
60
  mutableDefaults?: boolean;
61
61
  } & Except<OptionsInit, 'url'>;
62
- type OptionsInitWithoutUrl = Except<OptionsInit, 'url'>;
63
- export type StrictOptions = Except<OptionsInitWithoutUrl, 'responseType' | 'resolveBodyOnly'>;
64
- export type StreamOptions = OptionsInitWithoutUrl;
65
- export type OptionsWithPagination<T = unknown, R = unknown> = Merge<OptionsInitWithoutUrl, {
62
+ export type StreamOptions = Except<OptionsInit, 'url'>;
63
+ export type StrictOptions = Except<StreamOptions, 'responseType' | 'resolveBodyOnly'>;
64
+ export type OptionsWithPagination<T = unknown, R = unknown> = Merge<StreamOptions, {
66
65
  pagination?: PaginationOptions<T, R>;
67
66
  }>;
68
67
  /**
@@ -188,9 +187,9 @@ export type GotRequestFunction<U extends ExtendOptions = Record<string, unknown>
188
187
  (options: OptionsOfTextResponseBodyOnly): RequestPromise<string>;
189
188
  <T>(options: OptionsOfJSONResponseBodyOnly): RequestPromise<T>;
190
189
  (options: OptionsOfBufferResponseBodyOnly): RequestPromise<Uint8Array<ArrayBuffer>>;
191
- (url: string | URL, options?: OptionsInitWithoutUrl): RequestPromise | Request;
192
- (options: OptionsInitWithoutUrl): RequestPromise | Request;
193
- (url: undefined, options: undefined, defaults: Options): RequestPromise | Request;
190
+ (url: string | URL, options?: StreamOptions): RequestPromise;
191
+ (options: StreamOptions): RequestPromise;
192
+ (url: undefined, options: undefined, defaults: Options): RequestPromise;
194
193
  };
195
194
  /**
196
195
  All available HTTP request methods provided by Got.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "15.0.0",
3
+ "version": "15.0.2",
4
4
  "description": "Human-friendly and powerful HTTP request library for Node.js",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
package/readme.md CHANGED
@@ -254,13 +254,11 @@ By default, Got will retry on failure. To disable this option, set [`options.ret
254
254
  [s3]: https://www.npmjs.com/package/superagent
255
255
 
256
256
  <!-- COVERAGE -->
257
- [gc]: https://img.shields.io/coveralls/github/sindresorhus/got?color=0b9062&label
258
257
  [kc]: https://img.shields.io/codecov/c/github/sindresorhus/ky?color=0b9062&label
259
258
  [nc]: https://img.shields.io/coveralls/github/bitinn/node-fetch?color=0b9062&label
260
259
  [ac]: https://img.shields.io/coveralls/github/mzabriskie/axios?color=0b9062&label
261
260
  [sc]: https://img.shields.io/codecov/c/github/visionmedia/superagent?color=0b9062&label
262
261
 
263
- [g4]: https://coveralls.io/github/sindresorhus/got
264
262
  [k4]: https://codecov.io/gh/sindresorhus/ky
265
263
  [n4]: https://coveralls.io/github/bitinn/node-fetch
266
264
  [a4]: https://coveralls.io/github/mzabriskie/axios
@@ -342,7 +340,6 @@ By default, Got will retry on failure. To disable this option, set [`options.ret
342
340
  [k10]: https://github.com/sindresorhus/ky
343
341
  [n10]: https://github.com/node-fetch/node-fetch
344
342
  [a10]: https://github.com/axios/axios
345
- [s10]: https://github.com/visionmedia/superagent
346
343
 
347
344
  <!-- LAST COMMIT -->
348
345
  [glc]: https://img.shields.io/github/last-commit/sindresorhus/got?color=gray&label