diff --git a/.eslintrc b/.eslintrc index 466fc67d..9bcdb468 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,16 +2,5 @@ "extends": [ "eslint-config-egg/typescript", "eslint-config-egg/lib/rules/enforce-node-prefix" - ], - "parserOptions": { - // recommend to use another config file like tsconfig.eslint.json and extends tsconfig.json in it. - // because you may be need to lint test/**/*.test.ts but no need to emit to js. - // @see https://github.com/typescript-eslint/typescript-eslint/issues/890 - "project": "./tsconfig.eslint.json" - }, - "ignorePatterns": [ - "src/**/*.js", - "src/esm", - "src/cjs" ] } diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 4285be1f..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ "master" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "master" ] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript', 'typescript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 9e51f0d3..271cd4b1 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -12,6 +12,6 @@ jobs: uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: os: 'ubuntu-latest, macos-latest, windows-latest' - version: '14.19.3, 14, 16, 18, 20, 22' + version: '18.19.0, 20, 22' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/README.md b/README.md index ec5c9a63..48332177 100644 --- a/README.md +++ b/README.md @@ -283,25 +283,14 @@ Fork [undici benchmarks script](https://github.com/fengmk2/undici/blob/urllib-be | undici - stream | 45 | 12523.45 req/sec | ± 2.97 % | + 754.61 % | | undici - dispatch | 51 | 12970.18 req/sec | ± 3.15 % | + 785.10 % | +## License + +[MIT](LICENSE) ## Contributors -|[
fengmk2](https://github.com/fengmk2)
|[
dead-horse](https://github.com/dead-horse)
|[
semantic-release-bot](https://github.com/semantic-release-bot)
|[
xingrz](https://github.com/xingrz)
|[
popomore](https://github.com/popomore)
|[
JacksonTian](https://github.com/JacksonTian)
| -| :---: | :---: | :---: | :---: | :---: | :---: | -|[
ibigbug](https://github.com/ibigbug)
|[
greenkeeperio-bot](https://github.com/greenkeeperio-bot)
|[
atian25](https://github.com/atian25)
|[
killagu](https://github.com/killagu)
|[
paambaati](https://github.com/paambaati)
|[
tremby](https://github.com/tremby)
| -|[
denghongcai](https://github.com/denghongcai)
|[
gemwuu](https://github.com/gemwuu)
|[
XadillaX](https://github.com/XadillaX)
|[
alsotang](https://github.com/alsotang)
|[
leoner](https://github.com/leoner)
|[
hyj1991](https://github.com/hyj1991)
| -|[
isayme](https://github.com/isayme)
|[
cyjake](https://github.com/cyjake)
|[
whxaxes](https://github.com/whxaxes)
|[
chadxz](https://github.com/chadxz)
|[
adapt0](https://github.com/adapt0)
|[
danielwpz](https://github.com/danielwpz)
| -|[
danielsss](https://github.com/danielsss)
|[
Jeff-Tian](https://github.com/Jeff-Tian)
|[
nick-ng](https://github.com/nick-ng)
|[
rishavsharan](https://github.com/rishavsharan)
|[
willizm](https://github.com/willizm)
|[
davidkhala](https://github.com/davidkhala)
| -|[
aleafs](https://github.com/aleafs)
|[
Amunu](https://github.com/Amunu)
|[
azure-pipelines[bot]](https://github.com/apps/azure-pipelines)
|[
capsice](https://github.com/capsice)
|[
changzhiwin](https://github.com/changzhiwin)
|[
yuzhigang33](https://github.com/yuzhigang33)
| -|[
elrrrrrrr](https://github.com/elrrrrrrr)
|[
fishbar](https://github.com/fishbar)
|[
gxcsoccer](https://github.com/gxcsoccer)
|[
mars-coder](https://github.com/mars-coder)
|[
rockdai](https://github.com/rockdai)
|[
dickeylth](https://github.com/dickeylth)
| -[
aladdin-add](https://github.com/aladdin-add)
- -This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Mon Dec 04 2023 00:13:39 GMT+0800`. +[![Contributors](https://contrib.rocks/image?repo=node-modules/urllib)](https://github.com/node-modules/urllib/graphs/contributors) - - -## License - -[MIT](LICENSE) +Made with [contributors-img](https://contrib.rocks). diff --git a/package.json b/package.json index cecb688a..a1fff8c9 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "urllib", - "version": "3.25.1", + "version": "4.0.0", "publishConfig": { "tag": "latest" }, - "description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more. Base undici fetch API.", + "description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, timeout and more. Base undici API.", "keywords": [ "urllib", "http", @@ -39,42 +39,35 @@ "test": "npm run lint && vitest run", "test-keepalive": "cross-env TEST_KEEPALIVE_COUNT=50 vitest run --test-timeout 180000 keep-alive-header.test.ts", "cov": "vitest run --coverage", - "preci": "node scripts/pre_test.js", - "ci": "npm run lint && npm run cov && node scripts/build_test.js", - "contributor": "git-contributor", + "ci": "npm run lint && npm run cov && npm run prepublishOnly && attw --pack", "clean": "rm -rf dist", "prepublishOnly": "npm run build" }, "dependencies": { - "default-user-agent": "^1.0.0", - "digest-header": "^1.0.0", - "form-data-encoder": "^1.7.2", - "formdata-node": "^4.3.3", - "formstream": "^1.1.1", + "formstream": "^1.5.1", "mime-types": "^2.1.35", - "pump": "^3.0.0", - "qs": "^6.11.2", - "type-fest": "^4.3.1", - "undici": "^5.28.2", - "ylru": "^1.3.2" + "qs": "^6.12.1", + "type-fest": "^4.20.1", + "undici": "^6.19.2", + "ylru": "^2.0.0" }, "devDependencies": { + "@arethetypeswrong/cli": "^0.15.3", + "@eggjs/tsconfig": "^1.3.3", "@tsconfig/node18": "^18.2.1", "@tsconfig/strictest": "^2.0.2", "@types/busboy": "^1.5.0", - "@types/default-user-agent": "^1.0.0", "@types/mime-types": "^2.1.1", "@types/node": "^20.2.1", - "@types/pump": "^1.1.1", + "@types/proxy": "^1.0.4", "@types/qs": "^6.9.7", "@types/selfsigned": "^2.0.1", "@types/tar-stream": "^2.2.2", - "@vitest/coverage-v8": "^1.3.1", + "@vitest/coverage-v8": "^1.6.0", "busboy": "^1.6.0", "cross-env": "^7.0.3", - "eslint": "^8.25.0", - "eslint-config-egg": "^12.1.0", - "git-contributor": "^2.0.0", + "eslint": "8", + "eslint-config-egg": "13", "iconv-lite": "^0.6.3", "proxy": "^1.0.2", "selfsigned": "^2.0.1", @@ -82,10 +75,10 @@ "tshy": "^1.0.0", "tshy-after": "^1.0.0", "typescript": "^5.0.4", - "vitest": "^1.3.1" + "vitest": "^1.6.0" }, "engines": { - "node": ">= 14.19.3" + "node": ">= 18.19.0" }, "license": "MIT", "type": "module", @@ -98,10 +91,12 @@ "exports": { ".": { "import": { + "source": "./src/index.ts", "types": "./dist/esm/index.d.ts", "default": "./dist/esm/index.js" }, "require": { + "source": "./src/index.ts", "types": "./dist/commonjs/index.d.ts", "default": "./dist/commonjs/index.js" } diff --git a/scripts/build_test.js b/scripts/build_test.js deleted file mode 100644 index d2b06180..00000000 --- a/scripts/build_test.js +++ /dev/null @@ -1,15 +0,0 @@ -import { execSync } from 'child_process'; - -function main() { - if (process.version.startsWith('v14.')) { - console.log(`ignore build:test on Node.js ${process.version}`); - return; - } - const cwd = process.cwd() - execSync('npm run build:test', { - cwd, - stdio: [ 'inherit', 'inherit', 'inherit' ], - }); -} - -main(); diff --git a/scripts/pre_test.js b/scripts/pre_test.js deleted file mode 100644 index f79e535d..00000000 --- a/scripts/pre_test.js +++ /dev/null @@ -1,24 +0,0 @@ -import { execSync } from 'node:child_process'; -import { writeFileSync, readFileSync } from 'node:fs'; -import { join } from 'node:path'; - -function main() { - if (!process.version.startsWith('v14.')) { - return; - } - console.log(`use vitest@^0.33.0 on Node.js ${process.version}`); - const cwd = process.cwd() - execSync('npm i vitest@^0.33.0 @vitest/coverage-v8@^0.33.0', { - cwd, - stdio: [ 'inherit', 'inherit', 'inherit' ], - }); - if (process.env.CI) { - // add --no-threads - const pkgFile = join(process.cwd(), 'package.json'); - const pkg = JSON.parse(readFileSync(pkgFile, 'utf-8')); - pkg.scripts.cov = `${pkg.scripts.cov} --no-threads`; - writeFileSync(pkgFile, JSON.stringify(pkg)); - } -} - -main(); diff --git a/scripts/replace_urllib_version.js b/scripts/replace_urllib_version.js index 0efb7b02..ee06f779 100644 --- a/scripts/replace_urllib_version.js +++ b/scripts/replace_urllib_version.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -import fs from 'fs/promises'; -import path from 'path'; +import fs from 'node:fs/promises'; +import path from 'node:path'; async function main() { const root = process.cwd(); @@ -12,9 +12,9 @@ async function main() { ]; for (const file of files) { const content = await fs.readFile(file, 'utf-8'); - // replace "('node-urllib', 'VERSION')" to "('node-urllib', 'pkg.version')" - const newContent = content.replace(/\(\'node-urllib\', \'VERSION\'\)/, (match) => { - const after = `('node-urllib', '${pkg.version}')`; + // replace "const VERSION = 'VERSION';" to "const VERSION = '4.0.0';" + const newContent = content.replace(/const VERSION = 'VERSION';/, match => { + const after = `const VERSION = '${pkg.version}';`; console.log('[%s] %s => %s', file, match, after); return after; }); diff --git a/src/HttpClient.ts b/src/HttpClient.ts index 5bf5e7d2..dad15287 100644 --- a/src/HttpClient.ts +++ b/src/HttpClient.ts @@ -11,34 +11,33 @@ import { } from 'node:zlib'; import { Blob } from 'node:buffer'; import { Readable, pipeline } from 'node:stream'; -import stream from 'node:stream'; +import { pipeline as pipelinePromise } from 'node:stream/promises'; import { basename } from 'node:path'; import { createReadStream } from 'node:fs'; import { format as urlFormat } from 'node:url'; import { performance } from 'node:perf_hooks'; import querystring from 'node:querystring'; +import { setTimeout as sleep } from 'node:timers/promises'; import { - FormData as FormDataNative, + FormData, request as undiciRequest, Dispatcher, Agent, getGlobalDispatcher, Pool, } from 'undici'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore import undiciSymbols from 'undici/lib/core/symbols.js'; -import { FormData as FormDataNode } from 'formdata-node'; -import { FormDataEncoder } from 'form-data-encoder'; -import createUserAgent from 'default-user-agent'; import mime from 'mime-types'; import qs from 'qs'; -import pump from 'pump'; // Compatible with old style formstream import FormStream from 'formstream'; import { HttpAgent, CheckAddressFunction } from './HttpAgent.js'; import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; import { RequestURL, RequestOptions, HttpMethod, RequestMeta } from './Request.js'; import { RawResponseWithMeta, HttpClientResponse, SocketInfo } from './Response.js'; -import { parseJSON, sleep, digestAuthHeader, globalId, performanceTime, isReadable } from './utils.js'; +import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable } from './utils.js'; import symbols from './symbols.js'; import { initDiagnosticsChannel } from './diagnosticsChannel.js'; import { HttpClientConnectTimeoutError, HttpClientRequestTimeoutError } from './HttpClientError.js'; @@ -49,24 +48,12 @@ type PropertyShouldBe = Omit & { [P in K]: V }; type IUndiciRequestOption = PropertyShouldBe; const PROTO_RE = /^https?:\/\//i; -const FormData = FormDataNative ?? FormDataNode; -// impl promise pipeline on Node.js 14 -const pipelinePromise = stream.promises?.pipeline ?? function pipeline(...args: any[]) { - return new Promise((resolve, reject) => { - pump(...args, (err?: Error) => { - if (err) return reject(err); - resolve(); - }); - }); -}; function noop() { // noop } const debug = debuglog('urllib:HttpClient'); -// Node.js 14 or 16 -const isNode14Or16 = /v1[46]\./.test(process.version); export type ClientOptions = { defaultArgs?: RequestOptions; @@ -125,7 +112,10 @@ class BlobFromStream { } } -export const HEADER_USER_AGENT = createUserAgent('node-urllib', 'VERSION'); +export const VERSION = 'VERSION'; +// 'node-urllib/4.0.0 Node.js/18.19.0 (darwin; x64)' +export const HEADER_USER_AGENT = + `node-urllib/${VERSION} Node.js/${process.version.substring(1)} (${process.platform}; ${process.arch})`; function getFileName(stream: Readable) { const filePath: string = (stream as any).path; @@ -207,13 +197,13 @@ export class HttpClient extends EventEmitter { getDispatcherPoolStats() { const agent = this.getDispatcher(); // origin => Pool Instance - const clients: Map> | undefined = agent[undiciSymbols.kClients]; + const clients: Map> | undefined = Reflect.get(agent, undiciSymbols.kClients); const poolStatsMap: Record = {}; if (!clients) { return poolStatsMap; } for (const [ key, ref ] of clients) { - const pool = ref.deref(); + const pool = typeof ref.deref === 'function' ? ref.deref() : ref as unknown as Pool; const stats = pool?.stats; if (!stats) continue; poolStatsMap[key] = { @@ -451,9 +441,11 @@ export class HttpClient extends EventEmitter { } else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) { uploadFiles.push([ 'file', args.files ]); } else if (typeof args.files === 'object') { - for (const field in args.files) { + const files = args.files as Record; + for (const field in files) { // set custom fileName - uploadFiles.push([ field, args.files[field], field ]); + const file = files[field]; + uploadFiles.push([ field, file, field ]); } } // set normal fields first @@ -478,18 +470,7 @@ export class HttpClient extends EventEmitter { isStreamingRequest = true; } } - - if (FormDataNative) { - requestOptions.body = formData; - } else { - // Node.js 14 does not support spec-compliant FormData - // https://github.com/octet-stream/form-data#usage - const encoder = new FormDataEncoder(formData as any); - Object.assign(headers, encoder.headers); - // fix "Content-Length":"NaN" - delete headers['Content-Length']; - requestOptions.body = Readable.from(encoder); - } + requestOptions.body = formData; } else if (args.content) { if (!isGETOrHEAD) { // handle content @@ -507,7 +488,7 @@ export class HttpClient extends EventEmitter { || isReadable(args.data); if (isGETOrHEAD) { if (!isStringOrBufferOrReadable) { - let query; + let query: string; if (args.nestedQuerystring) { query = qs.stringify(args.data); } else { @@ -608,9 +589,6 @@ export class HttpClient extends EventEmitter { res = Object.assign(response.body, res); } } else if (args.writeStream) { - if (isNode14Or16 && args.writeStream.destroyed) { - throw new Error('writeStream is destroyed'); - } if (args.compressed === true && isCompressedContent) { const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress(); await pipelinePromise(response.body, decoder, args.writeStream); diff --git a/src/diagnosticsChannel.ts b/src/diagnosticsChannel.ts index 97780e00..38b8e2a4 100644 --- a/src/diagnosticsChannel.ts +++ b/src/diagnosticsChannel.ts @@ -20,15 +20,14 @@ let initedDiagnosticsChannel = false; // -> undici:request:trailers => { request, trailers } function subscribe(name: string, listener: (message: unknown, channelName: string | symbol) => void) { - if (typeof diagnosticsChannel.subscribe === 'function') { - diagnosticsChannel.subscribe(name, listener); - } else { - // TODO: support Node.js 14, will be removed on the next major version - diagnosticsChannel.channel(name).subscribe(listener); - } + diagnosticsChannel.subscribe(name, listener); } -function formatSocket(socket: Socket) { +type SocketExtend = Socket & { + [key: symbol]: string | number | Date | undefined; +}; + +function formatSocket(socket: SocketExtend) { if (!socket) return socket; return { localAddress: socket[symbols.kSocketLocalAddress], @@ -41,8 +40,7 @@ function formatSocket(socket: Socket) { } // make sure error contains socket info -const kDestroy = Symbol('kDestroy'); -Socket.prototype[kDestroy] = Socket.prototype.destroy; +const destroySocket = Socket.prototype.destroy; Socket.prototype.destroy = function(err?: any) { if (err) { Object.defineProperty(err, symbols.kErrorSocket, { @@ -51,12 +49,12 @@ Socket.prototype.destroy = function(err?: any) { value: this, }); } - return this[kDestroy](err); + return destroySocket.call(this, err); }; function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol) { if (!kHandler) return; - const handler = request[kHandler]; + const handler = Reflect.get(request, kHandler); // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler { // responseHeaders: null, // opaque: { @@ -70,7 +68,7 @@ function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol } export function initDiagnosticsChannel() { - // makre sure init global DiagnosticsChannel once + // make sure init global DiagnosticsChannel once if (initedDiagnosticsChannel) return; initedDiagnosticsChannel = true; @@ -97,29 +95,27 @@ export function initDiagnosticsChannel() { opaque[symbols.kRequestTiming].queuing = performanceTime(opaque[symbols.kRequestStartTime]); }); - // diagnosticsChannel.channel('undici:client:beforeConnect') - subscribe('undici:client:connectError', (message, name) => { - const { error, connectParams } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any }; - let { socket } = message as DiagnosticsChannel.ClientConnectErrorMessage; - if (!socket && error[symbols.kErrorSocket]) { - socket = error[symbols.kErrorSocket]; + const { error, connectParams, socket } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any, socket: SocketExtend }; + let sock = socket; + if (!sock && error[symbols.kErrorSocket]) { + sock = error[symbols.kErrorSocket]; } - if (socket) { - socket[symbols.kSocketId] = globalId('UndiciSocket'); - socket[symbols.kSocketConnectErrorTime] = new Date(); - socket[symbols.kHandledRequests] = 0; - socket[symbols.kHandledResponses] = 0; + if (sock) { + sock[symbols.kSocketId] = globalId('UndiciSocket'); + sock[symbols.kSocketConnectErrorTime] = new Date(); + sock[symbols.kHandledRequests] = 0; + sock[symbols.kHandledResponses] = 0; // copy local address to symbol, avoid them be reset after request error throw - if (socket.localAddress) { - socket[symbols.kSocketLocalAddress] = socket.localAddress; - socket[symbols.kSocketLocalPort] = socket.localPort; + if (sock.localAddress) { + sock[symbols.kSocketLocalAddress] = sock.localAddress; + sock[symbols.kSocketLocalPort] = sock.localPort; } - socket[symbols.kSocketConnectProtocol] = connectParams.protocol; - socket[symbols.kSocketConnectHost] = connectParams.host; - socket[symbols.kSocketConnectPort] = connectParams.port; + sock[symbols.kSocketConnectProtocol] = connectParams.protocol; + sock[symbols.kSocketConnectHost] = connectParams.host; + sock[symbols.kSocketConnectPort] = connectParams.port; debug('[%s] Socket#%d connectError, connectParams: %o, error: %s, (sock: %o)', - name, socket[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(socket)); + name, sock[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(sock)); } else { debug('[%s] connectError, connectParams: %o, error: %o', name, connectParams, error); @@ -128,7 +124,7 @@ export function initDiagnosticsChannel() { // This message is published after a connection is established. subscribe('undici:client:connected', (message, name) => { - const { socket, connectParams } = message as DiagnosticsChannel.ClientConnectedMessage; + const { socket, connectParams } = message as DiagnosticsChannel.ClientConnectedMessage & { socket: SocketExtend }; socket[symbols.kSocketId] = globalId('UndiciSocket'); socket[symbols.kSocketStartTime] = performance.now(); socket[symbols.kSocketConnectedTime] = new Date(); @@ -145,11 +141,11 @@ export function initDiagnosticsChannel() { // This message is published right before the first byte of the request is written to the socket. subscribe('undici:client:sendHeaders', (message, name) => { - const { request, socket } = message as DiagnosticsChannel.ClientSendHeadersMessage; + const { request, socket } = message as DiagnosticsChannel.ClientSendHeadersMessage & { socket: SocketExtend }; const opaque = getRequestOpaque(request, kHandler); if (!opaque || !opaque[symbols.kRequestId]) return; - socket[symbols.kHandledRequests]++; + (socket[symbols.kHandledRequests] as number)++; // attach socket to opaque opaque[symbols.kRequestSocket] = socket; debug('[%s] Request#%d send headers on Socket#%d (handled %d requests, sock: %o)', @@ -158,11 +154,11 @@ export function initDiagnosticsChannel() { if (!opaque[symbols.kEnableRequestTiming]) return; opaque[symbols.kRequestTiming].requestHeadersSent = performanceTime(opaque[symbols.kRequestStartTime]); - // first socket need to caculate the connected time + // first socket need to calculate the connected time if (socket[symbols.kHandledRequests] === 1) { // kSocketStartTime - kRequestStartTime = connected time opaque[symbols.kRequestTiming].connected = - performanceTime(opaque[symbols.kRequestStartTime], socket[symbols.kSocketStartTime]); + performanceTime(opaque[symbols.kRequestStartTime], socket[symbols.kSocketStartTime] as number); } }); diff --git a/src/index.ts b/src/index.ts index cc3cec4d..6cbf7d1c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import LRU from 'ylru'; +import { LRU } from 'ylru'; import { HttpClient, HEADER_USER_AGENT } from './HttpClient.js'; import { RequestOptions, RequestURL } from './Request.js'; diff --git a/src/utils.ts b/src/utils.ts index bde49674..1f24c443 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,7 +3,7 @@ import { Readable } from 'node:stream'; import { performance } from 'node:perf_hooks'; import type { FixJSONCtlChars } from './Request.js'; -const JSONCtlCharsMap = { +const JSONCtlCharsMap: Record = { '"': '\\"', // \u0022 '\\': '\\\\', // \u005c '\b': '\\b', // \u0008 @@ -49,12 +49,6 @@ export function parseJSON(data: string, fixJSONCtlChars?: FixJSONCtlChars) { return data; } -export function sleep(ms: number) { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - function md5(s: string) { const sum = createHash('md5'); sum.update(s, 'utf8'); diff --git a/test/HttpClient.connect.rejectUnauthorized.test.ts b/test/HttpClient.connect.rejectUnauthorized.test.ts index 47591c8b..f28192ad 100644 --- a/test/HttpClient.connect.rejectUnauthorized.test.ts +++ b/test/HttpClient.connect.rejectUnauthorized.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import { HttpClient } from '../src'; -import { startServer } from './fixtures/server'; +import { HttpClient } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('HttpClient.connect.rejectUnauthorized.test.ts', () => { let close: any; diff --git a/test/HttpClient.events.test.ts b/test/HttpClient.events.test.ts index b1c4ce78..fb434c7c 100644 --- a/test/HttpClient.events.test.ts +++ b/test/HttpClient.events.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import { HttpClient } from '../src'; -import { startServer } from './fixtures/server'; +import { HttpClient } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('HttpClient.events.test.ts', () => { let close: any; diff --git a/test/HttpClient.test.ts b/test/HttpClient.test.ts index 07ecdacc..c9e02825 100644 --- a/test/HttpClient.test.ts +++ b/test/HttpClient.test.ts @@ -1,9 +1,8 @@ import { strict as assert } from 'node:assert'; import dns from 'node:dns'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import { HttpClient } from '../src'; -import { RawResponseWithMeta } from '../src/Response'; -import { startServer } from './fixtures/server'; +import { HttpClient, RawResponseWithMeta } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('HttpClient.test.ts', () => { let close: any; diff --git a/test/diagnostics_channel.test.ts b/test/diagnostics_channel.test.ts index a31f9f8b..f3796494 100644 --- a/test/diagnostics_channel.test.ts +++ b/test/diagnostics_channel.test.ts @@ -1,14 +1,14 @@ import { strict as assert } from 'node:assert'; import diagnosticsChannel from 'node:diagnostics_channel'; +import { setTimeout as sleep } from 'node:timers/promises'; import { describe, it, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; +import urllib from '../src/index.js'; import type { RequestDiagnosticsMessage, ResponseDiagnosticsMessage, -} from '../src'; -import symbols from '../src/symbols'; -import { startServer } from './fixtures/server'; -import { sleep } from './utils'; +} from '../src/index.js'; +import symbols from '../src/symbols.js'; +import { startServer } from './fixtures/server.js'; describe('diagnostics_channel.test.ts', () => { let close: any; @@ -62,9 +62,9 @@ describe('diagnostics_channel.test.ts', () => { lastRequestOpaque = opaque; // console.log(request); } - diagnosticsChannel.channel('undici:client:connected').subscribe(onMessage); - diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(onMessage); - diagnosticsChannel.channel('undici:request:trailers').subscribe(onMessage); + diagnosticsChannel.subscribe('undici:client:connected', onMessage); + diagnosticsChannel.subscribe('undici:client:sendHeaders', onMessage); + diagnosticsChannel.subscribe('undici:request:trailers', onMessage); let traceId = `mock-traceid-${Date.now()}`; // _url = 'https://registry.npmmirror.com/'; @@ -130,9 +130,9 @@ describe('diagnostics_channel.test.ts', () => { assert.equal(lastRequestOpaque.tracer.socket.requests, 2 + 1000 - count); } - diagnosticsChannel.channel('undici:client:connected').unsubscribe(onMessage); - diagnosticsChannel.channel('undici:client:sendHeaders').unsubscribe(onMessage); - diagnosticsChannel.channel('undici:request:trailers').unsubscribe(onMessage); + diagnosticsChannel.unsubscribe('undici:client:connected', onMessage); + diagnosticsChannel.unsubscribe('undici:client:sendHeaders', onMessage); + diagnosticsChannel.unsubscribe('undici:request:trailers', onMessage); }); it('should support trace request by urllib:request and urllib:response', async () => { @@ -147,8 +147,8 @@ describe('diagnostics_channel.test.ts', () => { socket = response.socket; assert.equal(request.args.opaque, lastRequestOpaque); } - diagnosticsChannel.channel('urllib:request').subscribe(onRequestMessage); - diagnosticsChannel.channel('urllib:response').subscribe(onResponseMessage); + diagnosticsChannel.subscribe('urllib:request', onRequestMessage); + diagnosticsChannel.subscribe('urllib:response', onResponseMessage); let traceId = `mock-traceid-${Date.now()}`; // _url = 'https://registry.npmmirror.com/'; @@ -218,8 +218,8 @@ describe('diagnostics_channel.test.ts', () => { assert.equal(socket.handledResponses, 2 + 1000 - count); } - diagnosticsChannel.channel('urllib:request').unsubscribe(onRequestMessage); - diagnosticsChannel.channel('urllib:response').unsubscribe(onResponseMessage); + diagnosticsChannel.unsubscribe('urllib:request', onRequestMessage); + diagnosticsChannel.unsubscribe('urllib:response', onResponseMessage); }); it('should support trace request error by urllib:request and urllib:response', async () => { @@ -236,8 +236,8 @@ describe('diagnostics_channel.test.ts', () => { assert.equal(request.args.opaque, lastRequestOpaque); lastError = error; } - diagnosticsChannel.channel('urllib:request').subscribe(onRequestMessage); - diagnosticsChannel.channel('urllib:response').subscribe(onResponseMessage); + diagnosticsChannel.subscribe('urllib:request', onRequestMessage); + diagnosticsChannel.subscribe('urllib:response', onResponseMessage); let traceId = `mock-traceid-${Date.now()}`; // handle network error @@ -311,7 +311,7 @@ describe('diagnostics_channel.test.ts', () => { assert.equal(socket.handledRequests, 2); assert.equal(socket.handledResponses, 2); - diagnosticsChannel.channel('urllib:request').unsubscribe(onRequestMessage); - diagnosticsChannel.channel('urllib:response').unsubscribe(onResponseMessage); + diagnosticsChannel.unsubscribe('urllib:request', onRequestMessage); + diagnosticsChannel.unsubscribe('urllib:response', onResponseMessage); }); }); diff --git a/test/fixtures/server.ts b/test/fixtures/server.ts index 1e62bb6e..6bdd593b 100644 --- a/test/fixtures/server.ts +++ b/test/fixtures/server.ts @@ -3,11 +3,12 @@ import { createServer, Server, IncomingMessage, ServerResponse } from 'node:http import { createServer as createHttpsServer } from 'node:https'; import { createBrotliCompress, createGzip, gzipSync, brotliCompressSync } from 'node:zlib'; import { createReadStream } from 'node:fs'; +import { setTimeout as sleep } from 'node:timers/promises'; import busboy from 'busboy'; import iconv from 'iconv-lite'; import selfsigned from 'selfsigned'; import qs from 'qs'; -import { readableToBytes, sleep } from '../utils'; +import { readableToBytes } from '../utils.js'; const requestsPerSocket = Symbol('requestsPerSocket'); diff --git a/test/index.test.ts b/test/index.test.ts index 90a677c0..9a403c2f 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -2,10 +2,12 @@ import { strict as assert } from 'node:assert'; import { parse as urlparse } from 'node:url'; import { readFileSync } from 'node:fs'; import { describe, it, beforeAll, afterAll, afterEach, beforeEach } from 'vitest'; -import urllib, { HttpClient, getDefaultHttpClient } from '../src'; -import { MockAgent, setGlobalDispatcher, getGlobalDispatcher } from '../src'; -import { startServer } from './fixtures/server'; -import { readableToBytes } from './utils'; +import urllib, { + HttpClient, getDefaultHttpClient, + MockAgent, setGlobalDispatcher, getGlobalDispatcher, +} from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { readableToBytes } from './utils.js'; describe('index.test.ts', () => { let close: any; diff --git a/test/keep-alive-header.test.ts b/test/keep-alive-header.test.ts index 3d797062..83e1d620 100644 --- a/test/keep-alive-header.test.ts +++ b/test/keep-alive-header.test.ts @@ -1,8 +1,9 @@ import { strict as assert } from 'node:assert'; +import { setTimeout as sleep } from 'node:timers/promises'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import { HttpClient } from '../src'; -import { startServer } from './fixtures/server'; -import { isWindows, nodeMajorVersion, sleep } from './utils'; +import { HttpClient } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { isWindows } from './utils.js'; describe('keep-alive-header.test.ts', () => { // should shorter than server keepalive timeout @@ -33,8 +34,8 @@ describe('keep-alive-header.test.ts', () => { const task = httpClient.request(_url); // console.log('after request stats: %o', httpClient.getDispatcherPoolStats()); if (httpClient.getDispatcherPoolStats()[origin]) { - if (!(nodeMajorVersion() === 14 || isWindows())) { - // ignore node = 14 & windows + if (!isWindows()) { + // ignore on windows assert.equal(httpClient.getDispatcherPoolStats()[origin].pending, 1); assert.equal(httpClient.getDispatcherPoolStats()[origin].size, 1); } @@ -42,7 +43,8 @@ describe('keep-alive-header.test.ts', () => { let response = await task; // console.log('after response stats: %o', httpClient.getDispatcherPoolStats()); assert.equal(httpClient.getDispatcherPoolStats()[origin].pending, 0); - assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 1); + // assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 1); + assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 0); // console.log(response.res.socket); assert.equal(response.status, 200); // console.log(response.headers); @@ -84,7 +86,7 @@ describe('keep-alive-header.test.ts', () => { // console.log(response.headers); assert.equal(response.headers.connection, 'keep-alive'); assert.equal(response.headers['keep-alive'], 'timeout=2'); - assert(parseInt(response.headers['x-requests-persocket'] as string) > 1); + assert(parseInt(response.headers['x-requests-persocket'] as string) >= 1, response.headers['x-requests-persocket'] as string); await sleep(keepAliveTimeout / 2); response = await httpClient.request(_url); // console.log(response.res.socket); @@ -128,11 +130,13 @@ describe('keep-alive-header.test.ts', () => { // console.log(response.headers); assert.equal(response.headers.connection, 'keep-alive'); assert.equal(response.headers['keep-alive'], 'timeout=2'); - assert(parseInt(response.headers['x-requests-persocket'] as string) > 1); + assert(parseInt(response.headers['x-requests-persocket'] as string) >= 1, response.headers['x-requests-persocket'] as string); // console.log('before sleep stats: %o', httpClient.getDispatcherPoolStats()); // { connected: 2, free: 1, pending: 0, queued: 0, running: 0, size: 0 } - assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 2); - assert.equal(httpClient.getDispatcherPoolStats()[origin].free, 1); + // assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 2); + assert.equal(httpClient.getDispatcherPoolStats()[origin].connected, 0); + // assert.equal(httpClient.getDispatcherPoolStats()[origin].free, 1); + assert.equal(httpClient.getDispatcherPoolStats()[origin].free, 0); await sleep(keepAliveTimeout); // console.log('after sleep stats: %o', httpClient.getDispatcherPoolStats()); // clients maybe all gone => after sleep stats: {} @@ -144,7 +148,7 @@ describe('keep-alive-header.test.ts', () => { assert(httpClient.getDispatcherPoolStats()[origin].free <= 2); assert.equal(httpClient.getDispatcherPoolStats()[origin].size, 0); } - } catch (err) { + } catch (err: any) { if (err.message === 'other side closed') { console.log(err); otherSideClosed++; diff --git a/test/non-ascii-request-header.test.ts b/test/non-ascii-request-header.test.ts index e7073f95..1517dd25 100644 --- a/test/non-ascii-request-header.test.ts +++ b/test/non-ascii-request-header.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; // https://github.com/node-modules/urllib/issues/198 describe('non-ascii-request-header.test.ts', () => { diff --git a/test/options.auth.test.ts b/test/options.auth.test.ts index aaeb8ea1..93b2bf65 100644 --- a/test/options.auth.test.ts +++ b/test/options.auth.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.auth.test.ts', () => { let close: any; diff --git a/test/options.compressed.test.ts b/test/options.compressed.test.ts index 1a17ad3b..ae64e486 100644 --- a/test/options.compressed.test.ts +++ b/test/options.compressed.test.ts @@ -1,9 +1,9 @@ import { strict as assert } from 'node:assert'; import { createWriteStream, createReadStream } from 'node:fs'; import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { readableToString, createTempfile, nodeMajorVersion } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { readableToString, createTempfile, nodeMajorVersion } from './utils.js'; describe('options.compressed.test.ts', () => { let close: any; diff --git a/test/options.content.test.ts b/test/options.content.test.ts index d8399522..0bcf9a8d 100644 --- a/test/options.content.test.ts +++ b/test/options.content.test.ts @@ -2,8 +2,8 @@ import { strict as assert } from 'node:assert'; import { createReadStream } from 'node:fs'; import { describe, it, beforeAll, afterAll } from 'vitest'; import fs from 'node:fs/promises'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.content.test.ts', () => { let close: any; diff --git a/test/options.data.test.ts b/test/options.data.test.ts index f804bc7f..55dd5508 100644 --- a/test/options.data.test.ts +++ b/test/options.data.test.ts @@ -3,8 +3,8 @@ import { createReadStream } from 'node:fs'; import { Readable } from 'node:stream'; import qs from 'qs'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.data.test.ts', () => { let close: any; diff --git a/test/options.dataType.test.ts b/test/options.dataType.test.ts index 725b7a58..36f32c1b 100644 --- a/test/options.dataType.test.ts +++ b/test/options.dataType.test.ts @@ -1,8 +1,8 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { nodeMajorVersion, readableToBytes } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { nodeMajorVersion, readableToBytes } from './utils.js'; describe('options.dataType.test.ts', () => { let close: any; diff --git a/test/options.digestAuth.test.ts b/test/options.digestAuth.test.ts index 463c9b61..e9385a3d 100644 --- a/test/options.digestAuth.test.ts +++ b/test/options.digestAuth.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.digestAuth.test.ts', () => { let close: any; diff --git a/test/options.dispatcher.test.ts b/test/options.dispatcher.test.ts index bde1e00e..ea133064 100644 --- a/test/options.dispatcher.test.ts +++ b/test/options.dispatcher.test.ts @@ -1,8 +1,8 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; import setup from 'proxy'; -import { request, ProxyAgent, getGlobalDispatcher, setGlobalDispatcher, Agent } from '../src'; -import { startServer } from './fixtures/server'; +import { request, ProxyAgent, getGlobalDispatcher, setGlobalDispatcher, Agent } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.dispatcher.test.ts', () => { let close: any; diff --git a/test/options.files.test.ts b/test/options.files.test.ts index 0550b5fc..60739d09 100644 --- a/test/options.files.test.ts +++ b/test/options.files.test.ts @@ -4,8 +4,8 @@ import fs from 'node:fs/promises'; import { createReadStream } from 'node:fs'; import { Readable } from 'node:stream'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.files.test.ts', () => { let close: any; @@ -274,7 +274,8 @@ describe('options.files.test.ts', () => { const response = await urllib.request(`${_url}multipart`, { files: { 'buffer.js': Buffer.from(rawData), - 'readable.js': Readable.from([ rawData ]), + // Readable.from data must be Buffer or Bytes + 'readable.js': Readable.from([ Buffer.from(rawData) ]), }, data: { hello: 'hello world,😄😓', diff --git a/test/options.fixJSONCtlChars.test.ts b/test/options.fixJSONCtlChars.test.ts index 381362e3..54b84849 100644 --- a/test/options.fixJSONCtlChars.test.ts +++ b/test/options.fixJSONCtlChars.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.fixJSONCtlChars.test.ts', () => { let close: any; diff --git a/test/options.followRedirect.test.ts b/test/options.followRedirect.test.ts index f001101b..1a399751 100644 --- a/test/options.followRedirect.test.ts +++ b/test/options.followRedirect.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.followRedirect.test.js', () => { let close: any; diff --git a/test/options.gzip.test.ts b/test/options.gzip.test.ts index 6f30d43e..292c9f35 100644 --- a/test/options.gzip.test.ts +++ b/test/options.gzip.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.gzip.test.ts', () => { let close: any; diff --git a/test/options.headers.test.ts b/test/options.headers.test.ts index 0b3e8ad1..12acfacc 100644 --- a/test/options.headers.test.ts +++ b/test/options.headers.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.headers.test.ts', () => { let close: any; diff --git a/test/options.method.test.ts b/test/options.method.test.ts index 6590d162..a3adadb7 100644 --- a/test/options.method.test.ts +++ b/test/options.method.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.method.test.ts', () => { let close: any; diff --git a/test/options.opaque.test.ts b/test/options.opaque.test.ts index 02d3287d..eccecc0a 100644 --- a/test/options.opaque.test.ts +++ b/test/options.opaque.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.opaque.test.ts', () => { let close: any; diff --git a/test/options.reset.test.ts b/test/options.reset.test.ts index 889ffcd0..590bd590 100644 --- a/test/options.reset.test.ts +++ b/test/options.reset.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.reset.test.ts', () => { let close: any; diff --git a/test/options.retry.test.ts b/test/options.retry.test.ts index 8313e64c..1b52f7bf 100644 --- a/test/options.retry.test.ts +++ b/test/options.retry.test.ts @@ -1,9 +1,9 @@ import { strict as assert } from 'node:assert'; import { createWriteStream, createReadStream } from 'node:fs'; import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { readableToString, createTempfile } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { readableToString, createTempfile } from './utils.js'; describe('options.retry.test.ts', () => { let close: any; diff --git a/test/options.signal.test.ts b/test/options.signal.test.ts index 3f2d4b85..6c67a8f1 100644 --- a/test/options.signal.test.ts +++ b/test/options.signal.test.ts @@ -1,9 +1,9 @@ import { strict as assert } from 'node:assert'; import { EventEmitter } from 'node:events'; +import { setTimeout as sleep } from 'node:timers/promises'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { sleep } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.signal.test.ts', () => { let close: any; @@ -18,7 +18,7 @@ describe('options.signal.test.ts', () => { await close(); }); - it.skipIf(typeof global.AbortController === 'undefined')('should throw error when AbortController abort', async () => { + it('should throw error when AbortController abort', async () => { await assert.rejects(async () => { const abortController = new AbortController(); const p = urllib.request(`${_url}?timeout=2000`, { @@ -28,10 +28,9 @@ describe('options.signal.test.ts', () => { abortController.abort(); await p; }, (err: any) => { - // console.error(err); assert.equal(err.name, 'AbortError'); - assert.equal(err.message, 'Request aborted'); - assert.equal(err.code, 'UND_ERR_ABORTED'); + assert.equal(err.message, 'This operation was aborted'); + assert.equal(err.code, 20); return true; }); }); diff --git a/test/options.socketErrorRetry.test.ts b/test/options.socketErrorRetry.test.ts index 1006241d..5831785c 100644 --- a/test/options.socketErrorRetry.test.ts +++ b/test/options.socketErrorRetry.test.ts @@ -1,9 +1,9 @@ import { strict as assert } from 'node:assert'; import { createWriteStream, createReadStream } from 'node:fs'; import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { createTempfile } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { createTempfile } from './utils.js'; describe('options.socketErrorRetry.test.ts', () => { let close: any; diff --git a/test/options.socketPath.test.ts b/test/options.socketPath.test.ts index c696222a..fc6bcf3c 100644 --- a/test/options.socketPath.test.ts +++ b/test/options.socketPath.test.ts @@ -1,8 +1,8 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/socket_server'; -import { isWindows } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/socket_server.js'; +import { isWindows } from './utils.js'; describe.skipIf(isWindows())('options.socketPath.test.ts', () => { let close: any; diff --git a/test/options.stream.test.ts b/test/options.stream.test.ts index 17a5f681..2c905488 100644 --- a/test/options.stream.test.ts +++ b/test/options.stream.test.ts @@ -7,10 +7,10 @@ import { Readable } from 'node:stream'; import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; import tar from 'tar-stream'; import FormStream from 'formstream'; -import urllib from '../src'; -import { isReadable } from '../src/utils'; -import { startServer } from './fixtures/server'; -import { createTempfile } from './utils'; +import urllib from '../src/index.js'; +import { isReadable } from '../src/utils.js'; +import { startServer } from './fixtures/server.js'; +import { createTempfile } from './utils.js'; describe('options.stream.test.ts', () => { let close: any; diff --git a/test/options.streaming.test.ts b/test/options.streaming.test.ts index a98f998a..f0e97dac 100644 --- a/test/options.streaming.test.ts +++ b/test/options.streaming.test.ts @@ -2,10 +2,10 @@ import { strict as assert } from 'node:assert'; import { pipeline } from 'node:stream'; import { createBrotliDecompress } from 'node:zlib'; import { describe, it, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; -import { isReadable } from '../src/utils'; -import { startServer } from './fixtures/server'; -import { readableToBytes } from './utils'; +import urllib from '../src/index.js'; +import { isReadable } from '../src/utils.js'; +import { startServer } from './fixtures/server.js'; +import { readableToBytes } from './utils.js'; describe('options.streaming.test.ts', () => { let close: any; diff --git a/test/options.timeout.test.ts b/test/options.timeout.test.ts index d5e9d521..b065096b 100644 --- a/test/options.timeout.test.ts +++ b/test/options.timeout.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib, { HttpClientRequestTimeoutError } from '../src'; -import { startServer } from './fixtures/server'; +import urllib, { HttpClientRequestTimeoutError } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.timeout.test.ts', () => { let close: any; @@ -25,12 +25,9 @@ describe('options.timeout.test.ts', () => { // console.error(err); assert.equal(err.name, 'HttpClientRequestTimeoutError'); assert.equal(err.message, 'Request timeout for 10 ms'); - if (err.cause) { - // not work on Node.js 14 - assert.equal(err.cause.name, 'HeadersTimeoutError'); - assert.equal(err.cause.message, 'Headers Timeout Error'); - assert.equal(err.cause.code, 'UND_ERR_HEADERS_TIMEOUT'); - } + assert.equal(err.cause.name, 'HeadersTimeoutError'); + assert.equal(err.cause.message, 'Headers Timeout Error'); + assert.equal(err.cause.code, 'UND_ERR_HEADERS_TIMEOUT'); assert.equal(err.res.status, -1); assert(err.res.rt > 10, `actual ${err.res.rt}`); diff --git a/test/options.timing.test.ts b/test/options.timing.test.ts index c6d2ca41..680686c2 100644 --- a/test/options.timing.test.ts +++ b/test/options.timing.test.ts @@ -1,9 +1,8 @@ import { strict as assert } from 'node:assert'; +import { setTimeout as sleep } from 'node:timers/promises'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { RawResponseWithMeta } from '../src/Response'; -import { startServer } from './fixtures/server'; -import { sleep } from './utils'; +import urllib, { RawResponseWithMeta } from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.timing.test.ts', () => { let close: any; diff --git a/test/options.type.test.ts b/test/options.type.test.ts index 91ffaabc..7bbf3049 100644 --- a/test/options.type.test.ts +++ b/test/options.type.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('options.type.test.ts', () => { let close: any; diff --git a/test/options.writeStream.test.ts b/test/options.writeStream.test.ts index 42cbfc20..bc17e41d 100644 --- a/test/options.writeStream.test.ts +++ b/test/options.writeStream.test.ts @@ -3,10 +3,11 @@ import { createWriteStream } from 'node:fs'; import { join } from 'node:path'; import { gunzipSync } from 'node:zlib'; import { stat, readFile } from 'node:fs/promises'; +import { setTimeout as sleep } from 'node:timers/promises'; import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; -import { createTempfile, sleep } from './utils'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; +import { createTempfile } from './utils.js'; describe('options.writeStream.test.ts', () => { let close: any; diff --git a/test/response-charset-gbk.test.ts b/test/response-charset-gbk.test.ts index c6735da1..3c929754 100644 --- a/test/response-charset-gbk.test.ts +++ b/test/response-charset-gbk.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('response-charset-gbk.test.ts', () => { let close: any; diff --git a/test/user-agent.test.ts b/test/user-agent.test.ts index 61e489dd..3d869e0b 100644 --- a/test/user-agent.test.ts +++ b/test/user-agent.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import urllib from '../src'; -import { startServer } from './fixtures/server'; +import urllib from '../src/index.js'; +import { startServer } from './fixtures/server.js'; describe('keep-alive-header.test.ts', () => { let close: any; diff --git a/test/utils.test.ts b/test/utils.test.ts index 92ba28a6..8d7f7ec0 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'node:assert'; import { describe, it } from 'vitest'; -import { globalId } from '../src/utils'; +import { globalId } from '../src/utils.js'; describe('utils.test.ts', () => { describe('globalId()', () => { diff --git a/test/utils.ts b/test/utils.ts index 61f36657..e3ff1044 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -5,12 +5,6 @@ import { join } from 'node:path'; import { tmpdir, platform } from 'node:os'; import { randomUUID } from 'node:crypto'; -export async function sleep(ms: number) { - await new Promise(resolve => { - setTimeout(resolve, ms); - }); -} - export async function readableToBytes(stream: Readable | ReadableStream) { const chunks: Buffer[] = []; let chunk: Buffer; diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index 91644d12..00000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ] -} diff --git a/tsconfig.json b/tsconfig.json index 241f0504..ff41b734 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,35 +1,10 @@ { + "extends": "@eggjs/tsconfig", "compilerOptions": { - "useUnknownInCatchVariables": true, - "allowSyntheticDefaultImports": true, - "declaration": true, - "downlevelIteration": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "importHelpers": false, - "module": "NodeNext", - "moduleResolution": "NodeNext", - "newLine": "LF", - "checkJs": false, - "allowJs": true, "strict": true, - "skipLibCheck": true, - "noImplicitAny": false, - "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, "target": "ES2022", - "sourceMap": false, - "esModuleInterop": true, - "stripInternal": true, - "lib": [ - "ES2022" - ], - "composite": true, - "types": [ - "node" - ], - "rootDir": "src" - }, - "include": [ - "src/**/*.ts" - ] + "module": "NodeNext", + "moduleResolution": "NodeNext" + } }