diff options
author | 2023-03-03 14:24:12 -0800 | |
---|---|---|
committer | 2023-03-03 14:24:12 -0800 | |
commit | 0f8f484e21e3ebafaf62370421f6296eaca262fe (patch) | |
tree | 8f5adeacb07ab24a20b7e8c764631e19244ec551 | |
parent | 7e5dddd2fa3d940ebfff0ba2f24d1789f41212ee (diff) | |
download | bun-0f8f484e21e3ebafaf62370421f6296eaca262fe.tar.gz bun-0f8f484e21e3ebafaf62370421f6296eaca262fe.tar.zst bun-0f8f484e21e3ebafaf62370421f6296eaca262fe.zip |
Improve types for `node:http` (#2284)
* Document node:http
* Fix test
* Fix default
* Fix default
-rw-r--r-- | packages/bun-types/globals.d.ts | 8 | ||||
-rw-r--r-- | packages/bun-types/http.d.ts | 935 | ||||
-rw-r--r-- | packages/bun-types/net.d.ts | 418 | ||||
-rw-r--r-- | packages/bun-types/stream.d.ts | 41 | ||||
-rw-r--r-- | packages/bun-types/tests/http.test-d.ts | 27 | ||||
-rw-r--r-- | src/bun.js/http.exports.js | 4 | ||||
-rw-r--r-- | test/bun.js/node-http.test.ts | 20 |
7 files changed, 1204 insertions, 249 deletions
diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts index 72c8495dc..e44bcf43d 100644 --- a/packages/bun-types/globals.d.ts +++ b/packages/bun-types/globals.d.ts @@ -1316,17 +1316,17 @@ declare var performance: { * Cancel a repeating timer by its timer ID. * @param id timer id */ -declare function clearInterval(id?: number): void; +declare function clearInterval(id?: number | Timer): void; /** * Cancel a delayed function call by its timer ID. * @param id timer id */ -declare function clearTimeout(id?: number): void; +declare function clearTimeout(id?: number | Timer): void; /** * Cancel an immediate function call by its immediate ID. * @param id immediate id */ -declare function clearImmediate(id?: number): void; +declare function clearImmediate(id?: number | Timer): void; // declare function createImageBitmap(image: ImageBitmapSource, options?: ImageBitmapOptions): Promise<ImageBitmap>; // declare function createImageBitmap(image: ImageBitmapSource, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise<ImageBitmap>; /** @@ -1981,6 +1981,8 @@ interface AbortSignal extends EventTarget { declare var AbortSignal: { prototype: AbortSignal; new (): AbortSignal; + abort(reason?: any): AbortSignal; + timeout(milliseconds: number): AbortSignal; }; // type AlgorithmIdentifier = Algorithm | string; diff --git a/packages/bun-types/http.d.ts b/packages/bun-types/http.d.ts index a282b621d..30571b4b6 100644 --- a/packages/bun-types/http.d.ts +++ b/packages/bun-types/http.d.ts @@ -41,6 +41,9 @@ */ declare module "http" { import * as stream from "node:stream"; + + import { Socket, TcpSocketConnectOpts, Server as NetServer } from "node:net"; + // incoming headers will never contain number interface IncomingHttpHeaders extends Dict<string | string[]> { accept?: string | undefined; @@ -111,26 +114,757 @@ declare module "http" { type OutgoingHttpHeader = number | string | string[]; interface OutgoingHttpHeaders extends Dict<OutgoingHttpHeader> {} interface ClientRequestArgs { - signal?: AbortSignal | undefined; - protocol?: string | null | undefined; + agent?: Agent | boolean | undefined; + auth?: string | null | undefined; + // createConnection?: + // | (( + // options: ClientRequestArgs, + // oncreate: (err: Error, socket: Socket) => void, + // ) => Socket) + // | undefined; + defaultPort?: number | string | undefined; + family?: number | undefined; + headers?: OutgoingHttpHeaders | undefined; + // hints?: LookupOptions["hints"]; host?: string | null | undefined; hostname?: string | null | undefined; - family?: number | undefined; - port?: number | string | null | undefined; - defaultPort?: number | string | undefined; + // insecureHTTPParser?: boolean | undefined; localAddress?: string | undefined; - socketPath?: string | undefined; + // localPort?: number | undefined; + // lookup?: LookupFunction | undefined; /** * @default 8192 */ maxHeaderSize?: number | undefined; method?: string | undefined; path?: string | null | undefined; - headers?: OutgoingHttpHeaders | undefined; - auth?: string | null | undefined; - timeout?: number | undefined; + port?: number | string | null | undefined; + protocol?: string | null | undefined; setHost?: boolean | undefined; + signal?: AbortSignal | undefined; + socketPath?: string | undefined; + timeout?: number | undefined; + // uniqueHeaders?: Array<string | string[]> | undefined; + } + + interface ServerOptions< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse = typeof ServerResponse, + > { + /** + * Specifies the `IncomingMessage` class to be used. Useful for extending the original `IncomingMessage`. + */ + IncomingMessage?: Request | undefined; + /** + * Specifies the `ServerResponse` class to be used. Useful for extending the original `ServerResponse`. + */ + ServerResponse?: Response | undefined; + /** + * Sets the timeout value in milliseconds for receiving the entire request from the client. + * @see Server.requestTimeout for more information. + * @default 300000 + * @since v18.0.0 + */ + requestTimeout?: number | undefined; + /** + * The number of milliseconds of inactivity a server needs to wait for additional incoming data, + * after it has finished writing the last response, before a socket will be destroyed. + * @see Server.keepAliveTimeout for more information. + * @default 5000 + * @since v18.0.0 + */ + keepAliveTimeout?: number | undefined; + /** + * Sets the interval value in milliseconds to check for request and headers timeout in incomplete requests. + * @default 30000 + */ + connectionsCheckingInterval?: number | undefined; + /** + * Use an insecure HTTP parser that accepts invalid HTTP headers when `true`. + * Using the insecure parser should be avoided. + * See --insecure-http-parser for more information. + * @default false + */ + insecureHTTPParser?: boolean | undefined; + /** + * Optionally overrides the value of + * `--max-http-header-size` for requests received by this server, i.e. + * the maximum length of request headers in bytes. + * @default 16384 + * @since v13.3.0 + */ + maxHeaderSize?: number | undefined; + /** + * If set to `true`, it disables the use of Nagle's algorithm immediately after a new incoming connection is received. + * @default true + * @since v16.5.0 + */ + noDelay?: boolean | undefined; + /** + * If set to `true`, it enables keep-alive functionality on the socket immediately after a new incoming connection is received, + * similarly on what is done in `socket.setKeepAlive([enable][, initialDelay])`. + * @default false + * @since v16.5.0 + */ + keepAlive?: boolean | undefined; + /** + * If set to a positive number, it sets the initial delay before the first keepalive probe is sent on an idle socket. + * @default 0 + * @since v16.5.0 + */ + keepAliveInitialDelay?: number | undefined; + /** + * A list of response headers that should be sent only once. + * If the header's value is an array, the items will be joined using `; `. + */ + uniqueHeaders?: Array<string | string[]> | undefined; } + type RequestListener< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse = typeof ServerResponse, + > = ( + req: InstanceType<Request>, + res: InstanceType<Response> & { req: InstanceType<Request> }, + ) => void; + /** + * @since v0.1.17 + */ + var Server: Server; + interface Server< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse = typeof ServerResponse, + > extends NetServer { + prototype: Server<Request, Response>; + + new <Req extends typeof IncomingMessage, Res extends typeof ServerResponse>( + requestListener?: RequestListener<Req, Res>, + ): Server<Req, Res>; + new <Req extends typeof IncomingMessage, Res extends typeof ServerResponse>( + options: ServerOptions<Req, Res>, + requestListener?: RequestListener<Req, Res>, + ): Server<Req, Res>; + /** + * Sets the timeout value for sockets, and emits a `'timeout'` event on + * the Server object, passing the socket as an argument, if a timeout + * occurs. + * + * If there is a `'timeout'` event listener on the Server object, then it + * will be called with the timed-out socket as an argument. + * + * By default, the Server does not timeout sockets. However, if a callback + * is assigned to the Server's `'timeout'` event, timeouts must be handled + * explicitly. + * @since v0.9.12 + * @param [msecs=0 (no timeout)] + */ + // setTimeout(msecs?: number, callback?: () => void): this; + // setTimeout(callback: () => void): this; + /** + * Limits maximum incoming headers count. If set to 0, no limit will be applied. + * @since v0.7.0 + */ + // maxHeadersCount: number | null; + /** + * The maximum number of requests socket can handle + * before closing keep alive connection. + * + * A value of `0` will disable the limit. + * + * When the limit is reached it will set the `Connection` header value to `close`, + * but will not actually close the connection, subsequent requests sent + * after the limit is reached will get `503 Service Unavailable` as a response. + * @since v16.10.0 + */ + // maxRequestsPerSocket: number | null; + /** + * The number of milliseconds of inactivity before a socket is presumed + * to have timed out. + * + * A value of `0` will disable the timeout behavior on incoming connections. + * + * The socket timeout logic is set up on connection, so changing this + * value only affects new connections to the server, not any existing connections. + * @since v0.9.12 + */ + // timeout: number; + /** + * Limit the amount of time the parser will wait to receive the complete HTTP + * headers. + * + * If the timeout expires, the server responds with status 408 without + * forwarding the request to the request listener and then closes the connection. + * + * It must be set to a non-zero value (e.g. 120 seconds) to protect against + * potential Denial-of-Service attacks in case the server is deployed without a + * reverse proxy in front. + * @since v11.3.0, v10.14.0 + */ + // headersTimeout: number; + /** + * The number of milliseconds of inactivity a server needs to wait for additional + * incoming data, after it has finished writing the last response, before a socket + * will be destroyed. If the server receives new data before the keep-alive + * timeout has fired, it will reset the regular inactivity timeout, i.e.,`server.timeout`. + * + * A value of `0` will disable the keep-alive timeout behavior on incoming + * connections. + * A value of `0` makes the http server behave similarly to Node.js versions prior + * to 8.0.0, which did not have a keep-alive timeout. + * + * The socket timeout logic is set up on connection, so changing this value only + * affects new connections to the server, not any existing connections. + * @since v8.0.0 + */ + // keepAliveTimeout: number; + /** + * Sets the timeout value in milliseconds for receiving the entire request from + * the client. + * + * If the timeout expires, the server responds with status 408 without + * forwarding the request to the request listener and then closes the connection. + * + * It must be set to a non-zero value (e.g. 120 seconds) to protect against + * potential Denial-of-Service attacks in case the server is deployed without a + * reverse proxy in front. + * @since v14.11.0 + */ + // requestTimeout: number; + /** + * Closes all connections connected to this server. + * @since v18.2.0 + */ + // closeAllConnections(): void; + /** + * Closes all connections connected to this server which are not sending a request or waiting for a response. + * @since v18.2.0 + */ + // closeIdleConnections(): void; + addListener(event: string, listener: (...args: any[]) => void): this; + addListener(event: "close", listener: () => void): this; + addListener(event: "connection", listener: (socket: Socket) => void): this; + addListener(event: "error", listener: (err: Error) => void): this; + addListener(event: "listening", listener: () => void): this; + addListener( + event: "checkContinue", + listener: RequestListener<Request, Response>, + ): this; + addListener( + event: "checkExpectation", + listener: RequestListener<Request, Response>, + ): this; + addListener( + event: "clientError", + listener: (err: Error, socket: stream.Duplex) => void, + ): this; + addListener( + event: "connect", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + addListener( + event: "request", + listener: RequestListener<Request, Response>, + ): this; + addListener( + event: "upgrade", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + emit(event: string, ...args: any[]): boolean; + emit(event: "close"): boolean; + emit(event: "connection", socket: Socket): boolean; + emit(event: "error", err: Error): boolean; + emit(event: "listening"): boolean; + emit( + event: "checkContinue", + req: InstanceType<Request>, + res: InstanceType<Response> & { req: InstanceType<Request> }, + ): boolean; + emit( + event: "checkExpectation", + req: InstanceType<Request>, + res: InstanceType<Response> & { req: InstanceType<Request> }, + ): boolean; + emit(event: "clientError", err: Error, socket: stream.Duplex): boolean; + emit( + event: "connect", + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ): boolean; + emit( + event: "request", + req: InstanceType<Request>, + res: InstanceType<Response> & { req: InstanceType<Request> }, + ): boolean; + emit( + event: "upgrade", + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ): boolean; + on(event: string, listener: (...args: any[]) => void): this; + on(event: "close", listener: () => void): this; + on(event: "connection", listener: (socket: Socket) => void): this; + on(event: "error", listener: (err: Error) => void): this; + on(event: "listening", listener: () => void): this; + on( + event: "checkContinue", + listener: RequestListener<Request, Response>, + ): this; + on( + event: "checkExpectation", + listener: RequestListener<Request, Response>, + ): this; + on( + event: "clientError", + listener: (err: Error, socket: stream.Duplex) => void, + ): this; + on( + event: "connect", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + on(event: "request", listener: RequestListener<Request, Response>): this; + on( + event: "upgrade", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + once(event: string, listener: (...args: any[]) => void): this; + once(event: "close", listener: () => void): this; + once(event: "connection", listener: (socket: Socket) => void): this; + once(event: "error", listener: (err: Error) => void): this; + once(event: "listening", listener: () => void): this; + once( + event: "checkContinue", + listener: RequestListener<Request, Response>, + ): this; + once( + event: "checkExpectation", + listener: RequestListener<Request, Response>, + ): this; + once( + event: "clientError", + listener: (err: Error, socket: stream.Duplex) => void, + ): this; + once( + event: "connect", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + once(event: "request", listener: RequestListener<Request, Response>): this; + once( + event: "upgrade", + listener: ( + req: InstanceType<Request>, + socket: stream.Duplex, + head: Buffer, + ) => void, + ): this; + // prependListener(event: string, listener: (...args: any[]) => void): this; + // prependListener(event: "close", listener: () => void): this; + // prependListener( + // event: "connection", + // listener: (socket: Socket) => void, + // ): this; + // prependListener(event: "error", listener: (err: Error) => void): this; + // prependListener(event: "listening", listener: () => void): this; + // prependListener( + // event: "checkContinue", + // listener: RequestListener<Request, Response>, + // ): this; + // prependListener( + // event: "checkExpectation", + // listener: RequestListener<Request, Response>, + // ): this; + // prependListener( + // event: "clientError", + // listener: (err: Error, socket: stream.Duplex) => void, + // ): this; + // prependListener( + // event: "connect", + // listener: ( + // req: InstanceType<Request>, + // socket: stream.Duplex, + // head: Buffer, + // ) => void, + // ): this; + // prependListener( + // event: "request", + // listener: RequestListener<Request, Response>, + // ): this; + // prependListener( + // event: "upgrade", + // listener: ( + // req: InstanceType<Request>, + // socket: stream.Duplex, + // head: Buffer, + // ) => void, + // ): this; + // prependOnceListener( + // event: string, + // listener: (...args: any[]) => void, + // ): this; + // prependOnceListener(event: "close", listener: () => void): this; + // prependOnceListener( + // event: "connection", + // listener: (socket: Socket) => void, + // ): this; + // prependOnceListener(event: "error", listener: (err: Error) => void): this; + // prependOnceListener(event: "listening", listener: () => void): this; + // prependOnceListener( + // event: "checkContinue", + // listener: RequestListener<Request, Response>, + // ): this; + // prependOnceListener( + // event: "checkExpectation", + // listener: RequestListener<Request, Response>, + // ): this; + // prependOnceListener( + // event: "clientError", + // listener: (err: Error, socket: stream.Duplex) => void, + // ): this; + // prependOnceListener( + // event: "connect", + // listener: ( + // req: InstanceType<Request>, + // socket: stream.Duplex, + // head: Buffer, + // ) => void, + // ): this; + // prependOnceListener( + // event: "request", + // listener: RequestListener<Request, Response>, + // ): this; + // prependOnceListener( + // event: "upgrade", + // listener: ( + // req: InstanceType<Request>, + // socket: stream.Duplex, + // head: Buffer, + // ) => void, + // ): this; + } + /** + * This class serves as the parent class of {@link ClientRequest} and {@link ServerResponse}. It is an abstract of outgoing message from + * the perspective of the participants of HTTP transaction. + * @since v0.1.17 + */ + class OutgoingMessage< + Request extends IncomingMessage = IncomingMessage, + > extends stream.Writable { + readonly req: Request; + chunkedEncoding: boolean; + shouldKeepAlive: boolean; + useChunkedEncodingByDefault: boolean; + sendDate: boolean; + /** + * @deprecated Use `writableEnded` instead. + */ + finished: boolean; + /** + * Read-only. `true` if the headers were sent, otherwise `false`. + * @since v0.9.3 + */ + readonly headersSent: boolean; + /** + * Aliases of `outgoingMessage.socket` + * @since v0.3.0 + * @deprecated Since v15.12.0,v14.17.1 - Use `socket` instead. + */ + readonly connection: Socket | null; + /** + * Reference to the underlying socket. Usually, users will not want to access + * this property. + * + * After calling `outgoingMessage.end()`, this property will be nulled. + * @since v0.3.0 + */ + readonly socket: Socket | null; + constructor(); + /** + * Once a socket is associated with the message and is connected,`socket.setTimeout()` will be called with `msecs` as the first parameter. + * @since v0.9.12 + * @param callback Optional function to be called when a timeout occurs. Same as binding to the `timeout` event. + */ + setTimeout(msecs: number, callback?: () => void): this; + /** + * Sets a single header value for the header object. + * @since v0.4.0 + * @param name Header name + * @param value Header value + */ + setHeader( + name: string, + value: number | string | ReadonlyArray<string>, + ): this; + /** + * Gets the value of HTTP header with the given name. If such a name doesn't + * exist in message, it will be `undefined`. + * @since v0.4.0 + * @param name Name of header + */ + getHeader(name: string): number | string | string[] | undefined; + /** + * Returns a shallow copy of the current outgoing headers. Since a shallow + * copy is used, array values may be mutated without additional calls to + * various header-related HTTP module methods. The keys of the returned + * object are the header names and the values are the respective header + * values. All header names are lowercase. + * + * The object returned by the `outgoingMessage.getHeaders()` method does + * not prototypically inherit from the JavaScript Object. This means that + * typical Object methods such as `obj.toString()`, `obj.hasOwnProperty()`, + * and others are not defined and will not work. + * + * ```js + * outgoingMessage.setHeader('Foo', 'bar'); + * outgoingMessage.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); + * + * const headers = outgoingMessage.getHeaders(); + * // headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] } + * ``` + * @since v7.7.0 + */ + getHeaders(): OutgoingHttpHeaders; + /** + * Returns an array of names of headers of the outgoing outgoingMessage. All + * names are lowercase. + * @since v7.7.0 + */ + getHeaderNames(): string[]; + /** + * Returns `true` if the header identified by `name` is currently set in the + * outgoing headers. The header name is case-insensitive. + * + * ```js + * const hasContentType = outgoingMessage.hasHeader('content-type'); + * ``` + * @since v7.7.0 + */ + hasHeader(name: string): boolean; + /** + * Removes a header that is queued for implicit sending. + * + * ```js + * outgoingMessage.removeHeader('Content-Encoding'); + * ``` + * @since v0.4.0 + * @param name Header name + */ + removeHeader(name: string): void; + /** + * Adds HTTP trailers (headers but at the end of the message) to the message. + * + * Trailers are **only** be emitted if the message is chunked encoded. If not, + * the trailer will be silently discarded. + * + * HTTP requires the `Trailer` header to be sent to emit trailers, + * with a list of header fields in its value, e.g. + * + * ```js + * message.writeHead(200, { 'Content-Type': 'text/plain', + * 'Trailer': 'Content-MD5' }); + * message.write(fileData); + * message.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' }); + * message.end(); + * ``` + * + * Attempting to set a header field name or value that contains invalid characters + * will result in a `TypeError` being thrown. + * @since v0.3.0 + */ + addTrailers( + headers: OutgoingHttpHeaders | ReadonlyArray<[string, string]>, + ): void; + /** + * Compulsorily flushes the message headers + * + * For efficiency reason, Node.js normally buffers the message headers + * until `outgoingMessage.end()` is called or the first chunk of message data + * is written. It then tries to pack the headers and data into a single TCP + * packet. + * + * It is usually desired (it saves a TCP round-trip), but not when the first + * data is not sent until possibly much later. `outgoingMessage.flushHeaders()`bypasses the optimization and kickstarts the request. + * @since v1.6.0 + */ + flushHeaders(): void; + } + /** + * This object is created internally by an HTTP server, not by the user. It is + * passed as the second parameter to the `'request'` event. + * @since v0.1.17 + */ + class ServerResponse< + Request extends IncomingMessage = IncomingMessage, + > extends OutgoingMessage<Request> { + /** + * When using implicit headers (not calling `response.writeHead()` explicitly), + * this property controls the status code that will be sent to the client when + * the headers get flushed. + * + * ```js + * response.statusCode = 404; + * ``` + * + * After response header was sent to the client, this property indicates the + * status code which was sent out. + * @since v0.4.0 + */ + statusCode: number; + /** + * When using implicit headers (not calling `response.writeHead()` explicitly), + * this property controls the status message that will be sent to the client when + * the headers get flushed. If this is left as `undefined` then the standard + * message for the status code will be used. + * + * ```js + * response.statusMessage = 'Not found'; + * ``` + * + * After response header was sent to the client, this property indicates the + * status message which was sent out. + * @since v0.11.8 + */ + statusMessage: string; + constructor(req: Request); + assignSocket(socket: Socket): void; + detachSocket(socket: Socket): void; + /** + * Sends an HTTP/1.1 100 Continue message to the client, indicating that + * the request body should be sent. See the `'checkContinue'` event on`Server`. + * @since v0.3.0 + */ + writeContinue(callback?: () => void): void; + /** + * Sends an HTTP/1.1 103 Early Hints message to the client with a Link header, + * indicating that the user agent can preload/preconnect the linked resources. + * The `hints` is an object containing the values of headers to be sent with + * early hints message. The optional `callback` argument will be called when + * the response message has been written. + * + * Example: + * + * ```js + * const earlyHintsLink = '</styles.css>; rel=preload; as=style'; + * response.writeEarlyHints({ + * 'link': earlyHintsLink, + * }); + * + * const earlyHintsLinks = [ + * '</styles.css>; rel=preload; as=style', + * '</scripts.js>; rel=preload; as=script', + * ]; + * response.writeEarlyHints({ + * 'link': earlyHintsLinks, + * 'x-trace-id': 'id for diagnostics' + * }); + * + * const earlyHintsCallback = () => console.log('early hints message sent'); + * response.writeEarlyHints({ + * 'link': earlyHintsLinks + * }, earlyHintsCallback); + * ``` + * + * @since v18.11.0 + * @param hints An object containing the values of headers + * @param callback Will be called when the response message has been written + */ + writeEarlyHints( + hints: Record<string, string | string[]>, + callback?: () => void, + ): void; + /** + * Sends a response header to the request. The status code is a 3-digit HTTP + * status code, like `404`. The last argument, `headers`, are the response headers. + * Optionally one can give a human-readable `statusMessage` as the second + * argument. + * + * `headers` may be an `Array` where the keys and values are in the same list. + * It is _not_ a list of tuples. So, the even-numbered offsets are key values, + * and the odd-numbered offsets are the associated values. The array is in the same + * format as `request.rawHeaders`. + * + * Returns a reference to the `ServerResponse`, so that calls can be chained. + * + * ```js + * const body = 'hello world'; + * response + * .writeHead(200, { + * 'Content-Length': Buffer.byteLength(body), + * 'Content-Type': 'text/plain' + * }) + * .end(body); + * ``` + * + * This method must only be called once on a message and it must + * be called before `response.end()` is called. + * + * If `response.write()` or `response.end()` are called before calling + * this, the implicit/mutable headers will be calculated and call this function. + * + * When headers have been set with `response.setHeader()`, they will be merged + * with any headers passed to `response.writeHead()`, with the headers passed + * to `response.writeHead()` given precedence. + * + * If this method is called and `response.setHeader()` has not been called, + * it will directly write the supplied header values onto the network channel + * without caching internally, and the `response.getHeader()` on the header + * will not yield the expected result. If progressive population of headers is + * desired with potential future retrieval and modification, use `response.setHeader()` instead. + * + * ```js + * // Returns content-type = text/plain + * const server = http.createServer((req, res) => { + * res.setHeader('Content-Type', 'text/html'); + * res.setHeader('X-Foo', 'bar'); + * res.writeHead(200, { 'Content-Type': 'text/plain' }); + * res.end('ok'); + * }); + * ``` + * + * `Content-Length` is given in bytes, not characters. Use `Buffer.byteLength()` to determine the length of the body in bytes. Node.js + * does not check whether `Content-Length` and the length of the body which has + * been transmitted are equal or not. + * + * Attempting to set a header field name or value that contains invalid characters + * will result in a `TypeError` being thrown. + * @since v0.1.30 + */ + writeHead( + statusCode: number, + statusMessage?: string, + headers?: OutgoingHttpHeaders | OutgoingHttpHeader[], + ): this; + writeHead( + statusCode: number, + headers?: OutgoingHttpHeaders | OutgoingHttpHeader[], + ): this; + /** + * Sends an HTTP/1.1 102 Processing message to the client, indicating that + * the request body should be sent. + * @since v10.0.0 + */ + writeProcessing(): void; + } + interface InformationEvent { statusCode: number; statusMessage: string; @@ -167,7 +901,7 @@ declare module "http" { * Node.js does not check whether Content-Length and the length of the * body which has been transmitted are equal or not. */ - class ClientRequest { + class ClientRequest extends OutgoingMessage { /** * The `request.aborted` property will be `true` if the request has * been aborted. @@ -231,11 +965,11 @@ declare module "http" { * retriableRequest(); * ``` */ - reusedSocket: boolean; + // reusedSocket: boolean; /** * Limits maximum response headers count. If set to 0, no limit will be applied. */ - maxHeadersCount: number; + // maxHeadersCount: number; constructor( url: string | URL | ClientRequestArgs, cb?: (res: IncomingMessage) => void, @@ -253,7 +987,7 @@ declare module "http" { * in the response to be dropped and the socket to be destroyed. * @deprecated Since v14.1.0,v13.14.0 - Use `destroy` instead. */ - abort(): void; + // abort(): void; /** * Once a socket is assigned to this request and is connected `socket.setTimeout()` will be called. * @param timeout Milliseconds before a request times out. @@ -299,7 +1033,7 @@ declare module "http" { /** * Once a socket is assigned to this request and is connected `socket.setNoDelay()` will be called. */ - setNoDelay(noDelay?: boolean): void; + // setNoDelay(noDelay?: boolean): void; /** * Once a socket is assigned to this request and is connected `socket.setKeepAlive()` will be called. */ @@ -316,7 +1050,7 @@ declare module "http" { * // headerNames === ['Foo', 'Set-Cookie'] * ``` */ - getRawHeaderNames(): string[]; + // getRawHeaderNames(): string[]; /** * @deprecated */ @@ -595,7 +1329,7 @@ declare module "http" { * } * ``` */ - url?: string | undefined; + url: string | undefined; /** * **Only valid for response obtained from {@link ClientRequest}.** * @@ -614,11 +1348,177 @@ declare module "http" { */ destroy(error?: Error): this; } + + interface AgentOptions extends Partial<TcpSocketConnectOpts> { + /** + * Keep sockets around in a pool to be used by other requests in the future. Default = false + */ + keepAlive?: boolean | undefined; + /** + * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. + * Only relevant if keepAlive is set to true. + */ + keepAliveMsecs?: number | undefined; + /** + * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity + */ + maxSockets?: number | undefined; + /** + * Maximum number of sockets allowed for all hosts in total. Each request will use a new socket until the maximum is reached. Default: Infinity. + */ + maxTotalSockets?: number | undefined; + /** + * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256. + */ + maxFreeSockets?: number | undefined; + /** + * Socket timeout in milliseconds. This will set the timeout after the socket is connected. + */ + // timeout?: number | undefined; + /** + * Scheduling strategy to apply when picking the next free socket to use. + * @default `lifo` + */ + scheduling?: "fifo" | "lifo" | undefined; + } + /** + * An `Agent` is responsible for managing connection persistence + * and reuse for HTTP clients. It maintains a queue of pending requests + * for a given host and port, reusing a single socket connection for each + * until the queue is empty, at which time the socket is either destroyed + * or put into a pool where it is kept to be used again for requests to the + * same host and port. Whether it is destroyed or pooled depends on the`keepAlive` `option`. + * + * Pooled connections have TCP Keep-Alive enabled for them, but servers may + * still close idle connections, in which case they will be removed from the + * pool and a new connection will be made when a new HTTP request is made for + * that host and port. Servers may also refuse to allow multiple requests + * over the same connection, in which case the connection will have to be + * remade for every request and cannot be pooled. The `Agent` will still make + * the requests to that server, but each one will occur over a new connection. + * + * When a connection is closed by the client or the server, it is removed + * from the pool. Any unused sockets in the pool will be unrefed so as not + * to keep the Node.js process running when there are no outstanding requests. + * (see `socket.unref()`). + * + * It is good practice, to `destroy()` an `Agent` instance when it is no + * longer in use, because unused sockets consume OS resources. + * + * Sockets are removed from an agent when the socket emits either + * a `'close'` event or an `'agentRemove'` event. When intending to keep one + * HTTP request open for a long time without keeping it in the agent, something + * like the following may be done: + * + * ```js + * http.get(options, (res) => { + * // Do stuff + * }).on('socket', (socket) => { + * socket.emit('agentRemove'); + * }); + * ``` + * + * An agent may also be used for an individual request. By providing`{agent: false}` as an option to the `http.get()` or `http.request()`functions, a one-time use `Agent` with default options + * will be used + * for the client connection. + * + * `agent:false`: + * + * ```js + * http.get({ + * hostname: 'localhost', + * port: 80, + * path: '/', + * agent: false // Create a new agent just for this one request + * }, (res) => { + * // Do stuff with response + * }); + * ``` + * @since v0.3.4 + */ + class Agent { + /** + * By default set to 256\. For agents with `keepAlive` enabled, this + * sets the maximum number of sockets that will be left open in the free + * state. + * @since v0.11.7 + */ + maxFreeSockets: number; + /** + * By default set to `Infinity`. Determines how many concurrent sockets the agent + * can have open per origin. Origin is the returned value of `agent.getName()`. + * @since v0.3.6 + */ + maxSockets: number; + /** + * By default set to `Infinity`. Determines how many concurrent sockets the agent + * can have open. Unlike `maxSockets`, this parameter applies across all origins. + * @since v14.5.0, v12.19.0 + */ + maxTotalSockets: number; + /** + * An object which contains arrays of sockets currently awaiting use by + * the agent when `keepAlive` is enabled. Do not modify. + * + * Sockets in the `freeSockets` list will be automatically destroyed and + * removed from the array on `'timeout'`. + * @since v0.11.4 + */ + readonly freeSockets: ReadOnlyDict<Socket[]>; + /** + * An object which contains arrays of sockets currently in use by the + * agent. Do not modify. + * @since v0.3.6 + */ + readonly sockets: ReadOnlyDict<Socket[]>; + /** + * An object which contains queues of requests that have not yet been assigned to + * sockets. Do not modify. + * @since v0.5.9 + */ + readonly requests: ReadOnlyDict<IncomingMessage[]>; + constructor(opts?: AgentOptions); + /** + * Destroy any sockets that are currently in use by the agent. + * + * It is usually not necessary to do this. However, if using an + * agent with `keepAlive` enabled, then it is best to explicitly shut down + * the agent when it is no longer needed. Otherwise, + * sockets might stay open for quite a long time before the server + * terminates them. + * @since v0.11.4 + */ + destroy(): void; + keepSocketAlive(socket: Socket): boolean; + } + const METHODS: string[]; const STATUS_CODES: { [errorCode: number]: string | undefined; [errorCode: string]: string | undefined; }; + + /** + * Returns a new instance of {@link Server}. + * + * The `requestListener` is a function which is automatically + * added to the `'request'` event. + * @since v0.1.13 + */ + function createServer< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse = typeof ServerResponse, + >( + requestListener?: RequestListener<Request, Response>, + ): Server<Request, Response>; + function createServer< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse = typeof ServerResponse, + >( + options: ServerOptions<Request, Response>, + requestListener?: RequestListener<Request, Response>, + ): Server<Request, Response>; + // although RequestOptions are passed as ClientRequestArgs to ClientRequest directly, // create interface RequestOptions would make the naming more clear to developers interface RequestOptions extends ClientRequestArgs {} @@ -884,6 +1784,9 @@ declare module "http" { options: RequestOptions, callback?: (res: IncomingMessage) => void, ): ClientRequest; + + let globalAgent: Agent; + /** * Read-only property specifying the maximum allowed size of HTTP headers in bytes. * Defaults to 16KB. Configurable using the `--max-http-header-size` CLI option. diff --git a/packages/bun-types/net.d.ts b/packages/bun-types/net.d.ts index 8459fe685..4817d98f8 100644 --- a/packages/bun-types/net.d.ts +++ b/packages/bun-types/net.d.ts @@ -14,10 +14,7 @@ */ declare module "net" { import * as stream from "node:stream"; - import { - Abortable, - // EventEmitter - } from "node:events"; + import { Abortable, EventEmitter } from "node:events"; import * as dns from "node:dns"; type LookupFunction = ( hostname: string, @@ -530,212 +527,213 @@ declare module "net" { * This class is used to create a TCP or `IPC` server. * @since v0.1.90 */ - // class Server extends EventEmitter { - // constructor(connectionListener?: (socket: Socket) => void); - // constructor( - // options?: ServerOpts, - // connectionListener?: (socket: Socket) => void, - // ); - // /** - // * Start a server listening for connections. A `net.Server` can be a TCP or - // * an `IPC` server depending on what it listens to. - // * - // * Possible signatures: - // * - // * * `server.listen(handle[, backlog][, callback])` - // * * `server.listen(options[, callback])` - // * * `server.listen(path[, backlog][, callback])` for `IPC` servers - // * * `server.listen([port[, host[, backlog]]][, callback])` for TCP servers - // * - // * This function is asynchronous. When the server starts listening, the `'listening'` event will be emitted. The last parameter `callback`will be added as a listener for the `'listening'` - // * event. - // * - // * All `listen()` methods can take a `backlog` parameter to specify the maximum - // * length of the queue of pending connections. The actual length will be determined - // * by the OS through sysctl settings such as `tcp_max_syn_backlog` and `somaxconn`on Linux. The default value of this parameter is 511 (not 512). - // * - // * All {@link Socket} are set to `SO_REUSEADDR` (see [`socket(7)`](https://man7.org/linux/man-pages/man7/socket.7.html) for - // * details). - // * - // * The `server.listen()` method can be called again if and only if there was an - // * error during the first `server.listen()` call or `server.close()` has been - // * called. Otherwise, an `ERR_SERVER_ALREADY_LISTEN` error will be thrown. - // * - // * One of the most common errors raised when listening is `EADDRINUSE`. - // * This happens when another server is already listening on the requested`port`/`path`/`handle`. One way to handle this would be to retry - // * after a certain amount of time: - // * - // * ```js - // * server.on('error', (e) => { - // * if (e.code === 'EADDRINUSE') { - // * console.log('Address in use, retrying...'); - // * setTimeout(() => { - // * server.close(); - // * server.listen(PORT, HOST); - // * }, 1000); - // * } - // * }); - // * ``` - // */ - // listen( - // port?: number, - // hostname?: string, - // backlog?: number, - // listeningListener?: () => void, - // ): this; - // listen( - // port?: number, - // hostname?: string, - // listeningListener?: () => void, - // ): this; - // listen( - // port?: number, - // backlog?: number, - // listeningListener?: () => void, - // ): this; - // listen(port?: number, listeningListener?: () => void): this; - // listen( - // path: string, - // backlog?: number, - // listeningListener?: () => void, - // ): this; - // listen(path: string, listeningListener?: () => void): this; - // listen(options: ListenOptions, listeningListener?: () => void): this; - // listen(handle: any, backlog?: number, listeningListener?: () => void): this; - // listen(handle: any, listeningListener?: () => void): this; - // /** - // * Stops the server from accepting new connections and keeps existing - // * connections. This function is asynchronous, the server is finally closed - // * when all connections are ended and the server emits a `'close'` event. - // * The optional `callback` will be called once the `'close'` event occurs. Unlike - // * that event, it will be called with an `Error` as its only argument if the server - // * was not open when it was closed. - // * @since v0.1.90 - // * @param callback Called when the server is closed. - // */ - // close(callback?: (err?: Error) => void): this; - // /** - // * Returns the bound `address`, the address `family` name, and `port` of the server - // * as reported by the operating system if listening on an IP socket - // * (useful to find which port was assigned when getting an OS-assigned address):`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`. - // * - // * For a server listening on a pipe or Unix domain socket, the name is returned - // * as a string. - // * - // * ```js - // * const server = net.createServer((socket) => { - // * socket.end('goodbye\n'); - // * }).on('error', (err) => { - // * // Handle errors here. - // * throw err; - // * }); - // * - // * // Grab an arbitrary unused port. - // * server.listen(() => { - // * console.log('opened server on', server.address()); - // * }); - // * ``` - // * - // * `server.address()` returns `null` before the `'listening'` event has been - // * emitted or after calling `server.close()`. - // * @since v0.1.90 - // */ - // address(): AddressInfo | string | null; - // /** - // * Asynchronously get the number of concurrent connections on the server. Works - // * when sockets were sent to forks. - // * - // * Callback should take two arguments `err` and `count`. - // * @since v0.9.7 - // */ - // getConnections(cb: (error: Error | null, count: number) => void): void; - // /** - // * Opposite of `unref()`, calling `ref()` on a previously `unref`ed server will _not_ let the program exit if it's the only server left (the default behavior). - // * If the server is `ref`ed calling `ref()` again will have no effect. - // * @since v0.9.1 - // */ - // ref(): this; - // /** - // * Calling `unref()` on a server will allow the program to exit if this is the only - // * active server in the event system. If the server is already `unref`ed calling`unref()` again will have no effect. - // * @since v0.9.1 - // */ - // unref(): this; - // /** - // * Set this property to reject connections when the server's connection count gets - // * high. - // * - // * It is not recommended to use this option once a socket has been sent to a child - // * with `child_process.fork()`. - // * @since v0.2.0 - // */ - // maxConnections: number; - // connections: number; - // /** - // * Indicates whether or not the server is listening for connections. - // * @since v5.7.0 - // */ - // listening: boolean; - // /** - // * events.EventEmitter - // * 1. close - // * 2. connection - // * 3. error - // * 4. listening - // * 5. drop - // */ - // addListener(event: string, listener: (...args: any[]) => void): this; - // addListener(event: "close", listener: () => void): this; - // addListener(event: "connection", listener: (socket: Socket) => void): this; - // addListener(event: "error", listener: (err: Error) => void): this; - // addListener(event: "listening", listener: () => void): this; - // addListener(event: "drop", listener: (data?: DropArgument) => void): this; - // emit(event: string | symbol, ...args: any[]): boolean; - // emit(event: "close"): boolean; - // emit(event: "connection", socket: Socket): boolean; - // emit(event: "error", err: Error): boolean; - // emit(event: "listening"): boolean; - // emit(event: "drop", data?: DropArgument): boolean; - // on(event: string, listener: (...args: any[]) => void): this; - // on(event: "close", listener: () => void): this; - // on(event: "connection", listener: (socket: Socket) => void): this; - // on(event: "error", listener: (err: Error) => void): this; - // on(event: "listening", listener: () => void): this; - // on(event: "drop", listener: (data?: DropArgument) => void): this; - // once(event: string, listener: (...args: any[]) => void): this; - // once(event: "close", listener: () => void): this; - // once(event: "connection", listener: (socket: Socket) => void): this; - // once(event: "error", listener: (err: Error) => void): this; - // once(event: "listening", listener: () => void): this; - // once(event: "drop", listener: (data?: DropArgument) => void): this; - // prependListener(event: string, listener: (...args: any[]) => void): this; - // prependListener(event: "close", listener: () => void): this; - // prependListener( - // event: "connection", - // listener: (socket: Socket) => void, - // ): this; - // prependListener(event: "error", listener: (err: Error) => void): this; - // prependListener(event: "listening", listener: () => void): this; - // prependListener( - // event: "drop", - // listener: (data?: DropArgument) => void, - // ): this; - // prependOnceListener( - // event: string, - // listener: (...args: any[]) => void, - // ): this; - // prependOnceListener(event: "close", listener: () => void): this; - // prependOnceListener( - // event: "connection", - // listener: (socket: Socket) => void, - // ): this; - // prependOnceListener(event: "error", listener: (err: Error) => void): this; - // prependOnceListener(event: "listening", listener: () => void): this; - // prependOnceListener( - // event: "drop", - // listener: (data?: DropArgument) => void, - // ): this; - // } + // change back to class once implemented + interface Server extends EventEmitter { + // constructor(connectionListener?: (socket: Socket) => void); + // constructor( + // options?: ServerOpts, + // connectionListener?: (socket: Socket) => void, + // ); + /** + * Start a server listening for connections. A `net.Server` can be a TCP or + * an `IPC` server depending on what it listens to. + * + * Possible signatures: + * + * * `server.listen(handle[, backlog][, callback])` + * * `server.listen(options[, callback])` + * * `server.listen(path[, backlog][, callback])` for `IPC` servers + * * `server.listen([port[, host[, backlog]]][, callback])` for TCP servers + * + * This function is asynchronous. When the server starts listening, the `'listening'` event will be emitted. The last parameter `callback`will be added as a listener for the `'listening'` + * event. + * + * All `listen()` methods can take a `backlog` parameter to specify the maximum + * length of the queue of pending connections. The actual length will be determined + * by the OS through sysctl settings such as `tcp_max_syn_backlog` and `somaxconn`on Linux. The default value of this parameter is 511 (not 512). + * + * All {@link Socket} are set to `SO_REUSEADDR` (see [`socket(7)`](https://man7.org/linux/man-pages/man7/socket.7.html) for + * details). + * + * The `server.listen()` method can be called again if and only if there was an + * error during the first `server.listen()` call or `server.close()` has been + * called. Otherwise, an `ERR_SERVER_ALREADY_LISTEN` error will be thrown. + * + * One of the most common errors raised when listening is `EADDRINUSE`. + * This happens when another server is already listening on the requested`port`/`path`/`handle`. One way to handle this would be to retry + * after a certain amount of time: + * + * ```js + * server.on('error', (e) => { + * if (e.code === 'EADDRINUSE') { + * console.log('Address in use, retrying...'); + * setTimeout(() => { + * server.close(); + * server.listen(PORT, HOST); + * }, 1000); + * } + * }); + * ``` + */ + listen( + port?: number, + hostname?: string, + backlog?: number, + listeningListener?: () => void, + ): this; + listen( + port?: number, + hostname?: string, + listeningListener?: () => void, + ): this; + listen( + port?: number, + backlog?: number, + listeningListener?: () => void, + ): this; + listen(port?: number, listeningListener?: () => void): this; + listen( + path: string, + backlog?: number, + listeningListener?: () => void, + ): this; + listen(path: string, listeningListener?: () => void): this; + listen(options: ListenOptions, listeningListener?: () => void): this; + listen(handle: any, backlog?: number, listeningListener?: () => void): this; + listen(handle: any, listeningListener?: () => void): this; + /** + * Stops the server from accepting new connections and keeps existing + * connections. This function is asynchronous, the server is finally closed + * when all connections are ended and the server emits a `'close'` event. + * The optional `callback` will be called once the `'close'` event occurs. Unlike + * that event, it will be called with an `Error` as its only argument if the server + * was not open when it was closed. + * @since v0.1.90 + * @param callback Called when the server is closed. + */ + close(callback?: (err?: Error) => void): this; + /** + * Returns the bound `address`, the address `family` name, and `port` of the server + * as reported by the operating system if listening on an IP socket + * (useful to find which port was assigned when getting an OS-assigned address):`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`. + * + * For a server listening on a pipe or Unix domain socket, the name is returned + * as a string. + * + * ```js + * const server = net.createServer((socket) => { + * socket.end('goodbye\n'); + * }).on('error', (err) => { + * // Handle errors here. + * throw err; + * }); + * + * // Grab an arbitrary unused port. + * server.listen(() => { + * console.log('opened server on', server.address()); + * }); + * ``` + * + * `server.address()` returns `null` before the `'listening'` event has been + * emitted or after calling `server.close()`. + * @since v0.1.90 + */ + address(): AddressInfo | string | null; + /** + * Asynchronously get the number of concurrent connections on the server. Works + * when sockets were sent to forks. + * + * Callback should take two arguments `err` and `count`. + * @since v0.9.7 + */ + // getConnections(cb: (error: Error | null, count: number) => void): void; + /** + * Opposite of `unref()`, calling `ref()` on a previously `unref`ed server will _not_ let the program exit if it's the only server left (the default behavior). + * If the server is `ref`ed calling `ref()` again will have no effect. + * @since v0.9.1 + */ + // ref(): this; + /** + * Calling `unref()` on a server will allow the program to exit if this is the only + * active server in the event system. If the server is already `unref`ed calling`unref()` again will have no effect. + * @since v0.9.1 + */ + // unref(): this; + /** + * Set this property to reject connections when the server's connection count gets + * high. + * + * It is not recommended to use this option once a socket has been sent to a child + * with `child_process.fork()`. + * @since v0.2.0 + */ + // maxConnections: number; + // connections: number; + /** + * Indicates whether or not the server is listening for connections. + * @since v5.7.0 + */ + // listening: boolean; + /** + * events.EventEmitter + * 1. close + * 2. connection + * 3. error + * 4. listening + * 5. drop + */ + addListener(event: string, listener: (...args: any[]) => void): this; + addListener(event: "close", listener: () => void): this; + addListener(event: "connection", listener: (socket: Socket) => void): this; + addListener(event: "error", listener: (err: Error) => void): this; + addListener(event: "listening", listener: () => void): this; + addListener(event: "drop", listener: (data?: DropArgument) => void): this; + emit(event: string | symbol, ...args: any[]): boolean; + emit(event: "close"): boolean; + emit(event: "connection", socket: Socket): boolean; + emit(event: "error", err: Error): boolean; + emit(event: "listening"): boolean; + emit(event: "drop", data?: DropArgument): boolean; + on(event: string, listener: (...args: any[]) => void): this; + on(event: "close", listener: () => void): this; + on(event: "connection", listener: (socket: Socket) => void): this; + on(event: "error", listener: (err: Error) => void): this; + on(event: "listening", listener: () => void): this; + on(event: "drop", listener: (data?: DropArgument) => void): this; + once(event: string, listener: (...args: any[]) => void): this; + once(event: "close", listener: () => void): this; + once(event: "connection", listener: (socket: Socket) => void): this; + once(event: "error", listener: (err: Error) => void): this; + once(event: "listening", listener: () => void): this; + once(event: "drop", listener: (data?: DropArgument) => void): this; + prependListener(event: string, listener: (...args: any[]) => void): this; + prependListener(event: "close", listener: () => void): this; + prependListener( + event: "connection", + listener: (socket: Socket) => void, + ): this; + prependListener(event: "error", listener: (err: Error) => void): this; + prependListener(event: "listening", listener: () => void): this; + prependListener( + event: "drop", + listener: (data?: DropArgument) => void, + ): this; + prependOnceListener( + event: string, + listener: (...args: any[]) => void, + ): this; + prependOnceListener(event: "close", listener: () => void): this; + prependOnceListener( + event: "connection", + listener: (socket: Socket) => void, + ): this; + prependOnceListener(event: "error", listener: (err: Error) => void): this; + prependOnceListener(event: "listening", listener: () => void): this; + prependOnceListener( + event: "drop", + listener: (data?: DropArgument) => void, + ): this; + } type IPVersion = "ipv4" | "ipv6"; /** * The `BlockList` object can be used with some network APIs to specify rules for diff --git a/packages/bun-types/stream.d.ts b/packages/bun-types/stream.d.ts index 5962692a0..8934146fa 100644 --- a/packages/bun-types/stream.d.ts +++ b/packages/bun-types/stream.d.ts @@ -555,24 +555,29 @@ declare module "stream" { */ destroyed: boolean; constructor(opts?: WritableOptions); - _write( - chunk: any, - encoding: BufferEncoding, - callback: (error?: Error | null) => void, - ): void; - _writev?( - chunks: Array<{ - chunk: any; - encoding: BufferEncoding; - }>, - callback: (error?: Error | null) => void, - ): void; - _construct?(callback: (error?: Error | null) => void): void; - _destroy( - error: Error | null, - callback: (error?: Error | null) => void, - ): void; - _final(callback: (error?: Error | null) => void): void; + + /** + * Hide internal methods from the public API. + */ + // _write( + // chunk: any, + // encoding: BufferEncoding, + // callback: (error?: Error | null) => void, + // ): void; + // _writev?( + // chunks: Array<{ + // chunk: any; + // encoding: BufferEncoding; + // }>, + // callback: (error?: Error | null) => void, + // ): void; + // _construct?(callback: (error?: Error | null) => void): void; + // _destroy( + // error: Error | null, + // callback: (error?: Error | null) => void, + // ): void; + // _final(callback: (error?: Error | null) => void): void; + /** * The `writable.write()` method writes some data to the stream, and calls the * supplied `callback` once the data has been fully handled. If an error diff --git a/packages/bun-types/tests/http.test-d.ts b/packages/bun-types/tests/http.test-d.ts new file mode 100644 index 000000000..d9754ac0c --- /dev/null +++ b/packages/bun-types/tests/http.test-d.ts @@ -0,0 +1,27 @@ +import * as http from "http"; + +const server = new http.Server({}); +server.address; +server.close(); +server.eventNames; +server.getMaxListeners(); +server.listeners; +server.on; +server.once; +server.prependListener; +server.prependOnceListener; +server.rawListeners; +server.removeAllListeners; +server.removeListener; +server.setMaxListeners; +server; +const agent = new http.Agent({}); + +http.globalAgent; +http.maxHeaderSize; +console.log(Object.getOwnPropertyNames(agent)); + +const req = http.request({ host: "localhost", port: 3000, method: "GET" }); +req.abort; +req.end(); +export {}; diff --git a/src/bun.js/http.exports.js b/src/bun.js/http.exports.js index 579991424..29421b836 100644 --- a/src/bun.js/http.exports.js +++ b/src/bun.js/http.exports.js @@ -920,6 +920,10 @@ export class ClientRequest extends OutgoingMessage { return this.#port; } + get method() { + return this.#method; + } + get host() { return this.#host; } diff --git a/test/bun.js/node-http.test.ts b/test/bun.js/node-http.test.ts index 6ba619c3e..e0964edb0 100644 --- a/test/bun.js/node-http.test.ts +++ b/test/bun.js/node-http.test.ts @@ -83,10 +83,10 @@ describe("node:http", () => { describe("request", () => { let server; let serverPort; - let timer = null; + let timer: Timer | null = null; beforeAll(() => { server = createServer((req, res) => { - const reqUrl = new URL(req.url, `http://${req.headers.host}`); + const reqUrl = new URL(req.url!, `http://${req.headers.host}`); if (reqUrl.pathname) { if (reqUrl.pathname === "/redirect") { // Temporary redirect @@ -148,6 +148,20 @@ describe("node:http", () => { if (timer) clearTimeout(timer); }); + it("check for expected fields", done => { + const req = request({ host: "localhost", port: serverPort, method: "GET" }, res => { + res.on("end", () => { + done(); + }); + res.on("error", err => done(err)); + }); + expect(req.path).toEqual("/"); + expect(req.method).toEqual("GET"); + expect(req.host).toEqual("localhost"); + expect(req.protocol).toEqual("http:"); + req.end(); + }); + it("should make a standard GET request when passed string as first arg", done => { const req = request(`http://localhost:${serverPort}`, res => { let data = ""; @@ -510,7 +524,9 @@ describe("node:http", () => { it("should noop keepSocketAlive", () => { const agent = new Agent({ keepAlive: true }); + // @ts-ignore expect(agent.keepAlive).toBe(true); + agent.keepSocketAlive(dummyReq.socket); }); |