Skip to content

Commit

Permalink
Require Node.js 16
Browse files Browse the repository at this point in the history
Fixes #989
Fixes #1581
  • Loading branch information
sindresorhus committed May 27, 2023
1 parent 1cefe8b commit 52a1063
Show file tree
Hide file tree
Showing 28 changed files with 338 additions and 350 deletions.
1 change: 0 additions & 1 deletion benchmark/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {URL} from 'node:url';
import https from 'node:https';
/// import axios from 'axios';
import Benchmark from 'benchmark';
Expand Down
14 changes: 6 additions & 8 deletions documentation/3-streams.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,27 @@ This constructor takes the same arguments as the Got promise.
> - If there's no body on purpose, remember to `stream.end()` or set the body option to an empty string.
```js
import {promisify} from 'node:util';
import stream from 'node:stream';
import {pipeline as streamPipeline} from 'node:stream/promises';
import fs from 'node:fs';
import got from 'got';

const pipeline = promisify(stream.pipeline);

// This example streams the GET response of a URL to a file.
await pipeline(
await streamPipeline(
got.stream('https://sindresorhus.com'),
fs.createWriteStream('index.html')
);

// For POST, PUT, PATCH, and DELETE methods, `got.stream` returns a `stream.Writable`.
// This example POSTs the contents of a file to a URL.
await pipeline(
await streamPipeline(
fs.createReadStream('index.html'),
got.stream.post('https://sindresorhus.com'),
new stream.PassThrough()
);

// In order to POST, PUT, PATCH, or DELETE without a request body, explicitly specify an empty body:
await pipeline(
await streamPipeline(
got.stream.post('https://sindresorhus.com', { body: '' }),
new stream.PassThrough()
)
Expand Down Expand Up @@ -181,7 +179,7 @@ Whether the socket was used for other previous requests.
This is emitted when a HTTP response is received.

```js
import {pipeline} from 'node:stream/promises';
import {pipeline as streamPipeline} from 'node:stream/promises';
import {createWriteStream} from 'node:fs';
import got from 'got';

Expand All @@ -202,7 +200,7 @@ readStream.on('response', async response => {
readStream.off('error', onError);

try {
await pipeline(
await streamPipeline(
readStream,
createWriteStream('image.png')
);
Expand Down
4 changes: 2 additions & 2 deletions documentation/migration-guides/nodejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ Well, it's easy as that:

```js
import got from 'got';
import stream from 'node:stream';
import {pipeline as streamPipeline} from 'node:stream/promises';
import fs from 'node:fs';

await stream.promises.pipeline(
await streamPipeline(
fs.createReadStream('article.txt'),
got.stream.post('https://httpbin.org/anything'),
fs.createWriteStream('httpbin.txt')
Expand Down
7 changes: 2 additions & 5 deletions documentation/migration-guides/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,12 @@ http.createServer((serverRequest, serverResponse) => {
The cool feature here is that Request can proxy headers with the stream, but Got can do that too!

```js
import {promisify} from 'node:util';
import stream from 'node:stream';
import {pipeline as streamPipeline} from 'node:stream/promises';
import got from 'got';

const pipeline = promisify(stream.pipeline);

const server = http.createServer(async (serverRequest, serverResponse) => {
if (serverRequest.url === '/doodle.png') {
await pipeline(
await streamPipeline(
got.stream('https://example.com/doodle.png'),
serverResponse
);
Expand Down
4 changes: 2 additions & 2 deletions documentation/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The [Stream API](3-streams.md) allows to leverage [Node.js Streams](https://node

```js
import fs from 'node:fs';
import {pipeline} from 'node:stream/promises';
import {pipeline as streamPipeline} from 'node:stream/promises';
import got from 'got';

const url = 'https://httpbin.org/anything';
Expand All @@ -81,7 +81,7 @@ const gotStream = got.stream.post(url, options);
const outStream = fs.createWriteStream('anything.json');

try {
await pipeline(gotStream, outStream);
await streamPipeline(gotStream, outStream);
} catch (error) {
console.error(error);
}
Expand Down
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"repository": "sindresorhus/got",
"funding": "https://github.com/sindresorhus/got?sponsor=1",
"type": "module",
"exports": "./dist/source/index.js",
"types": "./dist/source/index.d.ts",
"exports": {
"types": "./dist/source/index.d.ts",
"default": "./dist/source/index.js"
},
"engines": {
"node": ">=14.16"
"node": ">=16"
},
"scripts": {
"test": "xo && tsc --noEmit && ava",
Expand Down Expand Up @@ -99,8 +101,8 @@
"tough-cookie": "4.1.2",
"ts-node": "^10.8.2",
"type-fest": "^3.6.1",
"typescript": "~4.9.5",
"xo": "^0.53.1"
"typescript": "^5.0.4",
"xo": "^0.54.2"
},
"sideEffects": false,
"ava": {
Expand Down Expand Up @@ -135,8 +137,6 @@
"rules": {
"@typescript-eslint/no-empty-function": "off",
"n/no-deprecated-api": "off",
"n/prefer-global/url": "off",
"n/prefer-global/url-search-params": "off",
"@typescript-eslint/no-implicit-any-catch": "off",
"unicorn/prefer-node-protocol": "off",
"ava/assertion-arguments": "off",
Expand All @@ -146,6 +146,8 @@
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/await-thenable": "off",
"@typescript-eslint/no-redundant-type-constituents": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/promise-function-async": "off",
"no-lone-blocks": "off",
"unicorn/no-await-expression-member": "off"
}
Expand Down
14 changes: 8 additions & 6 deletions source/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import process from 'node:process';
import {Buffer} from 'node:buffer';
import {Duplex, type Readable} from 'node:stream';
import {URL, URLSearchParams} from 'node:url';
import http, {ServerResponse} from 'node:http';
import type {ClientRequest, RequestOptions} from 'node:http';
import type {Socket} from 'node:net';
Expand Down Expand Up @@ -46,6 +45,8 @@ import {
AbortError,
} from './errors.js';

const {buffer: getStreamAsBuffer} = getStream;

type Error = NodeJS.ErrnoException;

export type Progress = {
Expand All @@ -54,8 +55,6 @@ export type Progress = {
total?: number;
};

const {buffer: getBuffer} = getStream;

const supportsBrotli = is.string(process.versions.brotli);

const methodsWithoutBody: ReadonlySet<string> = new Set(['GET', 'HEAD']);
Expand Down Expand Up @@ -176,7 +175,7 @@ export default class Request extends Duplex implements RequestEvents<Request> {
private _isFromCache?: boolean;
private _cannotHaveBody: boolean;
private _triggerRead: boolean;
declare private _jobs: Array<() => void>;
declare private readonly _jobs: Array<() => void>;
private _cancelTimeouts: () => void;
private readonly _removeListeners: () => void;
private _nativeResponse?: IncomingMessageWithTimings;
Expand Down Expand Up @@ -877,7 +876,11 @@ export default class Request extends Duplex implements RequestEvents<Request> {

try {
// Errors are emitted via the `error` event
const rawBody = await getBuffer(from);
const rawBody = await getStreamAsBuffer(from);

// TODO: Switch to this:
// let rawBody = await from.toArray();
// rawBody = Buffer.concat(rawBody);

// On retry Request is destroyed with no error, therefore the above will successfully resolve.
// So in order to check if this was really successfull, we need to check if it has been properly ended.
Expand Down Expand Up @@ -992,7 +995,6 @@ export default class Request extends Duplex implements RequestEvents<Request> {
// We only need to implement the error handler in order to support HTTP2 caching.
// The result will be a promise anyway.
// @ts-expect-error ignore
// eslint-disable-next-line @typescript-eslint/promise-function-async
result.once = (event: string, handler: (reason: unknown) => void) => {
if (event === 'error') {
(async () => {
Expand Down
3 changes: 1 addition & 2 deletions source/core/options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import process from 'node:process';
import type {Buffer} from 'node:buffer';
import {promisify, inspect} from 'node:util';
import {URL, URLSearchParams} from 'node:url';
import {checkServerIdentity} from 'node:tls';
// DO NOT use destructuring for `https.request` and `http.request` as it's not compatible with `nock`.
import http from 'node:http';
Expand Down Expand Up @@ -976,7 +975,7 @@ const init = (options: OptionsInit, withOptions: OptionsInit, self: Options): vo

export default class Options {
private _unixOptions?: NativeRequestOptions;
private _internals: InternalsType;
private readonly _internals: InternalsType;
private _merging: boolean;
private readonly _init: OptionsInit[];

Expand Down
1 change: 0 additions & 1 deletion source/core/response.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {Buffer} from 'node:buffer';
import type {URL} from 'node:url';
import type {IncomingMessageWithTimings, Timings} from '@szmarczak/http-timer';
import {RequestError} from './errors.js';
import type {ParseJsonFunction, ResponseType} from './options.js';
Expand Down
18 changes: 9 additions & 9 deletions source/core/timed-out.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ export default function timedOut(request: ClientRequest, delays: Delays, options
}
});

if (typeof delays.request !== 'undefined') {
if (delays.request !== undefined) {
const cancelTimeout = addTimeout(delays.request, timeoutHandler, 'request');

once(request, 'response', (response: IncomingMessage): void => {
once(response, 'end', cancelTimeout);
});
}

if (typeof delays.socket !== 'undefined') {
if (delays.socket !== undefined) {
const {socket} = delays;

const socketTimeoutHandler = (): void => {
Expand All @@ -115,10 +115,10 @@ export default function timedOut(request: ClientRequest, delays: Delays, options
});
}

const hasLookup = typeof delays.lookup !== 'undefined';
const hasConnect = typeof delays.connect !== 'undefined';
const hasSecureConnect = typeof delays.secureConnect !== 'undefined';
const hasSend = typeof delays.send !== 'undefined';
const hasLookup = delays.lookup !== undefined;
const hasConnect = delays.connect !== undefined;
const hasSecureConnect = delays.secureConnect !== undefined;
const hasSend = delays.send !== undefined;
if (hasLookup || hasConnect || hasSecureConnect || hasSend) {
once(request, 'socket', (socket: net.Socket): void => {
const {socketPath} = request as ClientRequest & {socketPath?: string};
Expand All @@ -127,7 +127,7 @@ export default function timedOut(request: ClientRequest, delays: Delays, options
if (socket.connecting) {
const hasPath = Boolean(socketPath ?? net.isIP(hostname ?? host ?? '') !== 0);

if (hasLookup && !hasPath && typeof (socket.address() as net.AddressInfo).address === 'undefined') {
if (hasLookup && !hasPath && (socket.address() as net.AddressInfo).address === undefined) {
const cancelTimeout = addTimeout(delays.lookup!, timeoutHandler, 'lookup');
once(socket, 'lookup', cancelTimeout);
}
Expand Down Expand Up @@ -168,14 +168,14 @@ export default function timedOut(request: ClientRequest, delays: Delays, options
});
}

if (typeof delays.response !== 'undefined') {
if (delays.response !== undefined) {
once(request, 'upload-complete', (): void => {
const cancelTimeout = addTimeout(delays.response!, timeoutHandler, 'response');
once(request, 'response', cancelTimeout);
});
}

if (typeof delays.read !== 'undefined') {
if (delays.read !== undefined) {
once(request, 'response', (response: IncomingMessage): void => {
const cancelTimeout = addTimeout(delays.read!, timeoutHandler, 'read');
once(response, 'end', cancelTimeout);
Expand Down
2 changes: 0 additions & 2 deletions source/core/utils/is-unix-socket-url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type {URL} from 'url';

// eslint-disable-next-line @typescript-eslint/naming-convention
export default function isUnixSocketURL(url: URL) {
return url.protocol === 'unix:' || url.hostname === 'unix';
Expand Down
3 changes: 0 additions & 3 deletions source/core/utils/options-to-url.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/* istanbul ignore file: deprecated */
import {URL} from 'node:url';

// eslint-disable-next-line @typescript-eslint/naming-convention
export type URLOptions = {
href?: string;
Expand Down
2 changes: 1 addition & 1 deletion source/core/utils/url-to-options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {URL, UrlWithStringQuery} from 'node:url';
import type {UrlWithStringQuery} from 'node:url';
import is from '@sindresorhus/is';

// TODO: Deprecate legacy URL at some point
Expand Down
1 change: 0 additions & 1 deletion source/create.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type {URL} from 'node:url';
import is, {assert} from '@sindresorhus/is';
import asPromise from './as-promise/index.js';
import type {
Expand Down
1 change: 0 additions & 1 deletion source/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {Buffer} from 'node:buffer';
import type {URL} from 'node:url';
import type {CancelableRequest} from './as-promise/types.js';
import type {Response} from './core/response.js';
import type Options from './core/options.js';
Expand Down
Loading

0 comments on commit 52a1063

Please sign in to comment.