diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index d3c74609..5a5926ad 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,6 +13,6 @@ jobs: uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: os: 'ubuntu-latest, macos-latest, windows-latest' - version: '16, 18, 20, 22, 23' + version: '16, 18, 20, 22, 24' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/README.md b/README.md index be5fffae..f98564d6 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ content-type: application/json } ``` -This exmaple can use `options.data` with `application/json` content type: +This example can use `options.data` with `application/json` content type: ```js await request('https://example.com', { diff --git a/package.json b/package.json index 11b1ea1f..914c5ee1 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,9 @@ "test": "npm run lint -- --fix && vitest run", "test-keepalive": "cross-env TEST_KEEPALIVE_COUNT=50 vitest run --test-timeout 180000 keep-alive-header.test.ts", "test-node16": "node examples/httpclient.cjs && node examples/search_github.cjs && node examples/timing.cjs", - "cov": "cross-env NODE_OPTIONS='--require ./test/patch-structuredClone.cjs' vitest run --coverage", + "cov": "cross-env NODE_OPTIONS=\"--require ./test/patch-for-node16-18.cjs\" vitest run --coverage", "ci": "npm run lint && npm run cov && npm run prepublishOnly && npm pack && attw --pack", - "clean": "rm -rf dist", + "clean": "rm -rf dist && tsc -b --clean", "prepublishOnly": "npm run build" }, "dependencies": { @@ -74,11 +74,12 @@ "iconv-lite": "^0.6.3", "proxy": "^1.0.2", "selfsigned": "^2.4.1", + "string.prototype.towellformed": "^1.0.2", "tar-stream": "^2.2.0", "tshy": "^3.0.0", "tshy-after": "^1.0.0", "typescript": "^5.0.4", - "vitest": "^3.0.2" + "vitest": "^3.2.4" }, "engines": { "node": ">= 18.19.0" diff --git a/src/HttpClient.ts b/src/HttpClient.ts index d913cdad..fab557b3 100644 --- a/src/HttpClient.ts +++ b/src/HttpClient.ts @@ -227,9 +227,11 @@ export class HttpClient extends EventEmitter { return poolStatsMap; } for (const [ key, ref ] of clients) { - const pool = typeof ref.deref === 'function' ? ref.deref() : ref as unknown as Pool; - const stats = pool?.stats; + const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as (Pool & { dispatcher: Pool }); + // NOTE: pool become to { dispatcher: Pool } in undici@v7 + const stats = pool?.stats ?? pool?.dispatcher?.stats; if (!stats) continue; + poolStatsMap[key] = { connected: stats.connected, free: stats.free, diff --git a/src/fetch.ts b/src/fetch.ts index 7a7f09f5..48091d11 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -114,9 +114,11 @@ export class FetchFactory { return poolStatsMap; } for (const [ key, ref ] of clients) { - const pool = typeof ref.deref === 'function' ? ref.deref() : ref as unknown as Pool; - const stats = pool?.stats; + const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as (Pool & { dispatcher: Pool }); + // NOTE: pool become to { dispatcher: Pool } in undici@v7 + const stats = pool?.stats ?? pool?.dispatcher?.stats; if (!stats) continue; + poolStatsMap[key] = { connected: stats.connected, free: stats.free, diff --git a/test/HttpClient.test.ts b/test/HttpClient.test.ts index 0dc3c04a..cd2fa393 100644 --- a/test/HttpClient.test.ts +++ b/test/HttpClient.test.ts @@ -326,7 +326,8 @@ describe('HttpClient.test.ts', () => { const response = await httpclient.request(_url); assert.equal(response.status, 200); - assert.equal(Object.keys(httpclient.getDispatcherPoolStats()).length, 1); + assert.equal(Object.keys(httpclient.getDispatcherPoolStats()).length, 1, + `dispatcher pool stats: ${JSON.stringify(httpclient.getDispatcherPoolStats())}`); }); it('should check non-ip hostname with custom lookup', async () => { diff --git a/test/fetch.test.ts b/test/fetch.test.ts index 3667ceeb..e3c1b5cd 100644 --- a/test/fetch.test.ts +++ b/test/fetch.test.ts @@ -108,7 +108,7 @@ describe('fetch.test.ts', () => { const stats = FetchFactory.getDispatcherPoolStats(); assert(stats); - assert(Object.keys(stats).length > 0); + assert(Object.keys(stats).length > 0, `dispatcher pool stats: ${JSON.stringify(stats)}`); }); it('fetch request with post should work', async () => { diff --git a/test/fixtures/socket_server.ts b/test/fixtures/socket_server.ts index ea531304..8e1c2bd4 100644 --- a/test/fixtures/socket_server.ts +++ b/test/fixtures/socket_server.ts @@ -2,6 +2,7 @@ import { createServer, Server } from 'node:http'; const socketPathPrefix = '/tmp/urllib.unix.sock'; let index = 0; + export async function startServer(): Promise<{ server: Server, url: string, diff --git a/test/options.socketPath.test.ts b/test/options.socketPath.test.ts index fc6bcf3c..3e7fd6e8 100644 --- a/test/options.socketPath.test.ts +++ b/test/options.socketPath.test.ts @@ -19,7 +19,7 @@ describe.skipIf(isWindows())('options.socketPath.test.ts', () => { afterAll(async () => { await close(); - await server2.closeServer(); + await server2?.closeServer(); }); it('should request socket successfully', async () => { diff --git a/test/patch-for-node16-18.cjs b/test/patch-for-node16-18.cjs new file mode 100644 index 00000000..b140c688 --- /dev/null +++ b/test/patch-for-node16-18.cjs @@ -0,0 +1,18 @@ +// vitest require structuredClone +if (!('structuredClone' in globalThis)) { + const structuredClone = require('@ungap/structured-clone').default; + + globalThis.structuredClone = structuredClone; + // console.debug('patched structuredClone for Node.js %s', process.version); +} + +// vitest require crypto.getRandomValues +const crypto = require('node:crypto'); +if (typeof crypto.getRandomValues !== 'function') { + crypto.getRandomValues = crypto.webcrypto.getRandomValues.bind(crypto.webcrypto); +} + +// undici@v7 require String.prototype.toWellFormed, patch on Node.js 16 and 18 +if (typeof String.prototype.toWellFormed !== 'function') { + require('string.prototype.towellformed/auto'); +} diff --git a/test/patch-structuredClone.cjs b/test/patch-structuredClone.cjs deleted file mode 100644 index c5612599..00000000 --- a/test/patch-structuredClone.cjs +++ /dev/null @@ -1,7 +0,0 @@ -const structuredClone = require('@ungap/structured-clone').default; - -// vitest require structuredClone -if (!('structuredClone' in globalThis)) { - globalThis.structuredClone = structuredClone; - // console.debug('patched structuredClone for Node.js %s', process.version); -}