diff --git a/.github/workflows/nodejs-16.yml b/.github/workflows/nodejs-16.yml index a1c31fa1..93de72ec 100644 --- a/.github/workflows/nodejs-16.yml +++ b/.github/workflows/nodejs-16.yml @@ -2,22 +2,25 @@ name: Node.js 16 CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: - build: - + test: runs-on: ubuntu-latest + concurrency: + group: typecheck-${{ github.workflow }}-#${{ github.event.pull_request.number || github.head_ref || github.ref }} + cancel-in-progress: true steps: - uses: actions/checkout@v4 - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: 16 - run: npm install + - run: npm run ci - run: npm run prepublishOnly - run: node -v - - run: npm run test-node16 + - run: npm run test-node16 diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 5a5926ad..fbba518c 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -2,17 +2,85 @@ name: CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] merge_group: jobs: - Job: - name: Node.js - uses: node-modules/github-actions/.github/workflows/node-test.yml@master - with: - os: 'ubuntu-latest, macos-latest, windows-latest' - version: '16, 18, 20, 22, 24' - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + typecheck: + runs-on: ubuntu-latest + concurrency: + group: typecheck-${{ github.workflow }}-#${{ github.event.pull_request.number || github.head_ref || github.ref }} + cancel-in-progress: true + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + + - name: Install pnpm + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 + with: + node-version: '24' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run lint + run: pnpm run lint + + - name: Check dedupe + run: pnpm dedupe --check + + - name: Run typecheck + run: pnpm run typecheck + + - name: Run format check + run: pnpm run fmtcheck + + - name: Run build + run: pnpm run build + + test: + strategy: + fail-fast: false + matrix: + os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] + node: ['18', '20', '22', '24'] + + name: Test (${{ matrix.os }}, ${{ matrix.node }}) + runs-on: ${{ matrix.os }} + + concurrency: + group: test-${{ github.workflow }}-#${{ github.event.pull_request.number || github.head_ref || github.ref }}-(${{ matrix.os }}, ${{ matrix.node }}) + cancel-in-progress: true + + permissions: + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + + - name: Install pnpm + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 + with: + node-version: ${{ matrix.node }} + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run tests + run: pnpm run ci + + - name: Code Coverage + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5 + with: + use_oidc: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8d6a725..1a566906 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: Release on: push: - branches: [ master ] + branches: [master] jobs: release: diff --git a/.gitignore b/.gitignore index d1c87d62..7b8314e4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ test/fixtures/ts-esm/*.js .eslintcache .tshy* .idea/ -pnpm-lock.yaml diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 00000000..6685a6be --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,18 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "printWidth": 120, + "singleQuote": true, + "ignorePatterns": ["CHANGELOG.md", "pnpm-lock.yaml"], + "experimentalSortImports": { + "groups": [ + ["type-import"], + ["type-builtin", "value-builtin"], + ["type-external", "value-external", "type-internal", "value-internal"], + ["type-parent", "type-sibling", "type-index", "value-parent", "value-sibling", "value-index"], + ["ts-equals-import"], + ["unknown"] + ], + "newlinesBetween": true, + "order": "asc" + } +} diff --git a/.oxlintrc.json b/.oxlintrc.json index 731f4e85..28523821 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -3,9 +3,7 @@ "env": { "node": true }, - "extends": [ - "./node_modules/@eggjs/oxlint-config/.oxlintrc.json" - ], + "extends": ["./node_modules/@eggjs/oxlint-config/.oxlintrc.json"], "categories": { "correctness": "allow", "suspicious": "allow", @@ -126,4 +124,4 @@ "arrow-body-style": "allow", "prefer-destructuring": "allow" } -} \ No newline at end of file +} diff --git a/README.md b/README.md index f98564d6..e4099bdb 100644 --- a/README.md +++ b/README.md @@ -56,30 +56,30 @@ console.log('status: %s, body size: %d, headers: %j', res.status, data.length, r #### Arguments - **url** String | Object - The URL to request, either a String or a Object that return by [url.parse](https://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost). -- ***options*** Object - Optional - - ***method*** String - Request method, defaults to `GET`. Could be `GET`, `POST`, `DELETE` or `PUT`. Alias 'type'. - - ***data*** Object - Data to be sent. Will be stringify automatically. - - ***content*** String | [Buffer](https://nodejs.org/api/buffer.html) - Manually set the content of payload. If set, `data` will be ignored. - - ***stream*** [stream.Readable](https://nodejs.org/api/stream.html#stream_class_stream_readable) - Stream to be pipe to the remote. If set, `data` and `content` will be ignored. - - ***writeStream*** [stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable) - A writable stream to be piped by the response stream. Responding data will be write to this stream and `callback` will be called with `data` set `null` after finished writing. - - ***files*** {Array | Object | ReadStream | Buffer | String - The files will send with `multipart/form-data` format, base on `formstream`. If `method` not set, will use `POST` method by default. - - ***contentType*** String - Type of request data. Could be `json` (**Notes**: not use `application/json` here). If it's `json`, will auto set `Content-Type: application/json` header. - - ***dataType*** String - Type of response data. Could be `text` or `json`. If it's `text`, the `callback`ed `data` would be a String. If it's `json`, the `data` of callback would be a parsed JSON Object and will auto set `Accept: application/json` header. Default `callback`ed `data` would be a `Buffer`. - - ***fixJSONCtlChars*** Boolean - Fix the control characters (U+0000 through U+001F) before JSON parse response. Default is `false`. - - ***headers*** Object - Request headers. - - ***timeout*** Number | Array - Request timeout in milliseconds for connecting phase and response receiving phase. Default is `5000`. You can use `timeout: 5000` to tell urllib use same timeout on two phase or set them separately such as `timeout: [3000, 5000]`, which will set connecting timeout to 3s and response 5s. - - ***keepAliveTimeout*** `number | null` - Default is `4000`, 4 seconds - The timeout after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. - - ***auth*** String - `username:password` used in HTTP Basic Authorization. - - ***digestAuth*** String - `username:password` used in HTTP [Digest Authorization](https://en.wikipedia.org/wiki/Digest_access_authentication). - - ***followRedirect*** Boolean - follow HTTP 3xx responses as redirects. defaults to true. - - ***maxRedirects*** Number - The maximum number of redirects to follow, defaults to 10. - - ***formatRedirectUrl*** Function - Format the redirect url by yourself. Default is `url.resolve(from, to)`. - - ***beforeRequest*** Function - Before request hook, you can change every thing here. - - ***streaming*** Boolean - lets you get the `res` object when request connected, default `false`. alias `customResponse` - - ***compressed*** Boolean - Accept `gzip, br` response content and auto decode it, default is `false`. - - ***timing*** Boolean - Enable timing or not, default is `true`. - - ***socketPath*** String | null - request a unix socket service, default is `null`. - - ***highWaterMark*** Number - default is `67108864`, 64 KiB. +- **_options_** Object - Optional + - **_method_** String - Request method, defaults to `GET`. Could be `GET`, `POST`, `DELETE` or `PUT`. Alias 'type'. + - **_data_** Object - Data to be sent. Will be stringify automatically. + - **_content_** String | [Buffer](https://nodejs.org/api/buffer.html) - Manually set the content of payload. If set, `data` will be ignored. + - **_stream_** [stream.Readable](https://nodejs.org/api/stream.html#stream_class_stream_readable) - Stream to be pipe to the remote. If set, `data` and `content` will be ignored. + - **_writeStream_** [stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable) - A writable stream to be piped by the response stream. Responding data will be write to this stream and `callback` will be called with `data` set `null` after finished writing. + - **_files_** {Array | Object | ReadStream | Buffer | String - The files will send with `multipart/form-data` format, base on `formstream`. If `method` not set, will use `POST` method by default. + - **_contentType_** String - Type of request data. Could be `json` (**Notes**: not use `application/json` here). If it's `json`, will auto set `Content-Type: application/json` header. + - **_dataType_** String - Type of response data. Could be `text` or `json`. If it's `text`, the `callback`ed `data` would be a String. If it's `json`, the `data` of callback would be a parsed JSON Object and will auto set `Accept: application/json` header. Default `callback`ed `data` would be a `Buffer`. + - **_fixJSONCtlChars_** Boolean - Fix the control characters (U+0000 through U+001F) before JSON parse response. Default is `false`. + - **_headers_** Object - Request headers. + - **_timeout_** Number | Array - Request timeout in milliseconds for connecting phase and response receiving phase. Default is `5000`. You can use `timeout: 5000` to tell urllib use same timeout on two phase or set them separately such as `timeout: [3000, 5000]`, which will set connecting timeout to 3s and response 5s. + - **_keepAliveTimeout_** `number | null` - Default is `4000`, 4 seconds - The timeout after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by _keep-alive_ hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. + - **_auth_** String - `username:password` used in HTTP Basic Authorization. + - **_digestAuth_** String - `username:password` used in HTTP [Digest Authorization](https://en.wikipedia.org/wiki/Digest_access_authentication). + - **_followRedirect_** Boolean - follow HTTP 3xx responses as redirects. defaults to true. + - **_maxRedirects_** Number - The maximum number of redirects to follow, defaults to 10. + - **_formatRedirectUrl_** Function - Format the redirect url by yourself. Default is `url.resolve(from, to)`. + - **_beforeRequest_** Function - Before request hook, you can change every thing here. + - **_streaming_** Boolean - lets you get the `res` object when request connected, default `false`. alias `customResponse` + - **_compressed_** Boolean - Accept `gzip, br` response content and auto decode it, default is `false`. + - **_timing_** Boolean - Enable timing or not, default is `true`. + - **_socketPath_** String | null - request a unix socket service, default is `null`. + - **_highWaterMark_** Number - default is `67108864`, 64 KiB. #### Options: `options.data` diff --git a/examples/h2-other-side-closed-exit-0-fetch.cjs b/examples/h2-other-side-closed-exit-0-fetch.cjs index 00b3b6b5..4784c433 100644 --- a/examples/h2-other-side-closed-exit-0-fetch.cjs +++ b/examples/h2-other-side-closed-exit-0-fetch.cjs @@ -1,8 +1,10 @@ const { fetch, setGlobalDispatcher, Agent } = require('..'); -setGlobalDispatcher(new Agent({ - allowH2: true, -})); +setGlobalDispatcher( + new Agent({ + allowH2: true, + }), +); async function main() { for (let i = 0; i < 100; i++) { @@ -21,13 +23,15 @@ async function main() { } } -main().then(() => { - console.log('main end'); -}).catch(err => { - console.error('main error throw: %s', err); - // console.error(err); - process.exit(1); -}); +main() + .then(() => { + console.log('main end'); + }) + .catch((err) => { + console.error('main error throw: %s', err); + // console.error(err); + process.exit(1); + }); process.on('beforeExit', (...args) => { console.error('beforeExit', args); diff --git a/examples/h2-other-side-closed-exit-0.cjs b/examples/h2-other-side-closed-exit-0.cjs index a278ffe2..59c851c0 100644 --- a/examples/h2-other-side-closed-exit-0.cjs +++ b/examples/h2-other-side-closed-exit-0.cjs @@ -1,8 +1,10 @@ const { request, Agent, setGlobalDispatcher } = require('undici'); -setGlobalDispatcher(new Agent({ - allowH2: true, -})); +setGlobalDispatcher( + new Agent({ + allowH2: true, + }), +); async function main() { for (let i = 0; i < 100; i++) { @@ -21,13 +23,15 @@ async function main() { } } -main().then(() => { - console.log('main end'); -}).catch(err => { - console.error('main error throw: %s', err); - // console.error(err); - process.exit(1); -}); +main() + .then(() => { + console.log('main end'); + }) + .catch((err) => { + console.error('main error throw: %s', err); + // console.error(err); + process.exit(1); + }); process.on('beforeExit', (...args) => { console.error('beforeExit', args); diff --git a/examples/httpclient.cjs b/examples/httpclient.cjs index f3c6c704..8c011114 100644 --- a/examples/httpclient.cjs +++ b/examples/httpclient.cjs @@ -9,19 +9,20 @@ function tryHttpclient(HttpClient, name) { timing: true, }; const urllib = new HttpClient(); - urllib.on('response', function(info) { + urllib.on('response', function (info) { // console.log(name, httpAgent, httpAgent.getCurrentStatus()); // console.log(name, httpsAgent, httpsAgent.getCurrentStatus()); console.log('response', name, info.res); }); - urllib.request('https://nodejs.org', options) - .then(function() { + urllib + .request('https://nodejs.org', options) + .then(function () { return urllib.request('https://nodejs.org', options); }) - .then(function() { + .then(function () { return urllib.request('https://nodejs.org/en/', options); }) - .catch(function(err) { + .catch(function (err) { console.error('catch', err); }); } diff --git a/examples/longruning.cjs b/examples/longruning.cjs index 1db2b8ce..9adc34e9 100644 --- a/examples/longruning.cjs +++ b/examples/longruning.cjs @@ -21,13 +21,15 @@ async function main() { } } -main().then(() => { - console.log('main end'); -}).catch(err => { - console.error('main error throw: %s', err); - console.error(err); - process.exit(1); -}); +main() + .then(() => { + console.log('main end'); + }) + .catch((err) => { + console.error('main error throw: %s', err); + console.error(err); + process.exit(1); + }); // process.on('uncaughtException', (...args) => { // console.error('uncaughtException', args); diff --git a/examples/search_github.cjs b/examples/search_github.cjs index 1bd7cc53..22fb1975 100644 --- a/examples/search_github.cjs +++ b/examples/search_github.cjs @@ -2,14 +2,16 @@ var urllib = require('../'); -urllib.request('https://api.github.com/legacy/user/search/location:china', { - dataType: 'json', - timing: true, - timeout: 10000, -}).then(response => { - console.log(response); - console.log(response.data); -}); +urllib + .request('https://api.github.com/legacy/user/search/location:china', { + dataType: 'json', + timing: true, + timeout: 10000, + }) + .then((response) => { + console.log(response); + console.log(response.data); + }); // var https = require('https'); diff --git a/examples/timing.cjs b/examples/timing.cjs index d9e3e6a5..b970445b 100644 --- a/examples/timing.cjs +++ b/examples/timing.cjs @@ -19,8 +19,15 @@ async function request(index) { // dataType: 'json', }); console.log('---------------------------'); - console.log('No#%d: %s, content size: %d, requestUrls: %o, socket: %o, rt: %o', - index, res.statusCode, res.data.length, res.res.requestUrls, res.res.socket, res.res.rt); + console.log( + 'No#%d: %s, content size: %d, requestUrls: %o, socket: %o, rt: %o', + index, + res.statusCode, + res.data.length, + res.res.requestUrls, + res.res.socket, + res.res.rt, + ); console.log(res.res.timing); // console.log(res.res.timing, res.headers); // console.log(res.data); diff --git a/package.json b/package.json index 921f5403..850ea0b0 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,9 @@ }, "scripts": { "lint": "oxlint src test", + "fmt": "oxfmt", + "typecheck": "tsc --noEmit", + "fmtcheck": "oxfmt --check .", "prebuild": "npm run clean", "build": "tsc --version && tshy && tshy-after && npm run build:version", "postbuild": "rm -rf *.tsbuildinfo", @@ -40,7 +43,7 @@ "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-for-node16-18.cjs\" vitest run --coverage", - "ci": "npm run lint && npm run cov && npm run prepublishOnly && npm pack && attw --pack", + "ci": "npm run cov && npm run prepublishOnly && npm pack && attw --pack", "clean": "rm -rf dist && tsc -b --clean", "prepublishOnly": "npm run build" }, @@ -71,6 +74,7 @@ "busboy": "^1.6.0", "cross-env": "^10.0.0", "iconv-lite": "^0.6.3", + "oxfmt": "^0.17.0", "oxlint": "^1.11.0", "proxy": "^1.0.2", "selfsigned": "^3.0.0", @@ -111,5 +115,6 @@ ], "types": "./dist/commonjs/index.d.ts", "main": "./dist/commonjs/index.js", - "module": "./dist/esm/index.js" + "module": "./dist/esm/index.js", + "packageManager": "pnpm@10.24.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..553814c7 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3657 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + form-data: + specifier: ^4.0.1 + version: 4.0.4 + formstream: + specifier: ^1.5.1 + version: 1.5.2 + mime-types: + specifier: ^2.1.35 + version: 2.1.35 + qs: + specifier: ^6.12.1 + version: 6.14.0 + type-fest: + specifier: ^4.20.1 + version: 4.41.0 + undici: + specifier: ^7.1.1 + version: 7.15.0 + ylru: + specifier: ^2.0.0 + version: 2.0.0 + devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.18.0 + version: 0.18.2 + '@eggjs/oxlint-config': + specifier: ^1.0.0 + version: 1.0.0 + '@eggjs/tsconfig': + specifier: ^2.0.0 + version: 2.0.0 + '@tsconfig/node18': + specifier: ^18.2.1 + version: 18.2.4 + '@tsconfig/strictest': + specifier: ^2.0.2 + version: 2.0.5 + '@types/busboy': + specifier: ^1.5.0 + version: 1.5.4 + '@types/mime-types': + specifier: ^2.1.1 + version: 2.1.4 + '@types/node': + specifier: ^22.0.0 + version: 22.17.2 + '@types/proxy': + specifier: ^1.0.4 + version: 1.0.4 + '@types/qs': + specifier: ^6.9.7 + version: 6.14.0 + '@types/selfsigned': + specifier: ^2.0.1 + version: 2.1.0 + '@types/tar-stream': + specifier: ^2.2.2 + version: 2.2.3 + '@ungap/structured-clone': + specifier: ^1.2.1 + version: 1.3.0 + '@vitest/coverage-v8': + specifier: ^3.0.2 + version: 3.2.4(vitest@3.2.4(@types/node@22.17.2)) + busboy: + specifier: ^1.6.0 + version: 1.6.0 + cross-env: + specifier: ^10.0.0 + version: 10.0.0 + iconv-lite: + specifier: ^0.6.3 + version: 0.6.3 + oxfmt: + specifier: ^0.17.0 + version: 0.17.0 + oxlint: + specifier: ^1.11.0 + version: 1.12.0 + proxy: + specifier: ^1.0.2 + version: 1.0.2 + selfsigned: + specifier: ^3.0.0 + version: 3.0.1 + string.prototype.towellformed: + specifier: ^1.0.2 + version: 1.0.2 + tar-stream: + specifier: ^2.2.0 + version: 2.2.0 + tshy: + specifier: ^3.0.0 + version: 3.0.2 + tshy-after: + specifier: ^1.0.0 + version: 1.4.1 + typescript: + specifier: ^5.0.4 + version: 5.9.2 + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/node@22.17.2) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@andrewbranch/untar.js@1.0.3': + resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} + + '@arethetypeswrong/cli@0.18.2': + resolution: {integrity: sha512-PcFM20JNlevEDKBg4Re29Rtv2xvjvQZzg7ENnrWFSS0PHgdP2njibVFw+dRUhNkPgNfac9iUqO0ohAXqQL4hbw==} + engines: {node: '>=20'} + hasBin: true + + '@arethetypeswrong/core@0.18.2': + resolution: {integrity: sha512-GiwTmBFOU1/+UVNqqCGzFJYfBXEytUkiI+iRZ6Qx7KmUVtLm00sYySkfe203C9QtPG11yOz1ZaMek8dT/xnlgg==} + engines: {node: '>=20'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + + '@braidai/lang@1.1.2': + resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@eggjs/oxlint-config@1.0.0': + resolution: {integrity: sha512-3GfSoDftw7MS43naRk2SI7zXV6LJPrtD/S04DKOziu07jtltg5i1yn4cFuJPqS+EGBTF5bQ0kOGLd+SD4vRrmw==} + + '@eggjs/tsconfig@2.0.0': + resolution: {integrity: sha512-Isxjjkjyoo2EM2iO2oT60fXEyhSQFkGlFZ05FuNjR+6LVHmhs3fbul8y3zW7ymiZWyzGClN11R0nGEFgB1pSgg==} + engines: {node: '>=18.19.0'} + + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + + '@loaderkit/resolve@1.0.4': + resolution: {integrity: sha512-rJzYKVcV4dxJv+vW6jlvagF8zvGxHJ2+HTr1e2qOejfmGhAApgJHl8Aog4mMszxceTRiKTTbnpgmTO1bEZHV/A==} + + '@oxfmt/darwin-arm64@0.17.0': + resolution: {integrity: sha512-OMv0tOb+xiwSZKjYbM6TwMSP5QwFJlBGQmEsk98QJ30sHhdyC//0UvGKuR0KZuzZW4E0+k0rHDmos1Z5DmBEkA==} + cpu: [arm64] + os: [darwin] + + '@oxfmt/darwin-x64@0.17.0': + resolution: {integrity: sha512-trzidyzryKIdL/cLCYU9IwprgJegVBUrz1rqzOMe5is+qdgH/RxTCvhYUNFzxRHpil3g4QUYd2Ja831tc5Nehg==} + cpu: [x64] + os: [darwin] + + '@oxfmt/linux-arm64-gnu@0.17.0': + resolution: {integrity: sha512-KlwzidgvHznbUaaglZT1goTS30osTV553pfbKve9B1PyTDkluNDfm/polOaf3SVLN7wL/NNLFZRMupvJ1eJXAw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/linux-arm64-musl@0.17.0': + resolution: {integrity: sha512-+tbYJTocF4BNLaQQbc/xrBWTNgiU6zmYeF4NvRDxuuQjDOnmUZPn0EED3PZBRJyg4/YllhplHDo8x+gfcb9G3A==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/linux-x64-gnu@0.17.0': + resolution: {integrity: sha512-pEmv7zJIw2HpnA4Tn1xrfJNGi2wOH2+usT14Pkvf/c5DdB+pOir6k/5jzfe70+V3nEtmtV9Lm+spndN/y6+X7A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxfmt/linux-x64-musl@0.17.0': + resolution: {integrity: sha512-+DrFSCZWyFdtEAWR5xIBTV8GX0RA9iB+y7ZlJPRAXrNG8TdBY9vc7/MIGolIgrkMPK4mGMn07YG/qEyPY+iKaw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxfmt/win32-arm64@0.17.0': + resolution: {integrity: sha512-FoUZRR7mVpTYIaY/qz2BYwzqMnL+HsUxmMWAIy6nl29UEkDgxNygULJ4rIGY4/Axne41fhtldLrSGBOpwNm3jA==} + cpu: [arm64] + os: [win32] + + '@oxfmt/win32-x64@0.17.0': + resolution: {integrity: sha512-fBIcUpHmCwf3leWlo0cYwLb9Pd2mzxQlZYJX9dD9nylPvsxOnsy9fmsaflpj34O0JbQJN3Y0SRkoaCcHHlxFww==} + cpu: [x64] + os: [win32] + + '@oxlint-tsgolint/darwin-arm64@0.0.4': + resolution: {integrity: sha512-qL0zqIYdYrXl6ghTIHnhJkvyYy1eKz0P8YIEp59MjY3/zNiyk/gtyp8LkwZdqb9ezbcX9UDQhSuSO1wURJsq8g==} + cpu: [arm64] + os: [darwin] + + '@oxlint-tsgolint/darwin-x64@0.0.4': + resolution: {integrity: sha512-c3nSjqmDSKzemChAEUv/zy2e9cwgkkO/7rz4Y447+8pSbeZNHi3RrNpVHdrKL/Qep4pt6nFZE+6PoczZxHNQjg==} + cpu: [x64] + os: [darwin] + + '@oxlint-tsgolint/linux-arm64@0.0.4': + resolution: {integrity: sha512-P2BA54c/Ej5AGkChH1/7zMd6PwZfa+jnw8juB/JWops+BX+lbhbbBHz0cYduDBgWYjRo4e3OVJOTskqcpuMfNw==} + cpu: [arm64] + os: [linux] + + '@oxlint-tsgolint/linux-x64@0.0.4': + resolution: {integrity: sha512-hbgLpnDNicPrbHOAQ9nNfLOSrUrdWANP/umR7P/cwCc1sv66eEs7bm4G3mrhRU8aXFBJmbhdNqiDSUkYYvHWJQ==} + cpu: [x64] + os: [linux] + + '@oxlint-tsgolint/win32-arm64@0.0.4': + resolution: {integrity: sha512-ozKEppmwZhC5LMedClBEat6cXgBGUvxGOgsKK2ZZNE6zSScX7QbvJAOt3nWMGs8GQshHy/6ndMB33+uRloglQA==} + cpu: [arm64] + os: [win32] + + '@oxlint-tsgolint/win32-x64@0.0.4': + resolution: {integrity: sha512-gLfx+qogW21QcaRKFg6ARgra7tSPqyn+Ems3FgTUyxV4OpJYn7KsQroygxOWElqv6JUobtvHBrxdB6YhlvERbQ==} + cpu: [x64] + os: [win32] + + '@oxlint/darwin-arm64@1.12.0': + resolution: {integrity: sha512-Pv+Ho1uq2ny8g2P6JgQpaIUF1FHPL32DfOlZhKqmzDT3PydtFvZp/7zNyJE3BIXeTOOOG1Eg12hjZHMLsWxyNw==} + cpu: [arm64] + os: [darwin] + + '@oxlint/darwin-x64@1.12.0': + resolution: {integrity: sha512-kNXPH/7jXjX4pawrEWXQHOasOdOsrYKhskA1qYwLYcv/COVSoxOSElkQtQa+KxN5zzt3F02kBdWDndLpgJLbLQ==} + cpu: [x64] + os: [darwin] + + '@oxlint/linux-arm64-gnu@1.12.0': + resolution: {integrity: sha512-U7NETs02K55ZyDlgdhx4lWeFYbkUKcL+YcG+Ak70EyEt/BKIIVt4B84VdV1JzC71FErUipDYAwPJmxMREXr4Sg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxlint/linux-arm64-musl@1.12.0': + resolution: {integrity: sha512-e4Pb2eZu3V2BsiX4t4gyv9iJ8+KRT6bkoWM5uC9BLX7edsVchwLwL6LB2vPYusYdPPrxdjlFCg6ni+9wlw7FbQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/linux-x64-gnu@1.12.0': + resolution: {integrity: sha512-qJK98Dj/z7Nbm0xoz0nCCMFGy0W/kLewPzOK5QENxuUoQQ6ymt7/75rXOuTwAZJ6JFTarqfSuMAA0pka6Tmytw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxlint/linux-x64-musl@1.12.0': + resolution: {integrity: sha512-jNeltpHc1eonSev/bWKipJ7FI6+Rc7EXh6Y7E0pm8e95sc1klFA29FFVs3FjMA6CCa+SRT0u0nnNTTAtf2QOiQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxlint/win32-arm64@1.12.0': + resolution: {integrity: sha512-T3fpNZJ3Q9YGgJTKc1YyvGoomSXnrV5mREz0QACE06zUzfS8EWyaYc/GN17FhHvQ4uQk/1xLgnM6FPsuLMeRhw==} + cpu: [arm64] + os: [win32] + + '@oxlint/win32-x64@1.12.0': + resolution: {integrity: sha512-2eC4XQ1SMM2z7bCDG+Ifrn5GrvP6fkL0FGi4ZwDCrx6fwb1byFrXgSUNIPiqiiqBBrFRMKlXzU9zD6IjuFlUOg==} + cpu: [x64] + os: [win32] + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rollup/rollup-android-arm-eabi@4.48.0': + resolution: {integrity: sha512-aVzKH922ogVAWkKiyKXorjYymz2084zrhrZRXtLrA5eEx5SO8Dj0c/4FpCHZyn7MKzhW2pW4tK28vVr+5oQ2xw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.48.0': + resolution: {integrity: sha512-diOdQuw43xTa1RddAFbhIA8toirSzFMcnIg8kvlzRbK26xqEnKJ/vqQnghTAajy2Dcy42v+GMPMo6jq67od+Dw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.48.0': + resolution: {integrity: sha512-QhR2KA18fPlJWFefySJPDYZELaVqIUVnYgAOdtJ+B/uH96CFg2l1TQpX19XpUMWUqMyIiyY45wje8K6F4w4/CA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.48.0': + resolution: {integrity: sha512-Q9RMXnQVJ5S1SYpNSTwXDpoQLgJ/fbInWOyjbCnnqTElEyeNvLAB3QvG5xmMQMhFN74bB5ZZJYkKaFPcOG8sGg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.48.0': + resolution: {integrity: sha512-3jzOhHWM8O8PSfyft+ghXZfBkZawQA0PUGtadKYxFqpcYlOYjTi06WsnYBsbMHLawr+4uWirLlbhcYLHDXR16w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.48.0': + resolution: {integrity: sha512-NcD5uVUmE73C/TPJqf78hInZmiSBsDpz3iD5MF/BuB+qzm4ooF2S1HfeTChj5K4AV3y19FFPgxonsxiEpy8v/A==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.48.0': + resolution: {integrity: sha512-JWnrj8qZgLWRNHr7NbpdnrQ8kcg09EBBq8jVOjmtlB3c8C6IrynAJSMhMVGME4YfTJzIkJqvSUSVJRqkDnu/aA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.48.0': + resolution: {integrity: sha512-9xu92F0TxuMH0tD6tG3+GtngwdgSf8Bnz+YcsPG91/r5Vgh5LNofO48jV55priA95p3c92FLmPM7CvsVlnSbGQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.48.0': + resolution: {integrity: sha512-NLtvJB5YpWn7jlp1rJiY0s+G1Z1IVmkDuiywiqUhh96MIraC0n7XQc2SZ1CZz14shqkM+XN2UrfIo7JB6UufOA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.48.0': + resolution: {integrity: sha512-QJ4hCOnz2SXgCh+HmpvZkM+0NSGcZACyYS8DGbWn2PbmA0e5xUk4bIP8eqJyNXLtyB4gZ3/XyvKtQ1IFH671vQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loongarch64-gnu@4.48.0': + resolution: {integrity: sha512-Pk0qlGJnhILdIC5zSKQnprFjrGmjfDM7TPZ0FKJxRkoo+kgMRAg4ps1VlTZf8u2vohSicLg7NP+cA5qE96PaFg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-gnu@4.48.0': + resolution: {integrity: sha512-/dNFc6rTpoOzgp5GKoYjT6uLo8okR/Chi2ECOmCZiS4oqh3mc95pThWma7Bgyk6/WTEvjDINpiBCuecPLOgBLQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-gnu@4.48.0': + resolution: {integrity: sha512-YBwXsvsFI8CVA4ej+bJF2d9uAeIiSkqKSPQNn0Wyh4eMDY4wxuSp71BauPjQNCKK2tD2/ksJ7uhJ8X/PVY9bHQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.48.0': + resolution: {integrity: sha512-FI3Rr2aGAtl1aHzbkBIamsQyuauYtTF9SDUJ8n2wMXuuxwchC3QkumZa1TEXYIv/1AUp1a25Kwy6ONArvnyeVQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.48.0': + resolution: {integrity: sha512-Dx7qH0/rvNNFmCcIRe1pyQ9/H0XO4v/f0SDoafwRYwc2J7bJZ5N4CHL/cdjamISZ5Cgnon6iazAVRFlxSoHQnQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.48.0': + resolution: {integrity: sha512-GUdZKTeKBq9WmEBzvFYuC88yk26vT66lQV8D5+9TgkfbewhLaTHRNATyzpQwwbHIfJvDJ3N9WJ90wK/uR3cy3Q==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.48.0': + resolution: {integrity: sha512-ao58Adz/v14MWpQgYAb4a4h3fdw73DrDGtaiF7Opds5wNyEQwtO6M9dBh89nke0yoZzzaegq6J/EXs7eBebG8A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-win32-arm64-msvc@4.48.0': + resolution: {integrity: sha512-kpFno46bHtjZVdRIOxqaGeiABiToo2J+st7Yce+aiAoo1H0xPi2keyQIP04n2JjDVuxBN6bSz9R6RdTK5hIppw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.48.0': + resolution: {integrity: sha512-rFYrk4lLk9YUTIeihnQMiwMr6gDhGGSbWThPEDfBoU/HdAtOzPXeexKi7yU8jO+LWRKnmqPN9NviHQf6GDwBcQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.48.0': + resolution: {integrity: sha512-sq0hHLTgdtwOPDB5SJOuaoHyiP1qSwg+71TQWk8iDS04bW1wIE0oQ6otPiRj2ZvLYNASLMaTp8QRGUVZ+5OL5A==} + cpu: [x64] + os: [win32] + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@tsconfig/node18@18.2.4': + resolution: {integrity: sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==} + + '@tsconfig/strictest@2.0.5': + resolution: {integrity: sha512-ec4tjL2Rr0pkZ5hww65c+EEPYwxOi4Ryv+0MtjeaSQRJyq322Q27eOQiFbuNgw2hpL4hB1/W/HBGk3VKS43osg==} + + '@types/busboy@1.5.4': + resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + + '@types/chai@5.2.2': + resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/mime-types@2.1.4': + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + + '@types/node@22.17.2': + resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==} + + '@types/proxy@1.0.4': + resolution: {integrity: sha512-KnYy7hpp3wXQ2U0ExvCMF9BvWZ6h2aI0XWb8g705mn26Zmn2HO/eLRi6UuhHELA6MNJtYtiZYWv38gobJN0xXQ==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/selfsigned@2.1.0': + resolution: {integrity: sha512-9IpB+OBu3QaMojPbLMg0PxMA85lOt7o53ycx2ds82CSFMyxlj0iZtAPVJ1m1qnzKTlznYqa6zNVaEWC7hk/E/w==} + deprecated: This is a stub types definition. selfsigned provides its own type definitions, so you do not need this installed. + + '@types/tar-stream@2.2.3': + resolution: {integrity: sha512-if3mugZfjVkXOMZdFjIHySxY13r6GXPpyOlsDmLffvyI7tLz9wXE8BFjNivXsvUeyJ1KNlOpfLnag+ISmxgxPw==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitest/coverage-v8@3.2.4': + resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} + peerDependencies: + '@vitest/browser': 3.2.4 + vitest: 3.2.4 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + args@5.0.1: + resolution: {integrity: sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==} + engines: {node: '>= 6.0.0'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-v8-to-istanbul@0.3.4: + resolution: {integrity: sha512-cxrAnZNLBnQwBPByK4CeDaw5sWZtMilJE/Q3iDA0aamgaIVNDF9T6K2/8DfYDZEejZ2jNnDrG9m8MY72HFd0KA==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + basic-auth-parser@0.0.2: + resolution: {integrity: sha512-Y7OBvWn+JnW45JWHLY6ybYub2k9cXCMrtCyO1Hds2s6eqClqWhPnOQpgXUPjAiMHj+A8TEPIQQ1dYENnJoBOHQ==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + camelcase@5.0.0: + resolution: {integrity: sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==} + engines: {node: '>=6'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.0: + resolution: {integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + cross-env@10.0.0: + resolution: {integrity: sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==} + engines: {node: '>=20'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + formstream@1.5.2: + resolution: {integrity: sha512-NASf0lgxC1AyKNXQIrXTEYkiX99LhCEXTkiGObXAkpBui86a4u8FjH1o2bGb3PpqI3kafC+yw4zWeK6l6VHTgg==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + leven@2.1.0: + resolution: {integrity: sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==} + engines: {node: '>=0.10.0'} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + + magic-string@0.30.18: + resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + marked-terminal@7.3.0: + resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <16' + + marked@9.1.6: + resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} + engines: {node: '>= 16'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + mri@1.1.4: + resolution: {integrity: sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + + node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + + node-hex@1.0.1: + resolution: {integrity: sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ==} + engines: {node: '>=8.0.0'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + oxfmt@0.17.0: + resolution: {integrity: sha512-12Rmq2ub61rUZ3Pqnsvmo99rRQ6hQJwQsjnFnbvXYLMrlIsWT6SFVsrjAkBBrkXXSHv8ePIpKQ0nZph5KDrOqw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + oxlint-tsgolint@0.0.4: + resolution: {integrity: sha512-KFWVP+VU3ymgK/Dtuf6iRkqjo+aN42lS1YThY6JWlNi1GQqm7wtio/kAwssqDhm8kP+CVXbgZAtu1wgsK4XeTg==} + hasBin: true + + oxlint@1.12.0: + resolution: {integrity: sha512-tBQ9aB00aYLlGXE21WJHnKQAI8xoi2V6Eiz/WvGV7FwU9YLYuNOurEEVbfoS5u0ODX8GLvGWj1fdHh5Rb74Kkw==} + engines: {node: '>=8.*'} + hasBin: true + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + polite-json@5.0.0: + resolution: {integrity: sha512-OLS/0XeUAcE8a2fdwemNja+udKgXNnY6yKVIXqAD2zVRx1KvY6Ato/rZ2vdzbxqYwPW0u6SCNC/bAMPNzpzxbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + proxy@1.0.2: + resolution: {integrity: sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==} + hasBin: true + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-import@2.0.0: + resolution: {integrity: sha512-jpKjLibLuc8D1XEV2+7zb0aqN7I8d12u89g/v6IsgCzdVlccMQJq4TKkPw5fbhHdxhm7nbVtN+KvOTnjFf+nEA==} + engines: {node: 20 || >=22} + + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + + rollup@4.48.0: + resolution: {integrity: sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + selfsigned@3.0.1: + resolution: {integrity: sha512-6U6w6kSLrM9Zxo0D7mC7QdGS6ZZytMWBnj/vhF9p+dAHx6CwGezuRcO4VclTbrrI7mg7SD6zNiqXUuBHOVopNQ==} + engines: {node: '>=10'} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.towellformed@1.0.2: + resolution: {integrity: sha512-qusT1OKg083o5gTeUI86HywOMABeJWWbcC936o/TXnzXE6VEQo23S5a2JIzd2pWeS8N3aNUWDOxwTIsrJTTJug==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + + sync-content@2.0.1: + resolution: {integrity: sha512-NI1mo514yFhr8pV/5Etvgh+pSBUIpoAKoiBIUwALVlQQNAwb40bTw8hhPFaip/dvv0GhpHVOq0vq8iY02ppLTg==} + engines: {node: 20 || >=22} + hasBin: true + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + test-exclude@7.0.1: + resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} + engines: {node: '>=18'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.3: + resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tshy-after@1.4.1: + resolution: {integrity: sha512-EVUiYSR59AGOy8I8eElVYKlR5bK/7ufAOv3H190HNu3sc9f3CP6Dn5QQfPIYzvg3kCt88NkTwx7n+xR8AQCCmw==} + hasBin: true + + tshy@3.0.2: + resolution: {integrity: sha512-8GkWnAfmNXxl8iDTZ1o2H4jdaj9H7HeDKkr5qd0ZhQBCNA41D3xqTyg2Ycs51VCfmjJ5e+0v9AUmD6ylAI9Bgw==} + engines: {node: 20 || >=22} + hasBin: true + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript@5.6.1-rc: + resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.15.0: + resolution: {integrity: sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==} + engines: {node: '>=20.18.1'} + + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.1.3: + resolution: {integrity: sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + ylru@2.0.0: + resolution: {integrity: sha512-T6hTrKcr9lKeUG0MQ/tO72D3UGptWVohgzpHG8ljU1jeBt2RCjcWxvsTPD8ZzUq1t1FvwROAw1kxg2euvg/THg==} + engines: {node: '>= 18.19.0'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@andrewbranch/untar.js@1.0.3': {} + + '@arethetypeswrong/cli@0.18.2': + dependencies: + '@arethetypeswrong/core': 0.18.2 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.3.0(marked@9.1.6) + semver: 7.7.2 + + '@arethetypeswrong/core@0.18.2': + dependencies: + '@andrewbranch/untar.js': 1.0.3 + '@loaderkit/resolve': 1.0.4 + cjs-module-lexer: 1.4.3 + fflate: 0.8.2 + lru-cache: 11.1.0 + semver: 7.7.2 + typescript: 5.6.1-rc + validate-npm-package-name: 5.0.1 + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@bcoe/v8-coverage@1.0.2': {} + + '@braidai/lang@1.1.2': {} + + '@colors/colors@1.5.0': + optional: true + + '@eggjs/oxlint-config@1.0.0': {} + + '@eggjs/tsconfig@2.0.0': {} + + '@epic-web/invariant@1.0.0': {} + + '@esbuild/aix-ppc64@0.25.9': + optional: true + + '@esbuild/android-arm64@0.25.9': + optional: true + + '@esbuild/android-arm@0.25.9': + optional: true + + '@esbuild/android-x64@0.25.9': + optional: true + + '@esbuild/darwin-arm64@0.25.9': + optional: true + + '@esbuild/darwin-x64@0.25.9': + optional: true + + '@esbuild/freebsd-arm64@0.25.9': + optional: true + + '@esbuild/freebsd-x64@0.25.9': + optional: true + + '@esbuild/linux-arm64@0.25.9': + optional: true + + '@esbuild/linux-arm@0.25.9': + optional: true + + '@esbuild/linux-ia32@0.25.9': + optional: true + + '@esbuild/linux-loong64@0.25.9': + optional: true + + '@esbuild/linux-mips64el@0.25.9': + optional: true + + '@esbuild/linux-ppc64@0.25.9': + optional: true + + '@esbuild/linux-riscv64@0.25.9': + optional: true + + '@esbuild/linux-s390x@0.25.9': + optional: true + + '@esbuild/linux-x64@0.25.9': + optional: true + + '@esbuild/netbsd-arm64@0.25.9': + optional: true + + '@esbuild/netbsd-x64@0.25.9': + optional: true + + '@esbuild/openbsd-arm64@0.25.9': + optional: true + + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + + '@esbuild/sunos-x64@0.25.9': + optional: true + + '@esbuild/win32-arm64@0.25.9': + optional: true + + '@esbuild/win32-ia32@0.25.9': + optional: true + + '@esbuild/win32-x64@0.25.9': + optional: true + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@loaderkit/resolve@1.0.4': + dependencies: + '@braidai/lang': 1.1.2 + + '@oxfmt/darwin-arm64@0.17.0': + optional: true + + '@oxfmt/darwin-x64@0.17.0': + optional: true + + '@oxfmt/linux-arm64-gnu@0.17.0': + optional: true + + '@oxfmt/linux-arm64-musl@0.17.0': + optional: true + + '@oxfmt/linux-x64-gnu@0.17.0': + optional: true + + '@oxfmt/linux-x64-musl@0.17.0': + optional: true + + '@oxfmt/win32-arm64@0.17.0': + optional: true + + '@oxfmt/win32-x64@0.17.0': + optional: true + + '@oxlint-tsgolint/darwin-arm64@0.0.4': + optional: true + + '@oxlint-tsgolint/darwin-x64@0.0.4': + optional: true + + '@oxlint-tsgolint/linux-arm64@0.0.4': + optional: true + + '@oxlint-tsgolint/linux-x64@0.0.4': + optional: true + + '@oxlint-tsgolint/win32-arm64@0.0.4': + optional: true + + '@oxlint-tsgolint/win32-x64@0.0.4': + optional: true + + '@oxlint/darwin-arm64@1.12.0': + optional: true + + '@oxlint/darwin-x64@1.12.0': + optional: true + + '@oxlint/linux-arm64-gnu@1.12.0': + optional: true + + '@oxlint/linux-arm64-musl@1.12.0': + optional: true + + '@oxlint/linux-x64-gnu@1.12.0': + optional: true + + '@oxlint/linux-x64-musl@1.12.0': + optional: true + + '@oxlint/win32-arm64@1.12.0': + optional: true + + '@oxlint/win32-x64@1.12.0': + optional: true + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@rollup/rollup-android-arm-eabi@4.48.0': + optional: true + + '@rollup/rollup-android-arm64@4.48.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.48.0': + optional: true + + '@rollup/rollup-darwin-x64@4.48.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.48.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.48.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.48.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.48.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.48.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.48.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.48.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.48.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.48.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.48.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.48.0': + optional: true + + '@sindresorhus/is@4.6.0': {} + + '@tsconfig/node18@18.2.4': {} + + '@tsconfig/strictest@2.0.5': {} + + '@types/busboy@1.5.4': + dependencies: + '@types/node': 22.17.2 + + '@types/chai@5.2.2': + dependencies: + '@types/deep-eql': 4.0.2 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/mime-types@2.1.4': {} + + '@types/node@22.17.2': + dependencies: + undici-types: 6.21.0 + + '@types/proxy@1.0.4': + dependencies: + '@types/node': 22.17.2 + + '@types/qs@6.14.0': {} + + '@types/selfsigned@2.1.0': + dependencies: + selfsigned: 3.0.1 + + '@types/tar-stream@2.2.3': + dependencies: + '@types/node': 22.17.2 + + '@ungap/structured-clone@1.3.0': {} + + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@22.17.2))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.4 + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.18 + magicast: 0.3.5 + std-env: 3.9.0 + test-exclude: 7.0.1 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/node@22.17.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.1.3(@types/node@22.17.2))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.18 + optionalDependencies: + vite: 7.1.3(@types/node@22.17.2) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.0.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.18 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.3 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.0: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + args@5.0.1: + dependencies: + camelcase: 5.0.0 + chalk: 2.4.2 + leven: 2.1.0 + mri: 1.1.4 + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@0.3.4: + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + estree-walker: 3.0.3 + js-tokens: 9.0.1 + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + basic-auth-parser@0.0.2: {} + + binary-extensions@2.3.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + camelcase@5.0.0: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.0: {} + + char-regex@1.0.2: {} + + check-error@2.1.1: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + cjs-module-lexer@1.4.3: {} + + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@10.0.1: {} + + cross-env@10.0.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + destroy@1.2.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + emojilib@2.4.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + environment@1.1.0: {} + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.2.2: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fflate@0.8.2: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formstream@1.5.2: + dependencies: + destroy: 1.2.0 + mime: 2.6.0 + node-hex: 1.0.1 + pause-stream: 0.0.11 + + fs-constants@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + highlight.js@10.7.3: {} + + html-escaper@2.0.2: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + + js-tokens@9.0.1: {} + + leven@2.1.0: {} + + loupe@3.2.1: {} + + lru-cache@10.4.3: {} + + lru-cache@11.1.0: {} + + magic-string@0.30.18: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + + marked-terminal@7.3.0(marked@9.1.6): + dependencies: + ansi-escapes: 7.0.0 + ansi-regex: 6.2.0 + chalk: 5.6.0 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + + marked@9.1.6: {} + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.2: {} + + mkdirp@3.0.1: {} + + mri@1.1.4: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + + node-forge@1.3.1: {} + + node-hex@1.0.1: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + oxfmt@0.17.0: + optionalDependencies: + '@oxfmt/darwin-arm64': 0.17.0 + '@oxfmt/darwin-x64': 0.17.0 + '@oxfmt/linux-arm64-gnu': 0.17.0 + '@oxfmt/linux-arm64-musl': 0.17.0 + '@oxfmt/linux-x64-gnu': 0.17.0 + '@oxfmt/linux-x64-musl': 0.17.0 + '@oxfmt/win32-arm64': 0.17.0 + '@oxfmt/win32-x64': 0.17.0 + + oxlint-tsgolint@0.0.4: + optionalDependencies: + '@oxlint-tsgolint/darwin-arm64': 0.0.4 + '@oxlint-tsgolint/darwin-x64': 0.0.4 + '@oxlint-tsgolint/linux-arm64': 0.0.4 + '@oxlint-tsgolint/linux-x64': 0.0.4 + '@oxlint-tsgolint/win32-arm64': 0.0.4 + '@oxlint-tsgolint/win32-x64': 0.0.4 + optional: true + + oxlint@1.12.0: + optionalDependencies: + '@oxlint/darwin-arm64': 1.12.0 + '@oxlint/darwin-x64': 1.12.0 + '@oxlint/linux-arm64-gnu': 1.12.0 + '@oxlint/linux-arm64-musl': 1.12.0 + '@oxlint/linux-x64-gnu': 1.12.0 + '@oxlint/linux-x64-musl': 1.12.0 + '@oxlint/win32-arm64': 1.12.0 + '@oxlint/win32-x64': 1.12.0 + oxlint-tsgolint: 0.0.4 + + package-json-from-dist@1.0.1: {} + + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + polite-json@5.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + proxy@1.0.2: + dependencies: + args: 5.0.1 + basic-auth-parser: 0.0.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + resolve-import@2.0.0: + dependencies: + glob: 11.0.3 + walk-up-path: 4.0.0 + + rimraf@6.0.1: + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + + rollup@4.48.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.48.0 + '@rollup/rollup-android-arm64': 4.48.0 + '@rollup/rollup-darwin-arm64': 4.48.0 + '@rollup/rollup-darwin-x64': 4.48.0 + '@rollup/rollup-freebsd-arm64': 4.48.0 + '@rollup/rollup-freebsd-x64': 4.48.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.48.0 + '@rollup/rollup-linux-arm-musleabihf': 4.48.0 + '@rollup/rollup-linux-arm64-gnu': 4.48.0 + '@rollup/rollup-linux-arm64-musl': 4.48.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.48.0 + '@rollup/rollup-linux-ppc64-gnu': 4.48.0 + '@rollup/rollup-linux-riscv64-gnu': 4.48.0 + '@rollup/rollup-linux-riscv64-musl': 4.48.0 + '@rollup/rollup-linux-s390x-gnu': 4.48.0 + '@rollup/rollup-linux-x64-gnu': 4.48.0 + '@rollup/rollup-linux-x64-musl': 4.48.0 + '@rollup/rollup-win32-arm64-msvc': 4.48.0 + '@rollup/rollup-win32-ia32-msvc': 4.48.0 + '@rollup/rollup-win32-x64-msvc': 4.48.0 + fsevents: 2.3.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + selfsigned@3.0.1: + dependencies: + node-forge: 1.3.1 + + semver@7.7.2: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.9.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamsearch@1.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string.prototype.towellformed@1.0.2: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.2.0 + + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + sync-content@2.0.1: + dependencies: + glob: 11.0.3 + mkdirp: 3.0.1 + path-scurry: 2.0.0 + rimraf: 6.0.1 + tshy: 3.0.2 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + test-exclude@7.0.1: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 10.4.5 + minimatch: 9.0.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through@2.3.8: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.3: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tshy-after@1.4.1: {} + + tshy@3.0.2: + dependencies: + chalk: 5.6.0 + chokidar: 3.6.0 + foreground-child: 3.3.1 + minimatch: 10.0.3 + mkdirp: 3.0.1 + polite-json: 5.0.0 + resolve-import: 2.0.0 + rimraf: 6.0.1 + sync-content: 2.0.1 + typescript: 5.9.2 + walk-up-path: 4.0.0 + + type-fest@4.41.0: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.6.1-rc: {} + + typescript@5.9.2: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + undici@7.15.0: {} + + unicode-emoji-modifier-base@1.0.0: {} + + util-deprecate@1.0.2: {} + + validate-npm-package-name@5.0.1: {} + + vite-node@3.2.4(@types/node@22.17.2): + dependencies: + cac: 6.7.14 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.1.3(@types/node@22.17.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.1.3(@types/node@22.17.2): + dependencies: + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.48.0 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 22.17.2 + fsevents: 2.3.3 + + vitest@3.2.4(@types/node@22.17.2): + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.1.3(@types/node@22.17.2)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.1 + expect-type: 1.2.2 + magic-string: 0.30.18 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.1.3(@types/node@22.17.2) + vite-node: 3.2.4(@types/node@22.17.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.17.2 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + walk-up-path@4.0.0: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + y18n@5.0.8: {} + + yargs-parser@20.2.9: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + ylru@2.0.0: {} diff --git a/renovate.json b/renovate.json index 5db72dd6..22a99432 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ] + "extends": ["config:recommended"] } diff --git a/scripts/replace_urllib_version.js b/scripts/replace_urllib_version.js index eac94165..7a469c03 100644 --- a/scripts/replace_urllib_version.js +++ b/scripts/replace_urllib_version.js @@ -6,15 +6,12 @@ import path from 'node:path'; async function main() { const root = process.cwd(); const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'))); - const files = [ - path.join(root, 'dist/commonjs/HttpClient.js'), - path.join(root, 'dist/esm/HttpClient.js'), - ]; + const files = [path.join(root, 'dist/commonjs/HttpClient.js'), path.join(root, 'dist/esm/HttpClient.js')]; for (const file of files) { const content = await fs.readFile(file, 'utf-8'); // replace "const VERSION = 'VERSION';" to "const VERSION = '4.0.0';" // "exports.VERSION = 'VERSION';" => "exports.VERSION = '4.0.0';" - const newContent = content.replace(/ = 'VERSION';/, match => { + const newContent = content.replace(/ = 'VERSION';/, (match) => { const after = ` = '${pkg.version}';`; console.log('[%s] %s => %s', file, match, after); return after; diff --git a/src/BaseAgent.ts b/src/BaseAgent.ts index 9003ea55..49834eb5 100644 --- a/src/BaseAgent.ts +++ b/src/BaseAgent.ts @@ -1,8 +1,7 @@ -import { - Agent, - Dispatcher, -} from 'undici'; import { AsyncLocalStorage } from 'node:async_hooks'; + +import { Agent, Dispatcher } from 'undici'; + import { FetchOpaque } from './FetchOpaqueInterceptor.js'; export interface BaseAgentOptions extends Agent.Options { diff --git a/src/FetchOpaqueInterceptor.ts b/src/FetchOpaqueInterceptor.ts index 66647003..1ea89909 100644 --- a/src/FetchOpaqueInterceptor.ts +++ b/src/FetchOpaqueInterceptor.ts @@ -1,5 +1,6 @@ // const { AsyncLocalStorage } = require('node:async_hooks'); import { AsyncLocalStorage } from 'node:async_hooks'; + import symbols from './symbols.js'; // const RedirectHandler = require('../handler/redirect-handler') diff --git a/src/FormData.ts b/src/FormData.ts index 3f8d7f3e..3a3cd810 100644 --- a/src/FormData.ts +++ b/src/FormData.ts @@ -1,4 +1,5 @@ import path from 'node:path'; + import _FormData from 'form-data'; // eslint-disable-next-line @@ -29,7 +30,7 @@ export class FormData extends _FormData { // support non-ascii filename contentDisposition = 'filename="' + filename + '"'; if (NON_ASCII_RE.test(filename)) { - contentDisposition += '; filename*=UTF-8\'\'' + encodeURIComponent(filename); + contentDisposition += "; filename*=UTF-8''" + encodeURIComponent(filename); } } diff --git a/src/HttpAgent.ts b/src/HttpAgent.ts index 69befdeb..cbe6450b 100644 --- a/src/HttpAgent.ts +++ b/src/HttpAgent.ts @@ -1,10 +1,8 @@ import dns from 'node:dns'; import { LookupFunction, isIP } from 'node:net'; -import { - Agent, - Dispatcher, - buildConnector, -} from 'undici'; + +import { Agent, Dispatcher, buildConnector } from 'undici'; + import { BaseAgent, BaseAgentOptions } from './BaseAgent.js'; export type CheckAddressFunction = (ip: string, family: number | string, hostname: string) => boolean; @@ -12,7 +10,7 @@ export type CheckAddressFunction = (ip: string, family: number | string, hostnam export interface HttpAgentOptions extends BaseAgentOptions { lookup?: LookupFunction; checkAddress?: CheckAddressFunction; - connect?: buildConnector.BuildOptions, + connect?: buildConnector.BuildOptions; allowH2?: boolean; } @@ -52,7 +50,7 @@ export class HttpAgent extends BaseAgent { err = new IllegalAddressError(hostname, address, family); } } else if (Array.isArray(address)) { - const addresses = address as { address: string, family: number }[]; + const addresses = address as { address: string; family: number }[]; for (const addr of addresses) { if (!options.checkAddress(addr.address, addr.family, hostname)) { err = new IllegalAddressError(hostname, addr.address, addr.family); diff --git a/src/HttpClient.ts b/src/HttpClient.ts index b2b9f12c..fda8912f 100644 --- a/src/HttpClient.ts +++ b/src/HttpClient.ts @@ -1,46 +1,37 @@ import diagnosticsChannel from 'node:diagnostics_channel'; import { EventEmitter } from 'node:events'; -import { LookupFunction } from 'node:net'; +import { createReadStream } from 'node:fs'; import { STATUS_CODES } from 'node:http'; -import { debuglog } from 'node:util'; -import { - createGunzip, - createBrotliDecompress, - gunzipSync, - brotliDecompressSync, -} from 'node:zlib'; -import { Readable, pipeline } from 'node:stream'; -import { pipeline as pipelinePromise } from 'node:stream/promises'; +import { LookupFunction } from 'node:net'; 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 { Readable, pipeline } from 'node:stream'; +import { pipeline as pipelinePromise } from 'node:stream/promises'; import { setTimeout as sleep } from 'node:timers/promises'; -import { - request as undiciRequest, - Dispatcher, - Agent, - getGlobalDispatcher, - Pool, -} from 'undici'; +import { format as urlFormat } from 'node:url'; +import { debuglog } from 'node:util'; +import { createGunzip, createBrotliDecompress, gunzipSync, brotliDecompressSync } from 'node:zlib'; + +// Compatible with old style formstream +import FormStream from 'formstream'; +import mime from 'mime-types'; +import qs from 'qs'; +import { 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 mime from 'mime-types'; -import qs from 'qs'; -// Compatible with old style formstream -import FormStream from 'formstream'; + +import { initDiagnosticsChannel } from './diagnosticsChannel.js'; +import { FetchOpaque } from './FetchOpaqueInterceptor.js'; import { FormData } from './FormData.js'; import { HttpAgent, CheckAddressFunction } from './HttpAgent.js'; +import { HttpClientConnectTimeoutError, HttpClientRequestTimeoutError } from './HttpClientError.js'; import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; import { RequestURL, RequestOptions, HttpMethod, RequestMeta } from './Request.js'; import { RawResponseWithMeta, HttpClientResponse, SocketInfo } from './Response.js'; -import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable, updateSocketInfo } from './utils.js'; import symbols from './symbols.js'; -import { initDiagnosticsChannel } from './diagnosticsChannel.js'; -import { HttpClientConnectTimeoutError, HttpClientRequestTimeoutError } from './HttpClientError.js'; -import { FetchOpaque } from './FetchOpaqueInterceptor.js'; +import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable, updateSocketInfo } from './utils.js'; type Exists = T extends undefined ? never : T; type UndiciRequestOption = Exists[1]>; @@ -88,23 +79,23 @@ export type ClientOptions = { */ lookup?: LookupFunction; /** - * check request address to protect from SSRF and similar attacks. - * It receive two arguments(ip and family) and should return true or false to identified the address is legal or not. - * It rely on lookup and have the same version requirement. - */ + * check request address to protect from SSRF and similar attacks. + * It receive two arguments(ip and family) and should return true or false to identified the address is legal or not. + * It rely on lookup and have the same version requirement. + */ checkAddress?: CheckAddressFunction; connect?: { key?: string | Buffer; /** - * A string or Buffer containing the certificate key of the client in PEM format. - * Notes: This is necessary only if using the client certificate authentication - */ + * A string or Buffer containing the certificate key of the client in PEM format. + * Notes: This is necessary only if using the client certificate authentication + */ cert?: string | Buffer; /** - * If `true`, the server certificate is verified against the list of supplied CAs. - * An 'error' event is emitted if verification fails. - * Default: `true` - */ + * If `true`, the server certificate is verified against the list of supplied CAs. + * An 'error' event is emitted if verification fails. + * Default: `true` + */ rejectUnauthorized?: boolean; /** * socketPath string | null (optional) - Default: null - An IPC endpoint, either Unix domain socket or Windows named pipe @@ -114,13 +105,12 @@ export type ClientOptions = { * connect timeout, default is 10000ms */ timeout?: number; - }, + }; }; 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})`; +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; @@ -231,8 +221,8 @@ export class HttpClient extends EventEmitter { if (!clients) { return poolStatsMap; } - for (const [ key, ref ] of clients) { - const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as (Pool & { dispatcher: Pool }); + for (const [key, ref] of clients) { + 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; @@ -258,7 +248,11 @@ export class HttpClient extends EventEmitter { return await this.request(url, options); } - async #requestInternal(url: RequestURL, options?: RequestOptions, requestContext?: RequestContext): Promise> { + async #requestInternal( + url: RequestURL, + options?: RequestOptions, + requestContext?: RequestContext, + ): Promise> { const requestId = globalId('HttpClientRequest'); let requestUrl: URL; if (typeof url === 'string') { @@ -472,20 +466,20 @@ export class HttpClient extends EventEmitter { const formData = new FormData(); const uploadFiles: [string, string | Readable | Buffer, string?][] = []; if (Array.isArray(args.files)) { - for (const [ index, file ] of args.files.entries()) { + for (const [index, file] of args.files.entries()) { const field = index === 0 ? 'file' : `file${index}`; - uploadFiles.push([ field, file ]); + uploadFiles.push([field, file]); } } else if (args.files instanceof Readable || isReadable(args.files as any)) { - uploadFiles.push([ 'file', args.files as Readable ]); + uploadFiles.push(['file', args.files as Readable]); } else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) { - uploadFiles.push([ 'file', args.files ]); + uploadFiles.push(['file', args.files]); } else if (typeof args.files === 'object') { const files = args.files as Record; for (const field in files) { // set custom fileName const file = files[field]; - uploadFiles.push([ field, file, field ]); + uploadFiles.push([field, file, field]); } } // set normal fields first @@ -494,7 +488,7 @@ export class HttpClient extends EventEmitter { formData.append(field, args.data[field]); } } - for (const [ index, [ field, file, customFileName ]] of uploadFiles.entries()) { + for (const [index, [field, file, customFileName]] of uploadFiles.entries()) { let fileName = ''; let value: any; if (typeof file === 'string') { @@ -513,8 +507,7 @@ export class HttpClient extends EventEmitter { filename: fileName, contentType: mimeType, }); - debug('formData append field: %s, mimeType: %s, fileName: %s', - field, mimeType, fileName); + debug('formData append field: %s, mimeType: %s, fileName: %s', field, mimeType, fileName); } Object.assign(headers, formData.getHeaders()); requestOptions.body = formData; @@ -530,9 +523,8 @@ export class HttpClient extends EventEmitter { isStreamingRequest = isReadable(args.content); } } else if (args.data) { - const isStringOrBufferOrReadable = typeof args.data === 'string' - || Buffer.isBuffer(args.data) - || isReadable(args.data); + const isStringOrBufferOrReadable = + typeof args.data === 'string' || Buffer.isBuffer(args.data) || isReadable(args.data); if (isGETOrHEAD) { if (!isStringOrBufferOrReadable) { let query: string; @@ -550,9 +542,11 @@ export class HttpClient extends EventEmitter { requestOptions.body = args.data; isStreamingRequest = isReadable(args.data); } else { - if (args.contentType === 'json' - || args.contentType === 'application/json' - || headers['content-type']?.startsWith('application/json')) { + if ( + args.contentType === 'json' || + args.contentType === 'application/json' || + headers['content-type']?.startsWith('application/json') + ) { requestOptions.body = JSON.stringify(args.data); if (!headers['content-type']) { headers['content-type'] = 'application/json'; @@ -578,8 +572,19 @@ export class HttpClient extends EventEmitter { args.socketErrorRetry = 0; } - debug('Request#%d %s %s, headers: %j, headersTimeout: %s, bodyTimeout: %s, isStreamingRequest: %s, isStreamingResponse: %s, maxRedirections: %s, redirects: %s', - requestId, requestOptions.method, requestUrl.href, headers, headersTimeout, bodyTimeout, isStreamingRequest, isStreamingResponse, maxRedirects, requestContext.redirects); + debug( + 'Request#%d %s %s, headers: %j, headersTimeout: %s, bodyTimeout: %s, isStreamingRequest: %s, isStreamingResponse: %s, maxRedirections: %s, redirects: %s', + requestId, + requestOptions.method, + requestUrl.href, + headers, + headersTimeout, + bodyTimeout, + isStreamingRequest, + isStreamingResponse, + maxRedirects, + requestContext.redirects, + ); requestOptions.headers = headers; channels.request.publish({ request: reqMeta, @@ -589,17 +594,25 @@ export class HttpClient extends EventEmitter { } let response = await undiciRequest(requestUrl, requestOptions as UndiciRequestOption); - if (response.statusCode === 401 && (response.headers['www-authenticate'] || response.headers['x-www-authenticate']) && - !requestOptions.headers.authorization && args.digestAuth) { + if ( + response.statusCode === 401 && + (response.headers['www-authenticate'] || response.headers['x-www-authenticate']) && + !requestOptions.headers.authorization && + args.digestAuth + ) { // handle digest auth const authenticateHeaders = response.headers['www-authenticate'] ?? response.headers['x-www-authenticate']; const authenticate = Array.isArray(authenticateHeaders) - ? authenticateHeaders.find(authHeader => authHeader.startsWith('Digest ')) + ? authenticateHeaders.find((authHeader) => authHeader.startsWith('Digest ')) : authenticateHeaders; if (authenticate && authenticate.startsWith('Digest ')) { debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', requestId, requestUrl.href, authenticate); - requestOptions.headers.authorization = digestAuthHeader(requestOptions.method!, - `${requestUrl.pathname}${requestUrl.search}`, authenticate, args.digestAuth); + requestOptions.headers.authorization = digestAuthHeader( + requestOptions.method!, + `${requestUrl.pathname}${requestUrl.search}`, + authenticate, + args.digestAuth, + ); debug('Request#%d %s: auth with digest header: %s', requestId, url, requestOptions.headers.authorization); if (Array.isArray(response.headers['set-cookie'])) { // FIXME: merge exists cookie header @@ -627,8 +640,14 @@ export class HttpClient extends EventEmitter { const nextUrl = new URL(res.headers.location, requestUrl.href); // Ensure the response is consumed await response.body.arrayBuffer(); - debug('Request#%d got response, status: %s, headers: %j, timing: %j, redirect to %s', - requestId, res.status, res.headers, res.timing, nextUrl.href); + debug( + 'Request#%d got response, status: %s, headers: %j, timing: %j, redirect to %s', + requestId, + res.status, + res.headers, + res.timing, + nextUrl.href, + ); return await this.#requestInternal(nextUrl.href, options, requestContext); } } @@ -690,8 +709,14 @@ export class HttpClient extends EventEmitter { res, }; - debug('Request#%d got response, status: %s, headers: %j, timing: %j, socket: %j', - requestId, res.status, res.headers, res.timing, res.socket); + debug( + 'Request#%d got response, status: %s, headers: %j, timing: %j, socket: %j', + requestId, + res.status, + res.headers, + res.timing, + res.socket, + ); if (args.retry > 0 && requestContext.retries < args.retry) { const isRetry = args.isRetry ?? defaultIsRetry; @@ -723,8 +748,13 @@ export class HttpClient extends EventEmitter { return clientResponse; } catch (rawError: any) { - debug('Request#%d throw error: %s, socketErrorRetry: %s, socketErrorRetries: %s', - requestId, rawError, args.socketErrorRetry, requestContext.socketErrorRetries); + debug( + 'Request#%d throw error: %s, socketErrorRetry: %s, socketErrorRetries: %s', + requestId, + rawError, + args.socketErrorRetry, + requestContext.socketErrorRetries, + ); let err = rawError; if (err.name === 'HeadersTimeoutError') { err = new HttpClientRequestTimeoutError(headersTimeout, { cause: err }); @@ -738,8 +768,11 @@ export class HttpClient extends EventEmitter { // auto retry on socket error, https://github.com/node-modules/urllib/issues/454 if (args.socketErrorRetry > 0 && requestContext.socketErrorRetries < args.socketErrorRetry) { requestContext.socketErrorRetries++; - debug('Request#%d retry on socket error, socketErrorRetries: %d', - requestId, requestContext.socketErrorRetries); + debug( + 'Request#%d retry on socket error, socketErrorRetries: %d', + requestId, + requestContext.socketErrorRetries, + ); return await this.#requestInternal(url, options, requestContext); } } diff --git a/src/HttpClientError.ts b/src/HttpClientError.ts index 3a15e3bf..36957db2 100644 --- a/src/HttpClientError.ts +++ b/src/HttpClientError.ts @@ -1,5 +1,5 @@ -import type { RawResponseWithMeta, SocketInfo } from './Response.js'; import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; +import type { RawResponseWithMeta, SocketInfo } from './Response.js'; // need to support ES2021 interface ErrorOptions { diff --git a/src/IncomingHttpHeaders.ts b/src/IncomingHttpHeaders.ts index adc42aac..571fa265 100644 --- a/src/IncomingHttpHeaders.ts +++ b/src/IncomingHttpHeaders.ts @@ -1,6 +1,7 @@ -import type { Except } from 'type-fest'; import type { IncomingHttpHeaders as HTTPIncomingHttpHeaders } from 'node:http'; +import type { Except } from 'type-fest'; + // fix set-cookie type define https://github.com/nodejs/undici/pull/1893 export interface IncomingHttpHeaders extends Except { 'set-cookie'?: string | string[]; diff --git a/src/Request.ts b/src/Request.ts index bcd81ea5..0d91a8d6 100644 --- a/src/Request.ts +++ b/src/Request.ts @@ -1,9 +1,11 @@ -import type { Readable, Writable } from 'node:stream'; import type { EventEmitter } from 'node:events'; +import type { Readable, Writable } from 'node:stream'; + import type { Dispatcher } from 'undici'; +import { Request } from 'undici'; + import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; import type { HttpClientResponse } from './Response.js'; -import { Request } from 'undici'; export type HttpMethod = Dispatcher.HttpMethod; @@ -36,10 +38,16 @@ export type RequestOptions = { */ writeStream?: Writable; /** - * The files will send with multipart/form-data format, base on formstream. - * If method not set, will use POST method by default. - */ - files?: Array | Record | Readable | Buffer | string | object; + * The files will send with multipart/form-data format, base on formstream. + * If method not set, will use POST method by default. + */ + files?: + | Array + | Record + | Readable + | Buffer + | string + | object; /** Type of request data, could be 'json'. If it's 'json', will auto set Content-Type: 'application/json' header. */ contentType?: string; /** @@ -165,5 +173,5 @@ export type RequestMeta = { export type FetchMeta = { requestId: number; - request: Request, + request: Request; }; diff --git a/src/Response.ts b/src/Response.ts index fcf4b615..aa613bed 100644 --- a/src/Response.ts +++ b/src/Response.ts @@ -1,4 +1,5 @@ import type { Readable } from 'node:stream'; + import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; export type SocketInfo = { diff --git a/src/diagnosticsChannel.ts b/src/diagnosticsChannel.ts index 323d4c46..507ad7f2 100644 --- a/src/diagnosticsChannel.ts +++ b/src/diagnosticsChannel.ts @@ -1,8 +1,10 @@ import diagnosticsChannel from 'node:diagnostics_channel'; +import { Socket } from 'node:net'; import { performance } from 'node:perf_hooks'; import { debuglog } from 'node:util'; -import { Socket } from 'node:net'; + import { DiagnosticsChannel } from 'undici'; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import symbols from './symbols.js'; @@ -54,7 +56,7 @@ function formatSocket(socket: SocketExtend) { // make sure error contains socket info const destroySocket = Socket.prototype.destroy; -Socket.prototype.destroy = function(err?: any) { +Socket.prototype.destroy = function (err?: any) { if (err) { Object.defineProperty(err, symbols.kErrorSocket, { // don't show on console log @@ -104,14 +106,24 @@ export function initDiagnosticsChannel() { if (!opaque || !opaque[symbols.kRequestId]) return; Reflect.set(request, symbols.kRequestInternalOpaque, opaque); - debug('[%s] Request#%d %s %s, path: %s, headers: %j', - name, opaque[symbols.kRequestId], request.method, request.origin, request.path, request.headers); + debug( + '[%s] Request#%d %s %s, path: %s, headers: %j', + name, + opaque[symbols.kRequestId], + request.method, + request.origin, + request.path, + request.headers, + ); if (!opaque[symbols.kEnableRequestTiming]) return; opaque[symbols.kRequestTiming].queuing = performanceTime(opaque[symbols.kRequestStartTime]); }); subscribe('undici:client:connectError', (message, name) => { - const { error, connectParams, socket } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any, socket: SocketExtend }; + const { error, connectParams, socket } = message as DiagnosticsChannel.ClientConnectErrorMessage & { + error: any; + socket: SocketExtend; + }; let sock = socket; if (!sock && error[symbols.kErrorSocket]) { sock = error[symbols.kErrorSocket]; @@ -129,11 +141,16 @@ export function initDiagnosticsChannel() { sock[symbols.kSocketConnectProtocol] = connectParams.protocol; sock[symbols.kSocketConnectHost] = connectParams.host; sock[symbols.kSocketConnectPort] = connectParams.port; - debug('[%s] Socket#%d connectError, connectParams: %j, error: %s, (sock: %j)', - name, sock[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(sock)); + debug( + '[%s] Socket#%d connectError, connectParams: %j, error: %s, (sock: %j)', + name, + sock[symbols.kSocketId], + connectParams, + (error as Error).message, + formatSocket(sock), + ); } else { - debug('[%s] connectError, connectParams: %j, error: %o', - name, connectParams, error); + debug('[%s] connectError, connectParams: %j, error: %o', name, connectParams, error); } }); @@ -166,17 +183,24 @@ export function initDiagnosticsChannel() { (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: %j)', - name, opaque[symbols.kRequestId], socket[symbols.kSocketId], socket[symbols.kHandledRequests], - formatSocket(socket)); + debug( + '[%s] Request#%d send headers on Socket#%d (handled %d requests, sock: %j)', + name, + opaque[symbols.kRequestId], + socket[symbols.kSocketId], + socket[symbols.kHandledRequests], + formatSocket(socket), + ); if (!opaque[symbols.kEnableRequestTiming]) return; opaque[symbols.kRequestTiming].requestHeadersSent = performanceTime(opaque[symbols.kRequestStartTime]); // 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] as number); + opaque[symbols.kRequestTiming].connected = performanceTime( + opaque[symbols.kRequestStartTime], + socket[symbols.kSocketStartTime] as number, + ); } }); @@ -206,12 +230,22 @@ export function initDiagnosticsChannel() { const socket = opaque[symbols.kRequestSocket]; if (socket) { socket[symbols.kHandledResponses]++; - debug('[%s] Request#%d get %s response headers on Socket#%d (handled %d responses, sock: %j)', - name, opaque[symbols.kRequestId], response.statusCode, socket[symbols.kSocketId], socket[symbols.kHandledResponses], - formatSocket(socket)); + debug( + '[%s] Request#%d get %s response headers on Socket#%d (handled %d responses, sock: %j)', + name, + opaque[symbols.kRequestId], + response.statusCode, + socket[symbols.kSocketId], + socket[symbols.kHandledResponses], + formatSocket(socket), + ); } else { - debug('[%s] Request#%d get %s response headers on Unknown Socket', - name, opaque[symbols.kRequestId], response.statusCode); + debug( + '[%s] Request#%d get %s response headers on Unknown Socket', + name, + opaque[symbols.kRequestId], + response.statusCode, + ); } if (!opaque[symbols.kEnableRequestTiming]) return; diff --git a/src/fetch.ts b/src/fetch.ts index 09acdecf..cb9c042f 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -1,5 +1,6 @@ import { AsyncLocalStorage } from 'node:async_hooks'; import { debuglog } from 'node:util'; + import { fetch as UndiciFetch, RequestInfo, @@ -17,6 +18,11 @@ import undiciSymbols from 'undici/lib/core/symbols.js'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { getResponseState } from 'undici/lib/web/fetch/response.js'; + +import { BaseAgent, BaseAgentOptions } from './BaseAgent.js'; +import { initDiagnosticsChannel } from './diagnosticsChannel.js'; +import { FetchOpaque } from './FetchOpaqueInterceptor.js'; +import { HttpAgent, HttpAgentOptions } from './HttpAgent.js'; import { channels, ClientOptions, @@ -25,22 +31,11 @@ import { ResponseDiagnosticsMessage, UndiciTimingInfo, } from './HttpClient.js'; -import { - HttpAgent, - HttpAgentOptions, -} from './HttpAgent.js'; -import { initDiagnosticsChannel } from './diagnosticsChannel.js'; -import { convertHeader, globalId, performanceTime, updateSocketInfo } from './utils.js'; -import symbols from './symbols.js'; -import { - FetchMeta, - HttpMethod, - RequestMeta, -} from './Request.js'; -import { FetchOpaque } from './FetchOpaqueInterceptor.js'; -import { RawResponseWithMeta, SocketInfo } from './Response.js'; import { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; -import { BaseAgent, BaseAgentOptions } from './BaseAgent.js'; +import { FetchMeta, HttpMethod, RequestMeta } from './Request.js'; +import { RawResponseWithMeta, SocketInfo } from './Response.js'; +import symbols from './symbols.js'; +import { convertHeader, globalId, performanceTime, updateSocketInfo } from './utils.js'; const debug = debuglog('urllib/fetch'); @@ -117,8 +112,8 @@ export class FetchFactory { if (!clients) { return poolStatsMap; } - for (const [ key, ref ] of clients) { - const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as (Pool & { dispatcher: Pool }); + for (const [key, ref] of clients) { + 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; @@ -225,9 +220,7 @@ export class FetchFactory { aborted: false, rt: 0, keepAliveSocket: true, - requestUrls: [ - request.url, - ], + requestUrls: [request.url], timing, socket: socketInfo, retries: 0, @@ -267,8 +260,14 @@ export class FetchFactory { urllibResponse.size = parseInt(urllibResponse.headers['content-length']); } urllibResponse.rt = performanceTime(requestStartTime); - debug('Request#%d got response, status: %s, headers: %j, timing: %j, socket: %j', - requestId, urllibResponse.status, urllibResponse.headers, timing, urllibResponse.socket); + debug( + 'Request#%d got response, status: %s, headers: %j, timing: %j, socket: %j', + requestId, + urllibResponse.status, + urllibResponse.headers, + timing, + urllibResponse.socket, + ); channels.fetchResponse.publish({ fetch: fetchMeta, timingInfo: state.timingInfo, diff --git a/src/formstream.d.ts b/src/formstream.d.ts index 4914b3e4..8f0c552b 100644 --- a/src/formstream.d.ts +++ b/src/formstream.d.ts @@ -1,3 +1,7 @@ declare module 'formstream' { - export default class FormStream {} + export default class FormStream { + headers(): Record; + file(name: string, path: string): void; + field(name: string, value: string): void; + } } diff --git a/src/index.ts b/src/index.ts index e4fffa1e..ad69b5ff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { LRU } from 'ylru'; -import { patchForNode16 } from './utils.js'; +import { patchForNode16 } from './utils.js'; patchForNode16(); @@ -88,31 +88,44 @@ export async function curl(url: RequestURL, options?: UrllibRequestOpti } export { - MockAgent, ProxyAgent, Agent, Dispatcher, - setGlobalDispatcher, getGlobalDispatcher, - Request, RequestInfo, RequestInit, - Response, BodyInit, ResponseInit, - Headers, FormData, + MockAgent, + ProxyAgent, + Agent, + Dispatcher, + setGlobalDispatcher, + getGlobalDispatcher, + Request, + RequestInfo, + RequestInit, + Response, + BodyInit, + ResponseInit, + Headers, + FormData, } from 'undici'; // HttpClient2 is keep compatible with urllib@2 HttpClient2 export { - HttpClient, HttpClient as HttpClient2, HEADER_USER_AGENT as USER_AGENT, - RequestDiagnosticsMessage, ResponseDiagnosticsMessage, ClientOptions, + HttpClient, + HttpClient as HttpClient2, + HEADER_USER_AGENT as USER_AGENT, + RequestDiagnosticsMessage, + ResponseDiagnosticsMessage, + ClientOptions, } from './HttpClient.js'; // RequestOptions2 is keep compatible with urllib@2 RequestOptions2 export { - RequestOptions, RequestOptions as RequestOptions2, RequestURL, HttpMethod, - FixJSONCtlCharsHandler, FixJSONCtlChars, + RequestOptions, + RequestOptions as RequestOptions2, + RequestURL, + HttpMethod, + FixJSONCtlCharsHandler, + FixJSONCtlChars, } from './Request.js'; export { CheckAddressFunction } from './HttpAgent.js'; -export { - SocketInfo, Timing, RawResponseWithMeta, HttpClientResponse, -} from './Response.js'; -export { - IncomingHttpHeaders, -} from './IncomingHttpHeaders.js'; +export { SocketInfo, Timing, RawResponseWithMeta, HttpClientResponse } from './Response.js'; +export { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; export * from './HttpClientError.js'; export { FetchFactory, fetch } from './fetch.js'; export { FormData as WebFormData } from './FormData.js'; diff --git a/src/utils.ts b/src/utils.ts index 53eced1a..603fbe53 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,13 +1,14 @@ +import { Blob, File } from 'node:buffer'; import { randomBytes, createHash } from 'node:crypto'; -import { Readable } from 'node:stream'; import { performance } from 'node:perf_hooks'; +import { Readable } from 'node:stream'; import { ReadableStream, TransformStream } from 'node:stream/web'; -import { Blob, File } from 'node:buffer'; import { toUSVString } from 'node:util'; + +import { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; import type { FixJSONCtlChars } from './Request.js'; import { SocketInfo } from './Response.js'; import symbols from './symbols.js'; -import { IncomingHttpHeaders } from './IncomingHttpHeaders.js'; const JSONCtlCharsMap: Record = { '"': '\\"', // \u0022 @@ -45,8 +46,12 @@ export function parseJSON(data: string, fixJSONCtlChars?: FixJSONCtlChars) { } if (data.length > 1024) { // show 0~512 ... -512~end data - err.message += ' (data json format: ' + - JSON.stringify(data.slice(0, 512)) + ' ...skip... ' + JSON.stringify(data.slice(data.length - 512)) + ')'; + err.message += + ' (data json format: ' + + JSON.stringify(data.slice(0, 512)) + + ' ...skip... ' + + JSON.stringify(data.slice(data.length - 512)) + + ')'; } else { err.message += ' (data json format: ' + JSON.stringify(data) + ')'; } @@ -150,12 +155,14 @@ export function isReadable(stream: any) { // patch from node // https://github.com/nodejs/node/blob/1287530385137dda1d44975063217ccf90759475/lib/internal/streams/utils.js#L119 // simple way https://github.com/sindresorhus/is-stream/blob/main/index.js - return stream !== null - && typeof stream === 'object' - && typeof stream.pipe === 'function' - && stream.readable !== false - && typeof stream._read === 'function' - && typeof stream._readableState === 'object'; + return ( + stream !== null && + typeof stream === 'object' && + typeof stream.pipe === 'function' && + stream.readable !== false && + typeof stream._read === 'function' && + typeof stream._readableState === 'object' + ); } export function updateSocketInfo(socketInfo: SocketInfo, internalOpaque: any, err?: any) { @@ -197,10 +204,10 @@ export function updateSocketInfo(socketInfo: SocketInfo, internalOpaque: any, er export function convertHeader(headers: Headers): IncomingHttpHeaders { const res: IncomingHttpHeaders = {}; - for (const [ key, value ] of headers.entries()) { + for (const [key, value] of headers.entries()) { if (res[key]) { if (!Array.isArray(res[key])) { - res[key] = [ res[key] ]; + res[key] = [res[key]]; } res[key].push(value); } else { @@ -245,13 +252,13 @@ export function patchForNode16() { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Object.defineProperty(String.prototype, 'toWellFormed', { - value: function() { + value: function () { return toUSVString(this); }, enumerable: false, configurable: true, writable: true, - }) + }); } // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -260,7 +267,7 @@ export function patchForNode16() { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Object.defineProperty(String.prototype, 'isWellFormed', { - value: function() { + value: function () { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return toUSVString(this) === this; @@ -270,7 +277,6 @@ export function patchForNode16() { writable: true, }); } - } // https://github.com/jimmywarting/node-domexception/blob/main/index.js diff --git a/test/HttpClient.connect.rejectUnauthorized.test.ts b/test/HttpClient.connect.rejectUnauthorized.test.ts index f28192ad..116abdcb 100644 --- a/test/HttpClient.connect.rejectUnauthorized.test.ts +++ b/test/HttpClient.connect.rejectUnauthorized.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -23,33 +25,39 @@ describe('HttpClient.connect.rejectUnauthorized.test.ts', () => { }, }); - await assert.rejects(async () => { - const response = await httpclient.request(_url); - console.log(response.status, response.headers, response.data); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'Error'); - assert.match(err.message, /signed certificate/); - assert.equal(err.code, 'DEPTH_ZERO_SELF_SIGNED_CERT'); - assert.equal(err.res.status, -1); - return true; - }); + await assert.rejects( + async () => { + const response = await httpclient.request(_url); + console.log(response.status, response.headers, response.data); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'Error'); + assert.match(err.message, /signed certificate/); + assert.equal(err.code, 'DEPTH_ZERO_SELF_SIGNED_CERT'); + assert.equal(err.res.status, -1); + return true; + }, + ); }); it('should throw error on rejectUnauthorized = undefined', async () => { const httpclient = new HttpClient(); - await assert.rejects(async () => { - const response = await httpclient.request(_url); - console.log(response.status, response.headers, response.data); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'Error'); - assert.match(err.message, /signed certificate/); - assert.equal(err.code, 'DEPTH_ZERO_SELF_SIGNED_CERT'); - assert.equal(err.res.status, -1); - return true; - }); + await assert.rejects( + async () => { + const response = await httpclient.request(_url); + console.log(response.status, response.headers, response.data); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'Error'); + assert.match(err.message, /signed certificate/); + assert.equal(err.code, 'DEPTH_ZERO_SELF_SIGNED_CERT'); + assert.equal(err.res.status, -1); + return true; + }, + ); }); it('should 200 on rejectUnauthorized = false', async () => { diff --git a/test/HttpClient.events.test.ts b/test/HttpClient.events.test.ts index fb434c7c..1adba3c4 100644 --- a/test/HttpClient.events.test.ts +++ b/test/HttpClient.events.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -20,7 +22,7 @@ describe('HttpClient.events.test.ts', () => { const httpclient = new HttpClient(); let requestCount = 0; let responseCount = 0; - httpclient.on('request', info => { + httpclient.on('request', (info) => { requestCount++; // console.log(info); assert.equal(info.url, _url); @@ -32,7 +34,7 @@ describe('HttpClient.events.test.ts', () => { assert.equal(info.ctx, undefined); } }); - httpclient.on('response', info => { + httpclient.on('response', (info) => { responseCount++; // console.log(info); assert.equal(info.req.args.opaque.requestId, `mock-request-id-${requestCount}`); @@ -94,7 +96,7 @@ describe('HttpClient.events.test.ts', () => { httpclient.on('request', () => { requestCount++; }); - httpclient.on('response', info => { + httpclient.on('response', (info) => { responseCount++; // console.log(info); assert.equal(info.req.args.opaque.requestId, `mock-request-id-${requestCount}`); @@ -109,21 +111,24 @@ describe('HttpClient.events.test.ts', () => { assert.equal(info.error.status, -1); }); - await assert.rejects(async () => { - await httpclient.request(`${_url}error`, { - dataType: 'json', - opaque: { - requestId: 'mock-request-id-1', - }, - ctx: { foo: 'bar' }, - socketErrorRetry: 0, - }); - }, (err: any) => { - assert.equal(err.name, 'SocketError'); - assert.equal(err.message, 'other side closed'); - assert.equal(err.status, -1); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request(`${_url}error`, { + dataType: 'json', + opaque: { + requestId: 'mock-request-id-1', + }, + ctx: { foo: 'bar' }, + socketErrorRetry: 0, + }); + }, + (err: any) => { + assert.equal(err.name, 'SocketError'); + assert.equal(err.message, 'other side closed'); + assert.equal(err.status, -1); + return true; + }, + ); assert.equal(requestCount, 1); assert.equal(responseCount, 1); }); diff --git a/test/HttpClient.test.ts b/test/HttpClient.test.ts index 83f14749..72911b75 100644 --- a/test/HttpClient.test.ts +++ b/test/HttpClient.test.ts @@ -2,10 +2,13 @@ import { strict as assert } from 'node:assert'; import dns from 'node:dns'; import { once } from 'node:events'; import { sensitiveHeaders, createSecureServer } from 'node:http2'; +import { AddressInfo } from 'node:net'; import { PerformanceObserver } from 'node:perf_hooks'; import { setTimeout as sleep } from 'node:timers/promises'; -import { describe, it, beforeAll, afterAll } from 'vitest'; + import selfsigned from 'selfsigned'; +import { describe, it, beforeAll, afterAll } from 'vitest'; + import { HttpClient, RawResponseWithMeta, getGlobalDispatcher } from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { nodeMajorVersion } from './utils.js'; @@ -15,13 +18,13 @@ const pems = selfsigned.generate([], { }); if (process.env.ENABLE_PERF) { - const obs = new PerformanceObserver(items => { - items.getEntries().forEach(item => { + const obs = new PerformanceObserver((items) => { + items.getEntries().forEach((item) => { console.log('%j', item); }); }); obs.observe({ - entryTypes: [ 'net', 'dns', 'function', 'gc', 'http', 'http2', 'node' ], + entryTypes: ['net', 'dns', 'function', 'gc', 'http', 'http2', 'node'], buffered: true, }); } @@ -155,7 +158,7 @@ describe('HttpClient.test.ts', () => { }, }); - const url = `https://localhost:${server.address()!.port}`; + const url = `https://localhost:${(server.address() as AddressInfo).port}`; let response = await httpClient.request(url, { dataType: 'text', headers: { @@ -218,7 +221,7 @@ describe('HttpClient.test.ts', () => { }, }); - const url = `https://localhost:${server.address()!.port}`; + const url = `https://localhost:${(server.address() as AddressInfo).port}`; let response = await httpClient.request(url, { dataType: 'text', headers: { @@ -252,7 +255,7 @@ describe('HttpClient.test.ts', () => { }); describe('clientOptions.lookup', () => { - it('should work with custom lookup on HTTP protol', async () => { + it('should work with custom lookup on HTTP protocol', async () => { let lookupCallCounter = 0; const httpclient = new HttpClient({ // mock lookup delay @@ -314,23 +317,29 @@ describe('HttpClient.test.ts', () => { }); assert.equal(Object.keys(httpclient.getDispatcherPoolStats()).length, 0); - await assert.rejects(async () => { - await httpclient.request(_url); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, -1); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, 'localhost'); - assert.equal(typeof err.ip, 'string'); - assert(err.family === 4 || err.family === 6); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request(_url); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, -1); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, 'localhost'); + assert.equal(typeof err.ip, 'string'); + assert(err.family === 4 || err.family === 6); + return true; + }, + ); const response = await httpclient.request(_url); assert.equal(response.status, 200); - assert.equal(Object.keys(httpclient.getDispatcherPoolStats()).length, 1, - `dispatcher pool stats: ${JSON.stringify(httpclient.getDispatcherPoolStats())}`); + 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 () => { @@ -350,18 +359,21 @@ describe('HttpClient.test.ts', () => { }, }); - await assert.rejects(async () => { - await httpclient.request(_url); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, -1); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, 'localhost'); - assert.equal(typeof err.ip, 'string'); - assert(err.family === 4 || err.family === 6); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request(_url); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, -1); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, 'localhost'); + assert.equal(typeof err.ip, 'string'); + assert(err.family === 4 || err.family === 6); + return true; + }, + ); assert.equal(lookupCallCounter, 1); const response = await httpclient.request(_url); @@ -378,18 +390,21 @@ describe('HttpClient.test.ts', () => { }, }); - await assert.rejects(async () => { - await httpclient.request(_url.replace('localhost', '127.0.0.1')); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, -1); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, '127.0.0.1'); - assert.equal(err.ip, '127.0.0.1'); - assert(err.family === 4); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request(_url.replace('localhost', '127.0.0.1')); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, -1); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, '127.0.0.1'); + assert.equal(err.ip, '127.0.0.1'); + assert(err.family === 4); + return true; + }, + ); const response = await httpclient.request(_url.replace('localhost', '127.0.0.1')); assert.equal(response.status, 200); @@ -397,48 +412,57 @@ describe('HttpClient.test.ts', () => { it('should throw error when request address is ip v6', async () => { const httpclient = new HttpClient({ - checkAddress(address, family) { + checkAddress(_address, family) { return family !== 6; }, }); - await assert.rejects(async () => { - await httpclient.request('http://[::1]/foo/bar'); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, '::1'); - assert.equal(err.ip, '::1'); - assert(err.family === 6); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request('http://[::1]/foo/bar'); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, '::1'); + assert.equal(err.ip, '::1'); + assert(err.family === 6); + return true; + }, + ); - await assert.rejects(async () => { - await httpclient.request('http://[2001:0DB8:02de::0e13]/foo/bar'); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, -1); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, '2001:db8:2de::e13'); - assert.equal(err.ip, '2001:db8:2de::e13'); - assert(err.family === 6); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request('http://[2001:0DB8:02de::0e13]/foo/bar'); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, -1); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, '2001:db8:2de::e13'); + assert.equal(err.ip, '2001:db8:2de::e13'); + assert(err.family === 6); + return true; + }, + ); - await assert.rejects(async () => { - await httpclient.request('http://[2001:0DB8:02de:0000:0000:0000:0000:0e13]/foo/bar'); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, -1); - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - assert.equal(err.hostname, '2001:db8:2de::e13'); - assert.equal(err.ip, '2001:db8:2de::e13'); - assert(err.family === 6); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request('http://[2001:0DB8:02de:0000:0000:0000:0000:0e13]/foo/bar'); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, -1); + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + assert.equal(err.hostname, '2001:db8:2de::e13'); + assert.equal(err.ip, '2001:db8:2de::e13'); + assert(err.family === 6); + return true; + }, + ); }); it('should throw error when follow redirect and redirect address illegal', async () => { @@ -449,18 +473,21 @@ describe('HttpClient.test.ts', () => { }, }); - await assert.rejects(async () => { - await httpclient.request(`${_url}redirect-to-localhost`); - }, (err: any) => { - if (err.name !== 'IllegalAddressError') { - console.error(err); - } - assert.equal(err.name, 'IllegalAddressError'); - assert.equal(err.message, 'illegal address'); - // assert.equal(err.ip, '127.0.0.1'); - // assert(err.family === 4); - return true; - }); + await assert.rejects( + async () => { + await httpclient.request(`${_url}redirect-to-localhost`); + }, + (err: any) => { + if (err.name !== 'IllegalAddressError') { + console.error(err); + } + assert.equal(err.name, 'IllegalAddressError'); + assert.equal(err.message, 'illegal address'); + // assert.equal(err.ip, '127.0.0.1'); + // assert(err.family === 4); + return true; + }, + ); }); it('should allow hostname check', async () => { @@ -474,10 +501,12 @@ describe('HttpClient.test.ts', () => { if (process.version.startsWith('v18.') || process.version.startsWith('v16.')) { return callback(null, '127.0.0.1', 4); } - return callback(null, [{ - address: '127.0.0.1', - family: 4, - }]); + return callback(null, [ + { + address: '127.0.0.1', + family: 4, + }, + ]); }, }); diff --git a/test/diagnostics_channel.test.ts b/test/diagnostics_channel.test.ts index f3f6017c..8d1377dc 100644 --- a/test/diagnostics_channel.test.ts +++ b/test/diagnostics_channel.test.ts @@ -1,15 +1,15 @@ import { strict as assert } from 'node:assert'; import diagnosticsChannel from 'node:diagnostics_channel'; -import { setTimeout as sleep } from 'node:timers/promises'; -import { createSecureServer } from 'node:http2'; import { once } from 'node:events'; -import { describe, it, beforeEach, afterEach } from 'vitest'; +import { createSecureServer } from 'node:http2'; +import { AddressInfo } from 'node:net'; +import { setTimeout as sleep } from 'node:timers/promises'; + import selfsigned from 'selfsigned'; +import { describe, it, beforeEach, afterEach } from 'vitest'; + import urllib, { HttpClient } from '../src/index.js'; -import type { - RequestDiagnosticsMessage, - ResponseDiagnosticsMessage, -} from '../src/index.js'; +import type { RequestDiagnosticsMessage, ResponseDiagnosticsMessage } from '../src/index.js'; import symbols from '../src/symbols.js'; import { startServer } from './fixtures/server.js'; import { nodeMajorVersion } from './utils.js'; @@ -218,7 +218,7 @@ describe('diagnostics_channel.test.ts', () => { }); let traceId = `mock-traceid-${Date.now()}`; - _url = `https://localhost:${server.address().port}`; + _url = `https://localhost:${(server.address() as AddressInfo).port}`; let response = await httpClient.request(`${_url}?head=true`, { method: 'HEAD', opaque: { @@ -389,26 +389,29 @@ describe('diagnostics_channel.test.ts', () => { let traceId = `mock-traceid-${Date.now()}`; // handle network error - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - method: 'GET', - dataType: 'json', - opaque: { - tracer: { traceId }, - }, - }); - }, err => { - assert(err); - assert(lastError); - assert.equal(err, lastError); - assert.equal(err.name, 'SocketError'); - assert.equal(err.message, 'other side closed'); - assert.equal((err as any).code, 'UND_ERR_SOCKET'); - assert.equal((err as any).res.socket, socket); - assert.equal((err as any).socket, socket); - assert((err as any)._rawSocket); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + method: 'GET', + dataType: 'json', + opaque: { + tracer: { traceId }, + }, + }); + }, + (err) => { + assert(err); + assert(lastError); + assert.equal(err, lastError); + assert.equal(err.name, 'SocketError'); + assert.equal(err.message, 'other side closed'); + assert.equal((err as any).code, 'UND_ERR_SOCKET'); + assert.equal((err as any).res.socket, socket); + assert.equal((err as any).socket, socket); + assert((err as any)._rawSocket); + return true; + }, + ); assert(socket); assert.equal(socket.handledRequests, 1); assert.equal(socket.handledResponses, 0); @@ -437,25 +440,28 @@ describe('diagnostics_channel.test.ts', () => { // handle response decode error, not network error await sleep(1); - await assert.rejects(async () => { - await urllib.request(`${_url}error-gzip`, { - method: 'GET', - dataType: 'json', - opaque: { - tracer: { traceId }, - }, - }); - }, err => { - assert(lastError); - assert.equal(err, lastError); - assert.equal(err.name, 'UnzipError'); - assert.equal(err.message, 'incorrect header check'); - assert.equal((err as any).code, 'Z_DATA_ERROR'); - assert.equal((err as any).res.socket, socket); - assert.equal((err as any).socket, socket); - assert.equal((err as any)._rawSocket, undefined); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error-gzip`, { + method: 'GET', + dataType: 'json', + opaque: { + tracer: { traceId }, + }, + }); + }, + (err) => { + assert(lastError); + assert.equal(err, lastError); + assert.equal(err.name, 'UnzipError'); + assert.equal(err.message, 'incorrect header check'); + assert.equal((err as any).code, 'Z_DATA_ERROR'); + assert.equal((err as any).res.socket, socket); + assert.equal((err as any).socket, socket); + assert.equal((err as any)._rawSocket, undefined); + return true; + }, + ); assert.equal(socket.handledRequests, 2); assert.equal(socket.handledResponses, 2); diff --git a/test/esm/index.js b/test/esm/index.js index 095c7100..680770a8 100644 --- a/test/esm/index.js +++ b/test/esm/index.js @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; + import * as urllibStar from 'urllib'; import urllib from 'urllib'; import { request, HttpClient, USER_AGENT, getDefaultHttpClient } from 'urllib'; diff --git a/test/fetch-head-request-should-keepalive.test.ts b/test/fetch-head-request-should-keepalive.test.ts index 824b1372..1e477987 100644 --- a/test/fetch-head-request-should-keepalive.test.ts +++ b/test/fetch-head-request-should-keepalive.test.ts @@ -1,6 +1,8 @@ import { strict as assert } from 'node:assert'; import { scheduler } from 'node:timers/promises'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import { fetch } from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/fetch.test.ts b/test/fetch.test.ts index de2a3f54..b1d53d96 100644 --- a/test/fetch.test.ts +++ b/test/fetch.test.ts @@ -1,13 +1,13 @@ import assert from 'node:assert/strict'; import diagnosticsChannel from 'node:diagnostics_channel'; import { setTimeout as sleep } from 'node:timers/promises'; + +import { Request } from 'undici'; import { describe, it, beforeAll, afterAll } from 'vitest'; -import { startServer } from './fixtures/server.js'; -import { - fetch, FetchDiagnosticsMessage, FetchFactory, FetchResponseDiagnosticsMessage, -} from '../src/fetch.js'; + +import { fetch, FetchDiagnosticsMessage, FetchFactory, FetchResponseDiagnosticsMessage } from '../src/fetch.js'; import { RequestDiagnosticsMessage, ResponseDiagnosticsMessage } from '../src/HttpClient.js'; -import { Request } from 'undici'; +import { startServer } from './fixtures/server.js'; describe('fetch.test.ts', () => { let close: any; @@ -27,16 +27,16 @@ describe('fetch.test.ts', () => { let responseDiagnosticsMessage: ResponseDiagnosticsMessage; let fetchDiagnosticsMessage: FetchDiagnosticsMessage; let fetchResponseDiagnosticsMessage: FetchResponseDiagnosticsMessage; - diagnosticsChannel.subscribe('urllib:request', msg => { + diagnosticsChannel.subscribe('urllib:request', (msg) => { requestDiagnosticsMessage = msg as RequestDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:response', msg => { + diagnosticsChannel.subscribe('urllib:response', (msg) => { responseDiagnosticsMessage = msg as ResponseDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:request', msg => { + diagnosticsChannel.subscribe('urllib:fetch:request', (msg) => { fetchDiagnosticsMessage = msg as FetchDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:response', msg => { + diagnosticsChannel.subscribe('urllib:fetch:response', (msg) => { fetchResponseDiagnosticsMessage = msg as FetchResponseDiagnosticsMessage; }); FetchFactory.setClientOptions({}); @@ -48,7 +48,7 @@ describe('fetch.test.ts', () => { assert(responseDiagnosticsMessage!.request); assert(responseDiagnosticsMessage!.response); assert(responseDiagnosticsMessage!.response.socket.localAddress); - assert([ '127.0.0.1', '::1' ].includes(responseDiagnosticsMessage!.response.socket.localAddress)); + assert(['127.0.0.1', '::1'].includes(responseDiagnosticsMessage!.response.socket.localAddress)); assert(fetchDiagnosticsMessage!.fetch); assert(fetchResponseDiagnosticsMessage!.fetch); @@ -71,35 +71,38 @@ describe('fetch.test.ts', () => { let responseDiagnosticsMessage: ResponseDiagnosticsMessage; let fetchDiagnosticsMessage: FetchDiagnosticsMessage; let fetchResponseDiagnosticsMessage: FetchResponseDiagnosticsMessage; - diagnosticsChannel.subscribe('urllib:request', msg => { + diagnosticsChannel.subscribe('urllib:request', (msg) => { requestDiagnosticsMessage = msg as RequestDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:response', msg => { + diagnosticsChannel.subscribe('urllib:response', (msg) => { responseDiagnosticsMessage = msg as ResponseDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:request', msg => { + diagnosticsChannel.subscribe('urllib:fetch:request', (msg) => { fetchDiagnosticsMessage = msg as FetchDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:response', msg => { + diagnosticsChannel.subscribe('urllib:fetch:response', (msg) => { fetchResponseDiagnosticsMessage = msg as FetchResponseDiagnosticsMessage; }); FetchFactory.setClientOptions({}); - await assert.rejects(async () => { - await fetch(`${_url}html?timeout=9999`, { - signal: AbortSignal.timeout(100), - }); - }, (err: any) => { - assert.equal(err.name, 'TimeoutError'); - assert.equal(err.message, 'The operation was aborted due to timeout'); - return true; - }); + await assert.rejects( + async () => { + await fetch(`${_url}html?timeout=9999`, { + signal: AbortSignal.timeout(100), + }); + }, + (err: any) => { + assert.equal(err.name, 'TimeoutError'); + assert.equal(err.message, 'The operation was aborted due to timeout'); + return true; + }, + ); assert(requestDiagnosticsMessage!.request); assert(responseDiagnosticsMessage!.request); assert(responseDiagnosticsMessage!.response); assert(responseDiagnosticsMessage!.response.socket.localAddress); - assert([ '127.0.0.1', '::1' ].includes(responseDiagnosticsMessage!.response.socket.localAddress)); + assert(['127.0.0.1', '::1'].includes(responseDiagnosticsMessage!.response.socket.localAddress)); assert(fetchDiagnosticsMessage!.fetch); assert(fetchResponseDiagnosticsMessage!.fetch); @@ -124,16 +127,16 @@ describe('fetch.test.ts', () => { let responseDiagnosticsMessage: ResponseDiagnosticsMessage; let fetchDiagnosticsMessage: FetchDiagnosticsMessage; let fetchResponseDiagnosticsMessage: FetchResponseDiagnosticsMessage; - diagnosticsChannel.subscribe('urllib:request', msg => { + diagnosticsChannel.subscribe('urllib:request', (msg) => { requestDiagnosticsMessage = msg as RequestDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:response', msg => { + diagnosticsChannel.subscribe('urllib:response', (msg) => { responseDiagnosticsMessage = msg as ResponseDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:request', msg => { + diagnosticsChannel.subscribe('urllib:fetch:request', (msg) => { fetchDiagnosticsMessage = msg as FetchDiagnosticsMessage; }); - diagnosticsChannel.subscribe('urllib:fetch:response', msg => { + diagnosticsChannel.subscribe('urllib:fetch:response', (msg) => { fetchResponseDiagnosticsMessage = msg as FetchResponseDiagnosticsMessage; }); const factory = new FetchFactory(); @@ -145,7 +148,7 @@ describe('fetch.test.ts', () => { assert(responseDiagnosticsMessage!.request); assert(responseDiagnosticsMessage!.response); assert(responseDiagnosticsMessage!.response.socket.localAddress); - assert([ '127.0.0.1', '::1' ].includes(responseDiagnosticsMessage!.response.socket.localAddress)); + assert(['127.0.0.1', '::1'].includes(responseDiagnosticsMessage!.response.socket.localAddress)); assert(fetchDiagnosticsMessage!.fetch); assert(fetchResponseDiagnosticsMessage!.fetch); diff --git a/test/fixtures/server.ts b/test/fixtures/server.ts index 9faf032d..962c7e80 100644 --- a/test/fixtures/server.ts +++ b/test/fixtures/server.ts @@ -1,13 +1,15 @@ -import { Socket } from 'node:net'; +import { createReadStream } from 'node:fs'; 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 { Socket } from 'node:net'; import { setTimeout as sleep } from 'node:timers/promises'; +import { createBrotliCompress, createGzip, gzipSync, brotliCompressSync } from 'node:zlib'; + import busboy from 'busboy'; import iconv from 'iconv-lite'; -import selfsigned from 'selfsigned'; import qs from 'qs'; +import selfsigned from 'selfsigned'; + import { nodeMajorVersion, readableToBytes } from '../utils.js'; const requestsPerSocket = Symbol('requestsPerSocket'); @@ -15,17 +17,18 @@ const requestsPerSocket = Symbol('requestsPerSocket'); export async function startServer(options?: { keepAliveTimeout?: number; https?: boolean; -}): Promise<{ server: Server, url: string, urlWithDns: string, closeServer: any }> { +}): Promise<{ server: Server; url: string; urlWithDns: string; closeServer: any }> { let server: Server; const requestHandler = async (req: IncomingMessage, res: ServerResponse) => { const startTime = Date.now(); - req.socket[requestsPerSocket] = (req.socket[requestsPerSocket] || 0) + 1; + const socket = req.socket as any; + socket[requestsPerSocket] = (socket[requestsPerSocket] || 0) + 1; if (server.keepAliveTimeout) { res.setHeader('Keep-Alive', 'timeout=' + server.keepAliveTimeout / 1000); } const urlObject = new URL(req.url!, `http://${req.headers.host}`); const pathname = urlObject.pathname; - res.setHeader('x-requests-persocket', req.socket[requestsPerSocket]); + res.setHeader('x-requests-persocket', socket[requestsPerSocket]); res.setHeader('x-requests-socket-port', req.socket.remotePort!); res.setHeader('X-Foo', 'bar'); res.setHeader('x-href', urlObject.href); @@ -67,58 +70,86 @@ export async function startServer(options?: { const authorization = req.headers.authorization?.split(' ')[1] ?? ''; const data = Buffer.from(authorization, 'base64'); const auth = data.toString().split(':'); - return res.end(JSON.stringify({ - user: auth[0], - password: auth[1], - })); + return res.end( + JSON.stringify({ + user: auth[0], + password: auth[1], + }), + ); } if (pathname === '/hello/json') { - return res.end(JSON.stringify({ - hello: 'urllib', - })); + return res.end( + JSON.stringify({ + hello: 'urllib', + }), + ); } if (pathname === '/digestAuth') { const authorization = req.headers.authorization; if (!authorization) { - res.setHeader('www-authenticate', 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'); + res.setHeader( + 'www-authenticate', + 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', + ); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization required', - })); + return res.end( + JSON.stringify({ + error: 'authorization required', + }), + ); } if (!authorization.includes('Digest username="user"')) { - res.setHeader('www-authenticate', 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'); + res.setHeader( + 'www-authenticate', + 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', + ); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization invaild', - })); + return res.end( + JSON.stringify({ + error: 'authorization invaild', + }), + ); } - return res.end(JSON.stringify({ - authorization, - })); + return res.end( + JSON.stringify({ + authorization, + }), + ); } if (pathname === '/digestAuth2') { const authorization = req.headers.authorization; if (!authorization) { - res.setHeader('x-www-authenticate', 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'); + res.setHeader( + 'x-www-authenticate', + 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', + ); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization required', - })); + return res.end( + JSON.stringify({ + error: 'authorization required', + }), + ); } if (!authorization.includes('Digest username="user"')) { - res.setHeader('x-www-authenticate', 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'); + res.setHeader( + 'x-www-authenticate', + 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', + ); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization invaild', - })); + return res.end( + JSON.stringify({ + error: 'authorization invaild', + }), + ); } - return res.end(JSON.stringify({ - authorization, - })); + return res.end( + JSON.stringify({ + authorization, + }), + ); } if (pathname === '/digestAuth/multi') { @@ -129,20 +160,29 @@ export async function startServer(options?: { 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', ]); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization required', - })); + return res.end( + JSON.stringify({ + error: 'authorization required', + }), + ); } if (!authorization.includes('Digest username="user"')) { - res.setHeader('www-authenticate', 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'); + res.setHeader( + 'www-authenticate', + 'Digest realm="testrealm@urllib.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"', + ); res.statusCode = 401; - return res.end(JSON.stringify({ - error: 'authorization invaild', - })); + return res.end( + JSON.stringify({ + error: 'authorization invaild', + }), + ); } - return res.end(JSON.stringify({ - authorization, - })); + return res.end( + JSON.stringify({ + authorization, + }), + ); } if (pathname === '/wrongjson') { @@ -162,7 +202,7 @@ export async function startServer(options?: { } if (pathname === '/set-two-cookie') { - res.setHeader('Set-Cookie', [ 'foo=bar; path=/', 'hello=world; path=/' ]); + res.setHeader('Set-Cookie', ['foo=bar; path=/', 'hello=world; path=/']); res.setHeader('content-type', 'text/html'); return res.end('

hello set-cookie

'); } @@ -282,25 +322,27 @@ export async function startServer(options?: { url: req.url, href: urlObject.href, headers: req.headers, - files: {}, - form: {}, + files: {} as Record, + form: {} as Record, }; bb.on('file', (name, file, info) => { const { filename, encoding, mimeType } = info; // console.log(`File [${name}]: info %j`, info); let size = 0; - file.on('data', data => { - // console.log(`File [${name}] got ${data.length} bytes`); - size += data.length; - }).on('close', () => { - // console.log(`File [${name}] done`); - result.files[name] = { - filename, - encoding, - mimeType, - size, - }; - }); + file + .on('data', (data) => { + // console.log(`File [${name}] got ${data.length} bytes`); + size += data.length; + }) + .on('close', () => { + // console.log(`File [${name}] done`); + result.files[name] = { + filename, + encoding, + mimeType, + size, + }; + }); }); bb.on('field', (name, val) => { // console.log(`Field [${name}]: value length: %d, info: %j`, val.length, info); @@ -338,7 +380,7 @@ export async function startServer(options?: { }; } else { const searchParams = new URLSearchParams(raw); - for (const [ field, value ] of searchParams.entries()) { + for (const [field, value] of searchParams.entries()) { requestBody[field] = value; } } @@ -373,10 +415,13 @@ export async function startServer(options?: { const pem = selfsigned.generate([], { keySize: nodeMajorVersion() >= 22 ? 2048 : 1024, }); - server = createHttpsServer({ - key: pem.private, - cert: pem.cert, - }, requestHandler); + server = createHttpsServer( + { + key: pem.private, + cert: pem.cert, + }, + requestHandler, + ); } else { server = createServer(requestHandler); } @@ -389,13 +434,13 @@ export async function startServer(options?: { const hasCloseAllConnections = !!(server as any).closeAllConnections; const connections: Socket[] = []; if (!hasCloseAllConnections) { - server.on('connection', connection => { + server.on('connection', (connection) => { connections.push(connection); }); } const protocol = options?.https ? 'https' : 'http'; - return new Promise(resolve => { + return new Promise((resolve) => { server.listen(0, () => { const address: any = server.address(); resolve({ @@ -411,7 +456,7 @@ export async function startServer(options?: { connection.destroy(); } } - return new Promise(resolve => { + return new Promise((resolve) => { server.close(resolve); }); }, diff --git a/test/fixtures/socket_server.ts b/test/fixtures/socket_server.ts index 8e1c2bd4..66b49396 100644 --- a/test/fixtures/socket_server.ts +++ b/test/fixtures/socket_server.ts @@ -4,27 +4,27 @@ const socketPathPrefix = '/tmp/urllib.unix.sock'; let index = 0; export async function startServer(): Promise<{ - server: Server, - url: string, - socketPath: string, - closeServer: any, + server: Server; + url: string; + socketPath: string; + closeServer: any; }> { const socketPath = `${socketPathPrefix}_${index++}`; const unixSocketServer = createServer(); - unixSocketServer.on('request', (req, res) => { + unixSocketServer.on('request', (_req, res) => { res.setHeader('Content-Type', 'application/json'); res.write(JSON.stringify({ a: 1 })); res.end(); }); - return new Promise(resolve => { + return new Promise((resolve) => { unixSocketServer.listen(socketPath, () => { resolve({ url: 'http://localhost/', server: unixSocketServer, socketPath, - closeServer: () => new Promise(resolve => unixSocketServer.close(resolve)), + closeServer: () => new Promise((resolve) => unixSocketServer.close(resolve)), }); }); }); diff --git a/test/fixtures/ts-cjs-es2021/tsconfig.json b/test/fixtures/ts-cjs-es2021/tsconfig.json index 2f2baadd..715e34a5 100644 --- a/test/fixtures/ts-cjs-es2021/tsconfig.json +++ b/test/fixtures/ts-cjs-es2021/tsconfig.json @@ -6,7 +6,7 @@ "moduleResolution": "Node", "baseUrl": "./", "paths": { - "urllib": ["../../.."] - } - } + "urllib": ["../../.."], + }, + }, } diff --git a/test/fixtures/ts-esm/tsconfig.json b/test/fixtures/ts-esm/tsconfig.json index c7a99cb1..72cbcea6 100644 --- a/test/fixtures/ts-esm/tsconfig.json +++ b/test/fixtures/ts-esm/tsconfig.json @@ -6,7 +6,7 @@ "moduleResolution": "NodeNext", "baseUrl": "./", "paths": { - "urllib": ["../../.."] - } - } + "urllib": ["../../.."], + }, + }, } diff --git a/test/fixtures/ts/tsconfig.json b/test/fixtures/ts/tsconfig.json index 5d8c56c9..d13f6161 100644 --- a/test/fixtures/ts/tsconfig.json +++ b/test/fixtures/ts/tsconfig.json @@ -6,7 +6,7 @@ "moduleResolution": "Node", "baseUrl": "./", "paths": { - "urllib": ["../../.."] - } - } + "urllib": ["../../.."], + }, + }, } diff --git a/test/formData-with-BufferStream.test.ts b/test/formData-with-BufferStream.test.ts index b2fb94e0..b52819e9 100644 --- a/test/formData-with-BufferStream.test.ts +++ b/test/formData-with-BufferStream.test.ts @@ -1,10 +1,12 @@ import { strict as assert } from 'node:assert'; import { createReadStream } from 'node:fs'; import { basename } from 'node:path'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import { HttpClient, WebFormData } from '../src/index.js'; -import { startServer } from './fixtures/server.js'; import { BufferStream } from './fixtures/BufferStream.js'; +import { startServer } from './fixtures/server.js'; describe('formData-with-BufferStream.test.ts', () => { let close: any; diff --git a/test/head-request-should-keepalive.test.ts b/test/head-request-should-keepalive.test.ts index 8472324f..77c82475 100644 --- a/test/head-request-should-keepalive.test.ts +++ b/test/head-request-should-keepalive.test.ts @@ -1,6 +1,8 @@ import { strict as assert } from 'node:assert'; import { scheduler } from 'node:timers/promises'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/index.test.ts b/test/index.test.ts index b0ef86bc..c347811c 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,10 +1,15 @@ import { strict as assert } from 'node:assert'; -import { parse as urlparse } from 'node:url'; import { readFileSync } from 'node:fs'; +import { parse as urlparse } from 'node:url'; + import { describe, it, beforeAll, afterAll, afterEach, beforeEach } from 'vitest'; + import urllib, { - HttpClient, getDefaultHttpClient, - MockAgent, setGlobalDispatcher, getGlobalDispatcher, + HttpClient, + getDefaultHttpClient, + MockAgent, + setGlobalDispatcher, + getGlobalDispatcher, } from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { readableToBytes } from './utils.js'; @@ -63,10 +68,7 @@ describe('index.test.ts', () => { assert.equal(response.status, 200); assert(Array.isArray(response.headers['set-cookie'])); assert.equal(typeof response.headers['set-cookie'], 'object'); - assert.deepEqual(response.headers['set-cookie'], [ - 'foo=bar; path=/', - 'hello=world; path=/', - ]); + assert.deepEqual(response.headers['set-cookie'], ['foo=bar; path=/', 'hello=world; path=/']); assert.equal(response.headers['Set-Cookie'], undefined); }); @@ -124,36 +126,42 @@ describe('index.test.ts', () => { // unstable it.skip('should request not exists network error', async () => { - await assert.rejects(async () => { - await urllib.request('http://www.npmjs-not-exists.foo', { - timeout: 500, - }); - }, (err: any) => { - console.error(err); - assert.equal(err.res.status, -1); - // assert.equal(err.name, 'Error'); - // assert.equal(err.message, 'getaddrinfo ENOTFOUND www.npmjs-not-exists.foo'); - // err.status and err.headers - assert.equal(err.status, -1); - assert(err.headers); - return true; - }); + await assert.rejects( + async () => { + await urllib.request('http://www.npmjs-not-exists.foo', { + timeout: 500, + }); + }, + (err: any) => { + console.error(err); + assert.equal(err.res.status, -1); + // assert.equal(err.name, 'Error'); + // assert.equal(err.message, 'getaddrinfo ENOTFOUND www.npmjs-not-exists.foo'); + // err.status and err.headers + assert.equal(err.status, -1); + assert(err.headers); + return true; + }, + ); }); it('should handle server socket end("balabal") will error', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}socket.end.error`); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, 200); - assert.equal(err.name, 'HTTPParserError'); - assert.equal(err.message, 'Response does not match the HTTP/1.1 protocol (Invalid character in chunk size)'); - if (err.code) { - assert.equal(err.code, 'HPE_INVALID_CHUNK_SIZE'); - } - assert.equal(err.data, 'labala'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}socket.end.error`); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, 200); + assert.equal(err.name, 'HTTPParserError'); + assert.equal(err.message, 'Response does not match the HTTP/1.1 protocol (Invalid character in chunk size)'); + if (err.code) { + assert.equal(err.code, 'HPE_INVALID_CHUNK_SIZE'); + } + assert.equal(err.data, 'labala'); + return true; + }, + ); }); it('should request(host-only) work', async () => { @@ -196,39 +204,47 @@ describe('index.test.ts', () => { assert.equal(typeof getGlobalDispatcher, 'function'); assert(getGlobalDispatcher()); const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); - mockPool.intercept({ - path: '/foo', - method: 'POST', - }).reply(400, { - message: 'mock 400 bad request', - }); + mockPool + .intercept({ + path: '/foo', + method: 'POST', + }) + .reply(400, { + message: 'mock 400 bad request', + }); - mockPool.intercept({ - path: '/bar', - method: 'GET', - query: { - q: '1', - }, - }).reply(200, { - message: 'mock bar with q=1', - }); + mockPool + .intercept({ + path: '/bar', + method: 'GET', + query: { + q: '1', + }, + }) + .reply(200, { + message: 'mock bar with q=1', + }); - mockPool.intercept({ - path: '/bar', - method: 'GET', - query: { - q: '2', - }, - }).reply(200, { - message: 'mock bar with q=2', - }); + mockPool + .intercept({ + path: '/bar', + method: 'GET', + query: { + q: '2', + }, + }) + .reply(200, { + message: 'mock bar with q=2', + }); - mockPool.intercept({ - path: /\.tgz$/, - method: 'GET', - }).reply(400, { - message: 'mock 400 bad request on tgz', - }); + mockPool + .intercept({ + path: /\.tgz$/, + method: 'GET', + }) + .reply(400, { + message: 'mock 400 bad request on tgz', + }); let response = await urllib.request(`${_url}foo`, { method: 'POST', @@ -271,10 +287,13 @@ describe('index.test.ts', () => { it('should mocking intercept work with readable', async () => { const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); // mock response stream - mockPool.intercept({ - path: '/foo.js', - method: 'GET', - }).reply(200, readFileSync(__filename)).times(2); + mockPool + .intercept({ + path: '/foo.js', + method: 'GET', + }) + .reply(200, readFileSync(__filename)) + .times(2); let response = await urllib.request(`${_url}foo.js`, { method: 'GET', dataType: 'stream', @@ -306,39 +325,47 @@ describe('index.test.ts', () => { assert(oldAgent); httpClient.setDispatcher(mockAgent); const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); - mockPool.intercept({ - path: '/foo', - method: 'POST', - }).reply(400, { - message: 'mock 400 bad request', - }); + mockPool + .intercept({ + path: '/foo', + method: 'POST', + }) + .reply(400, { + message: 'mock 400 bad request', + }); - mockPool.intercept({ - path: '/bar', - method: 'GET', - query: { - q: '1', - }, - }).reply(200, { - message: 'mock bar with q=1', - }); + mockPool + .intercept({ + path: '/bar', + method: 'GET', + query: { + q: '1', + }, + }) + .reply(200, { + message: 'mock bar with q=1', + }); - mockPool.intercept({ - path: '/bar', - method: 'GET', - query: { - q: '2', - }, - }).reply(200, { - message: 'mock bar with q=2', - }); + mockPool + .intercept({ + path: '/bar', + method: 'GET', + query: { + q: '2', + }, + }) + .reply(200, { + message: 'mock bar with q=2', + }); - mockPool.intercept({ - path: /\.tgz$/, - method: 'GET', - }).reply(400, { - message: 'mock 400 bad request on tgz', - }); + mockPool + .intercept({ + path: /\.tgz$/, + method: 'GET', + }) + .reply(400, { + message: 'mock 400 bad request on tgz', + }); let response = await httpClient.request(`${_url}foo`, { method: 'POST', @@ -381,12 +408,14 @@ describe('index.test.ts', () => { // should not work httpClient.setDispatcher(oldAgent); - mockPool.intercept({ - path: '/foo', - method: 'POST', - }).reply(400, { - message: 'mock 400 bad request', - }); + mockPool + .intercept({ + path: '/foo', + method: 'POST', + }) + .reply(400, { + message: 'mock 400 bad request', + }); response = await httpClient.request(`${_url}foo`, { method: 'POST', dataType: 'json', diff --git a/test/keep-alive-header.test.ts b/test/keep-alive-header.test.ts index aef85147..bb0b9e34 100644 --- a/test/keep-alive-header.test.ts +++ b/test/keep-alive-header.test.ts @@ -1,6 +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 { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { isWindows } from './utils.js'; @@ -88,7 +90,10 @@ 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, response.headers['x-requests-persocket'] as string); + 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); @@ -132,7 +137,10 @@ 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, response.headers['x-requests-persocket'] as string); + 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); @@ -165,8 +173,7 @@ describe('keep-alive-header.test.ts', () => { } } if (otherSideClosed || readECONNRESET) { - console.log('otherSideClosed: %d, readECONNRESET: %d', - otherSideClosed, readECONNRESET); + console.log('otherSideClosed: %d, readECONNRESET: %d', otherSideClosed, readECONNRESET); } assert.equal(otherSideClosed, 0); assert.equal(readECONNRESET, 0); diff --git a/test/mts/src/index.mts b/test/mts/src/index.mts index 26513fe8..47613c86 100644 --- a/test/mts/src/index.mts +++ b/test/mts/src/index.mts @@ -1,7 +1,8 @@ -import { request, IncomingHttpHeaders } from "urllib"; -const responseObj = await request("test"); +// @ts-expect-error ignore type error +import { request, IncomingHttpHeaders } from 'urllib'; +const responseObj = await request('test'); -type IsAny = 0 extends (1 & T) ? Y : N; +type IsAny = 0 extends 1 & T ? Y : N; (x: IsAny) => x; // never (x: IsAny) => x; // true diff --git a/test/mts/tsconfig.json b/test/mts/tsconfig.json index 4f6320fa..30be5311 100644 --- a/test/mts/tsconfig.json +++ b/test/mts/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": ["@tsconfig/strictest/tsconfig", "@tsconfig/node18/tsconfig"], - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "outDir": "dist", - "skipLibCheck": false - }, - "include": ["src/**/*"] + "extends": ["@tsconfig/strictest/tsconfig", "@tsconfig/node18/tsconfig"], + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "outDir": "dist", + "skipLibCheck": false, + }, + "include": ["src/**/*"], } diff --git a/test/non-ascii-request-header.test.ts b/test/non-ascii-request-header.test.ts index 1517dd25..9307e5ed 100644 --- a/test/non-ascii-request-header.test.ts +++ b/test/non-ascii-request-header.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -18,20 +20,23 @@ describe('non-ascii-request-header.test.ts', () => { }); it('should throw error when request headers contain non ascii', async () => { - await assert.rejects(async () => { - const response = await urllib.request(_url, { - headers: { 'x-test': '中文' }, - dataType: 'json', - }); - console.log(response); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'InvalidArgumentError'); - assert.equal(err.message, 'invalid x-test header'); - assert.equal(err.code, 'UND_ERR_INVALID_ARG'); - assert(err.res); - assert.equal(err.res.status, -1); - return true; - }); + await assert.rejects( + async () => { + const response = await urllib.request(_url, { + headers: { 'x-test': '中文' }, + dataType: 'json', + }); + console.log(response); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'InvalidArgumentError'); + assert.equal(err.message, 'invalid x-test header'); + assert.equal(err.code, 'UND_ERR_INVALID_ARG'); + assert(err.res); + assert.equal(err.res.status, -1); + return true; + }, + ); }); }); diff --git a/test/options.auth.test.ts b/test/options.auth.test.ts index 93b2bf65..a2080bac 100644 --- a/test/options.auth.test.ts +++ b/test/options.auth.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.compressed.test.ts b/test/options.compressed.test.ts index 70e5debb..7b3e81e4 100644 --- a/test/options.compressed.test.ts +++ b/test/options.compressed.test.ts @@ -1,6 +1,8 @@ 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/index.js'; import { startServer } from './fixtures/server.js'; import { readableToString, createTempfile } from './utils.js'; @@ -36,8 +38,10 @@ describe('options.compressed.test.ts', () => { assert.equal(response.headers['content-encoding'], 'br'); // console.log(response.headers); const requestHeaders = JSON.parse(response.headers['x-request-headers'] as string); - assert(!requestHeaders['accept-encoding'], - `should not contains accept-encoding header: ${requestHeaders['accept-encoding']}`); + assert( + !requestHeaders['accept-encoding'], + `should not contains accept-encoding header: ${requestHeaders['accept-encoding']}`, + ); assert.match(response.data, /export async function startServer/); }); @@ -167,40 +171,46 @@ describe('options.compressed.test.ts', () => { }); it('should throw error when gzip content invalid', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}error-gzip`, { - dataType: 'text', - compressed: true, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'UnzipError'); - assert.equal(err.message, 'incorrect header check'); - assert.equal(err.code, 'Z_DATA_ERROR'); - assert.equal(err.status, 200); - assert.equal(err.headers['content-encoding'], 'gzip'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error-gzip`, { + dataType: 'text', + compressed: true, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'UnzipError'); + assert.equal(err.message, 'incorrect header check'); + assert.equal(err.code, 'Z_DATA_ERROR'); + assert.equal(err.status, 200); + assert.equal(err.headers['content-encoding'], 'gzip'); + return true; + }, + ); }); it('should throw error when brotli content invaild', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}error-brotli`, { - dataType: 'text', - compressed: true, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'UnzipError'); - assert.equal(err.message, 'Decompression failed'); - if (process.version !== 'v18.19.0' && !process.version.startsWith('v16.')) { - assert.equal(err.code, 'ERR__ERROR_FORMAT_PADDING_1'); - } else { - assert.equal(err.code, 'ERR_PADDING_1'); - } - assert.equal(err.status, 200); - assert.equal(err.headers['content-encoding'], 'br'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error-brotli`, { + dataType: 'text', + compressed: true, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'UnzipError'); + assert.equal(err.message, 'Decompression failed'); + if (process.version !== 'v18.19.0' && !process.version.startsWith('v16.')) { + assert.equal(err.code, 'ERR__ERROR_FORMAT_PADDING_1'); + } else { + assert.equal(err.code, 'ERR_PADDING_1'); + } + assert.equal(err.status, 200); + assert.equal(err.headers['content-encoding'], 'br'); + return true; + }, + ); }); }); diff --git a/test/options.content.test.ts b/test/options.content.test.ts index 0bcf9a8d..84a46db7 100644 --- a/test/options.content.test.ts +++ b/test/options.content.test.ts @@ -1,7 +1,9 @@ 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 { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.data.test.ts b/test/options.data.test.ts index 55dd5508..475267cf 100644 --- a/test/options.data.test.ts +++ b/test/options.data.test.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'node:assert'; 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/index.js'; import { startServer } from './fixtures/server.js'; @@ -27,9 +29,11 @@ describe('options.data.test.ts', () => { b: undefined, c: '2222', d: 1111, - e() { return ''; }, + e() { + return ''; + }, f: true, - g: [ 'a', 'b' ], + g: ['a', 'b'], }, dataType: 'json', }); @@ -38,7 +42,10 @@ describe('options.data.test.ts', () => { assert.equal(response.data.method, 'GET'); assert(response.url.startsWith(_url)); assert(!response.redirected); - assert.equal(response.data.url, '/?sql=SELECT%20*%20from%20table&data=%E5%93%88%E5%93%88&b=&c=2222&d=1111&e=&f=true&g=a&g=b'); + assert.equal( + response.data.url, + '/?sql=SELECT%20*%20from%20table&data=%E5%93%88%E5%93%88&b=&c=2222&d=1111&e=&f=true&g=a&g=b', + ); const url = new URL(response.data.href); assert.equal(url.searchParams.get('sql'), 'SELECT * from table'); assert.equal(url.searchParams.get('data'), '哈哈'); @@ -61,7 +68,7 @@ describe('options.data.test.ts', () => { data: '哈哈', foo: { bar: 'bar value', - array: [ 1, 2, 3 ], + array: [1, 2, 3], }, }, nestedQuerystring: true, @@ -76,7 +83,10 @@ describe('options.data.test.ts', () => { assert(response.url.startsWith(_url)); // console.log(response); assert(!response.redirected); - assert.equal(response.data.url, '/?sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3'); + assert.equal( + response.data.url, + '/?sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3', + ); const query = qs.parse(response.data.url.substring(2)); const url = new URL(response.data.href); assert.equal(url.searchParams.get('sql'), 'SELECT * from table'); @@ -87,7 +97,7 @@ describe('options.data.test.ts', () => { assert.equal(url.searchParams.get('foo[array][2]'), '3'); assert.equal(query.sql, 'SELECT * from table'); assert.equal(query.data, '哈哈'); - assert.deepEqual(query.foo, { bar: 'bar value', array: [ '1', '2', '3' ] }); + assert.deepEqual(query.foo, { bar: 'bar value', array: ['1', '2', '3'] }); }); it('should GET /ok?hello=1 with data work on nestedQuerystring=true', async () => { @@ -98,7 +108,7 @@ describe('options.data.test.ts', () => { data: '哈哈', foo: { bar: 'bar value', - array: [ 1, 2, 3 ], + array: [1, 2, 3], }, }, nestedQuerystring: true, @@ -113,7 +123,10 @@ describe('options.data.test.ts', () => { assert(response.url.startsWith(_url)); // console.log(response); assert(!response.redirected); - assert.equal(response.data.url, '/ok?hello=1&sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3'); + assert.equal( + response.data.url, + '/ok?hello=1&sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3', + ); const query = qs.parse(response.data.url.substring(4)); const url = new URL(response.data.href); assert.equal(url.searchParams.get('hello'), '1'); @@ -126,7 +139,7 @@ describe('options.data.test.ts', () => { assert.equal(query.hello, '1'); assert.equal(query.sql, 'SELECT * from table'); assert.equal(query.data, '哈哈'); - assert.deepEqual(query.foo, { bar: 'bar value', array: [ '1', '2', '3' ] }); + assert.deepEqual(query.foo, { bar: 'bar value', array: ['1', '2', '3'] }); }); it('should HEAD with data and auto convert to query string', async () => { @@ -177,10 +190,12 @@ describe('options.data.test.ts', () => { requestUrl.searchParams.set('that', 'in_path'); const response = await urllib.request(requestUrl, { method: 'GET', - data: Buffer.from(JSON.stringify({ - sql: 'SELECT * from table', - data: '哈哈', - })), + data: Buffer.from( + JSON.stringify({ + sql: 'SELECT * from table', + data: '哈哈', + }), + ), dataType: 'json', }); assert.equal(response.status, 200); @@ -314,7 +329,10 @@ describe('options.data.test.ts', () => { assert.equal(response.data.requestBody.sql, 'SELECT * from table'); assert.equal(response.data.requestBody.data, '哈哈 POST'); assert.equal(response.data.requestBody.foo, '[object Object]'); - assert.equal(response.data.requestBody.__raw__, 'sql=SELECT+*+from+table&data=%E5%93%88%E5%93%88+POST&foo=%5Bobject+Object%5D'); + assert.equal( + response.data.requestBody.__raw__, + 'sql=SELECT+*+from+table&data=%E5%93%88%E5%93%88+POST&foo=%5Bobject+Object%5D', + ); }); it('should POST with application/x-www-form-urlencoded work on nestedQuerystring=true', async () => { @@ -325,7 +343,7 @@ describe('options.data.test.ts', () => { data: '哈哈', foo: { bar: 'bar value', - array: [ 1, 2, 3 ], + array: [1, 2, 3], }, }, nestedQuerystring: true, @@ -346,8 +364,11 @@ describe('options.data.test.ts', () => { assert.equal(response.data.requestBody.data, '哈哈'); assert(response.data.requestBody.foo, 'missing requestBody.foo'); assert.equal(response.data.requestBody.foo.bar, 'bar value'); - assert.deepEqual(response.data.requestBody.foo.array, [ '1', '2', '3' ]); - assert.equal(response.data.requestBody.__raw__, 'sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3'); + assert.deepEqual(response.data.requestBody.foo.array, ['1', '2', '3']); + assert.equal( + response.data.requestBody.__raw__, + 'sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3', + ); }); it('should PUT with data and contentType = json', async () => { @@ -462,11 +483,13 @@ describe('options.data.test.ts', () => { const now = new Date(); const response = await urllib.request(_url, { method: 'put', - data: Buffer.from(JSON.stringify({ - foo: 'bar', - n1: 1, - now, - })), + data: Buffer.from( + JSON.stringify({ + foo: 'bar', + n1: 1, + now, + }), + ), headers: { 'Content-Type': 'application/json; charset=gbk' }, dataType: 'json', }); @@ -480,12 +503,14 @@ describe('options.data.test.ts', () => { it('should keep data to readable when content-type exists', async () => { const now = new Date(); - const buf = Buffer.from(JSON.stringify({ - foo: 'bar', - n1: 1, - now, - })); - const readable = Readable.from([ buf ]); + const buf = Buffer.from( + JSON.stringify({ + foo: 'bar', + n1: 1, + now, + }), + ); + const readable = Readable.from([buf]); const response = await urllib.request(_url, { method: 'put', data: readable, @@ -504,12 +529,14 @@ describe('options.data.test.ts', () => { it('should keep data to readable and not set content-type', async () => { const now = new Date(); - const buf = Buffer.from(JSON.stringify({ - foo: 'bar', - n1: 1, - now, - })); - const readable = Readable.from([ buf ]); + const buf = Buffer.from( + JSON.stringify({ + foo: 'bar', + n1: 1, + now, + }), + ); + const readable = Readable.from([buf]); const response = await urllib.request(_url, { method: 'put', data: readable, diff --git a/test/options.dataType.test.ts b/test/options.dataType.test.ts index 10ee12c6..b2e0b1c9 100644 --- a/test/options.dataType.test.ts +++ b/test/options.dataType.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { nodeMajorVersion, readableToBytes } from './utils.js'; @@ -99,29 +101,37 @@ describe('options.dataType.test.ts', () => { }); it('should throw with dataType = json when response json format invaild', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}wrongjson`, { - dataType: 'json', - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'JSONResponseFormatError'); - if (err.message.startsWith('Expected')) { - if (nodeMajorVersion() >= 21) { - assert.equal(err.message, 'Expected \',\' or \'}\' after property value in JSON at position 9 (line 1 column 10) (data json format: "{\\"foo\\":\\"\\"")'); + await assert.rejects( + async () => { + await urllib.request(`${_url}wrongjson`, { + dataType: 'json', + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'JSONResponseFormatError'); + if (err.message.startsWith('Expected')) { + if (nodeMajorVersion() >= 21) { + assert.equal( + err.message, + 'Expected \',\' or \'}\' after property value in JSON at position 9 (line 1 column 10) (data json format: "{\\"foo\\":\\"\\"")', + ); + } else { + // new message on Node.js >= 19 + assert.equal( + err.message, + 'Expected \',\' or \'}\' after property value in JSON at position 9 (data json format: "{\\"foo\\":\\"\\"")', + ); + } } else { - // new message on Node.js >= 19 - assert.equal(err.message, 'Expected \',\' or \'}\' after property value in JSON at position 9 (data json format: "{\\"foo\\":\\"\\"")'); + assert.equal(err.message, 'Unexpected end of JSON input (data json format: "{\\"foo\\":\\"\\"")'); } - - } else { - assert.equal(err.message, 'Unexpected end of JSON input (data json format: "{\\"foo\\":\\"\\"")'); - } - assert.equal(err.res.status, 200); - assert.equal(err.res.headers['content-type'], 'application/json'); - assert.equal(err.res.size, 9); - return true; - }); + assert.equal(err.res.status, 200); + assert.equal(err.res.headers['content-type'], 'application/json'); + assert.equal(err.res.size, 9); + return true; + }, + ); }); it('should work with dataType = text when response json format invaild', async () => { @@ -134,18 +144,21 @@ describe('options.dataType.test.ts', () => { }); it('should handle GET /wrongjson-gbk with dataType=json and data size > 1024', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}wrongjson-gbk`, { - dataType: 'json', - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'JSONResponseFormatError'); - assert.match(err.message, /" \.\.\.skip\.\.\. "/); - assert.equal(err.res.status, 200); - assert.equal(err.res.headers['content-type'], 'application/json'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}wrongjson-gbk`, { + dataType: 'json', + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'JSONResponseFormatError'); + assert.match(err.message, /" \.\.\.skip\.\.\. "/); + assert.equal(err.res.status, 200); + assert.equal(err.res.headers['content-type'], 'application/json'); + return true; + }, + ); }); it('should work with dataType = stream', async () => { diff --git a/test/options.digestAuth.test.ts b/test/options.digestAuth.test.ts index be5e5a0e..58aebabe 100644 --- a/test/options.digestAuth.test.ts +++ b/test/options.digestAuth.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.dispatcher.test.ts b/test/options.dispatcher.test.ts index e8185e06..dfe1c7eb 100644 --- a/test/options.dispatcher.test.ts +++ b/test/options.dispatcher.test.ts @@ -1,6 +1,8 @@ import { strict as assert } from 'node:assert'; -import { describe, it, beforeAll, afterAll } from 'vitest'; + import setup from 'proxy'; +import { describe, it, beforeAll, afterAll } from 'vitest'; + import { request, ProxyAgent, getGlobalDispatcher, setGlobalDispatcher, Agent } from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -14,7 +16,7 @@ describe('options.dispatcher.test.ts', () => { close = closeServer; _url = url; proxyServer = setup(); - await new Promise(resolve => { + await new Promise((resolve) => { proxyServer.listen(0, () => { // console.log('HTTP proxy server listening on port %d', proxyServer.address().port); proxyServerUrl = `http://127.0.0.1:${proxyServer.address().port}`; @@ -25,7 +27,7 @@ describe('options.dispatcher.test.ts', () => { afterAll(async () => { await close(); - await new Promise(resolve => { + await new Promise((resolve) => { proxyServer.close(resolve); }); }); diff --git a/test/options.files.test.ts b/test/options.files.test.ts index 2cc88642..9280093e 100644 --- a/test/options.files.test.ts +++ b/test/options.files.test.ts @@ -1,9 +1,11 @@ import { strict as assert } from 'node:assert'; -import path from 'node:path'; -import fs from 'node:fs/promises'; import { createReadStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; import { Readable } from 'node:stream'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -38,24 +40,27 @@ describe('options.files.test.ts', () => { it('should upload not exists file throw error', async () => { const file = path.join(__dirname, 'cjs', 'index.js-not-exists'); - await assert.rejects(async () => { - await urllib.request(`${_url}multipart`, { - files: [ file ], - dataType: 'json', - }); - }, (err: any) => { - assert.equal(err.code, 'ENOENT'); - assert.equal(err.res.status, -1); - assert.equal(err.status, -1); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}multipart`, { + files: [file], + dataType: 'json', + }); + }, + (err: any) => { + assert.equal(err.code, 'ENOENT'); + assert.equal(err.res.status, -1); + assert.equal(err.status, -1); + return true; + }, + ); }); it('should upload files = [filepath] success with default POST method', async () => { const file = path.join(__dirname, 'cjs', 'index.js'); const stat = await fs.stat(file); const response = await urllib.request(`${_url}multipart`, { - files: [ file ], + files: [file], dataType: 'json', }); assert.equal(response.status, 200); @@ -73,7 +78,7 @@ describe('options.files.test.ts', () => { const stat = await fs.stat(file); const jsonStat = await fs.stat(json); const response = await urllib.request(`${_url}multipart`, { - files: [ file, json ], + files: [file, json], dataType: 'json', }); assert.equal(response.status, 200); @@ -177,7 +182,7 @@ describe('options.files.test.ts', () => { const buffer = await fs.readFile(__filename); const response = await urllib.request(`${_url}multipart`, { method: 'PUT', - files: [ buffer, buffer ], + files: [buffer, buffer], dataType: 'json', }); assert.equal(response.status, 200); @@ -205,7 +210,7 @@ describe('options.files.test.ts', () => { const response = await urllib.request(`${_url}multipart`, { method: 'GET', - files: [ __filename, createReadStream(__filename), buffer, stream ], + files: [__filename, createReadStream(__filename), buffer, stream], dataType: 'json', }); assert.equal(response.status, 200); @@ -235,7 +240,7 @@ describe('options.files.test.ts', () => { const txtValue = await fs.readFile(txt, 'utf-8'); const response = await urllib.request(`${_url}multipart`, { method: 'HEAD', - files: [ __filename, txtEmoji ], + files: [__filename, txtEmoji], data: { hello: 'hello world,😄😓', // \r\n => \n, should encodeURIComponent first @@ -255,9 +260,7 @@ describe('options.files.test.ts', () => { assert.equal(response.data.files.file1.mimeType, 'text/plain'); assert.equal(response.data.files.file1.size, txtEmojiStat.size); assert.equal(response.data.form.hello, 'hello world,😄😓'); - assert.equal( - JSON.stringify(decodeURIComponent(response.data.form.txtValue)), - JSON.stringify(txtValue)); + assert.equal(JSON.stringify(decodeURIComponent(response.data.form.txtValue)), JSON.stringify(txtValue)); assert.equal(decodeURIComponent(response.data.form.txtValue), txtValue); assert.equal(decodeURIComponent(response.data.form.large), largeFormValue); }); @@ -295,7 +298,7 @@ describe('options.files.test.ts', () => { files: { 'buffer.js': Buffer.from(rawData), // Readable.from data must be Buffer or Bytes - 'readable.js': Readable.from([ Buffer.from(rawData) ]), + '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 b50bb2ff..00b9b34d 100644 --- a/test/options.fixJSONCtlChars.test.ts +++ b/test/options.fixJSONCtlChars.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -29,19 +31,22 @@ describe('options.fixJSONCtlChars.test.ts', () => { }); it('should throw error when json control characters exists', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}json_with_controls_unicode`, { - dataType: 'json', - }); - }, (err: any) => { - assert.equal(err.name, 'JSONResponseFormatError'); - // console.error(err); - // JSON parse new message format on Node.js >= 19 - assert.match(err.message, /Unexpected token|Bad control character in string literal in JSON at position 8/); - assert.equal(err.status, 200); - assert.equal(err.headers['x-method'], 'GET'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}json_with_controls_unicode`, { + dataType: 'json', + }); + }, + (err: any) => { + assert.equal(err.name, 'JSONResponseFormatError'); + // console.error(err); + // JSON parse new message format on Node.js >= 19 + assert.match(err.message, /Unexpected token|Bad control character in string literal in JSON at position 8/); + assert.equal(err.status, 200); + assert.equal(err.headers['x-method'], 'GET'); + return true; + }, + ); }); it('should fix json string with custom function', async () => { diff --git a/test/options.followRedirect.test.ts b/test/options.followRedirect.test.ts index 2dd6c172..323b9319 100644 --- a/test/options.followRedirect.test.ts +++ b/test/options.followRedirect.test.ts @@ -1,6 +1,8 @@ import { strict as assert } from 'node:assert'; import { createWriteStream } from 'node:fs'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -77,7 +79,7 @@ describe('options.followRedirect.test.ts', () => { assert.equal(response.url, `${_url}redirect-deadlock`); assert.equal(response.requestUrls.length, 2); assert.equal(response.data, 'Redirect to /redirect-deadlock'); - assert.deepEqual(response.requestUrls, [ `${_url}redirect-deadlock`, `${_url}redirect-deadlock` ]); + assert.deepEqual(response.requestUrls, [`${_url}redirect-deadlock`, `${_url}redirect-deadlock`]); }); it('should maxRedirects=0 work', async () => { @@ -89,7 +91,7 @@ describe('options.followRedirect.test.ts', () => { assert.equal(response.res.statusCode, 302); assert.equal(response.url, `${_url}redirect-deadlock`); assert.equal(response.data, 'Redirect to /redirect-deadlock'); - assert.deepEqual(response.requestUrls, [ `${_url}redirect-deadlock` ]); + assert.deepEqual(response.requestUrls, [`${_url}redirect-deadlock`]); }); it('should redirect `location: /redirect-full-to-url`', async () => { diff --git a/test/options.gzip.test.ts b/test/options.gzip.test.ts index 292c9f35..f1091504 100644 --- a/test/options.gzip.test.ts +++ b/test/options.gzip.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.headers.test.ts b/test/options.headers.test.ts index 12acfacc..64a94b42 100644 --- a/test/options.headers.test.ts +++ b/test/options.headers.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.method.test.ts b/test/options.method.test.ts index a3adadb7..532250b0 100644 --- a/test/options.method.test.ts +++ b/test/options.method.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.opaque.test.ts b/test/options.opaque.test.ts index eccecc0a..36da4e01 100644 --- a/test/options.opaque.test.ts +++ b/test/options.opaque.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; @@ -30,20 +32,23 @@ describe('options.opaque.test.ts', () => { }); it('should opaque work on error request', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}socket.end.error`, { - opaque: { + await assert.rejects( + async () => { + await urllib.request(`${_url}socket.end.error`, { + opaque: { + traceId: 'some random id here', + }, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.res.status, 200); + assert.equal(err.name, 'HTTPParserError'); + assert.deepEqual(err.opaque, { traceId: 'some random id here', - }, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.res.status, 200); - assert.equal(err.name, 'HTTPParserError'); - assert.deepEqual(err.opaque, { - traceId: 'some random id here', - }); - return true; - }); + }); + return true; + }, + ); }); }); diff --git a/test/options.reset.test.ts b/test/options.reset.test.ts index 590bd590..15f2dfeb 100644 --- a/test/options.reset.test.ts +++ b/test/options.reset.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.retry.test.ts b/test/options.retry.test.ts index 1b52f7bf..c8195947 100644 --- a/test/options.retry.test.ts +++ b/test/options.retry.test.ts @@ -1,6 +1,8 @@ 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/index.js'; import { startServer } from './fixtures/server.js'; import { readableToString, createTempfile } from './utils.js'; diff --git a/test/options.signal.test.ts b/test/options.signal.test.ts index 6c67a8f1..cd779971 100644 --- a/test/options.signal.test.ts +++ b/test/options.signal.test.ts @@ -1,7 +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/index.js'; import { startServer } from './fixtures/server.js'; @@ -19,37 +21,43 @@ describe('options.signal.test.ts', () => { }); it('should throw error when AbortController abort', async () => { - await assert.rejects(async () => { - const abortController = new AbortController(); - const p = urllib.request(`${_url}?timeout=2000`, { - signal: abortController.signal, - }); - await sleep(100); - abortController.abort(); - await p; - }, (err: any) => { - assert.equal(err.name, 'AbortError'); - assert.equal(err.message, 'This operation was aborted'); - assert.equal(err.code, 20); - return true; - }); + await assert.rejects( + async () => { + const abortController = new AbortController(); + const p = urllib.request(`${_url}?timeout=2000`, { + signal: abortController.signal, + }); + await sleep(100); + abortController.abort(); + await p; + }, + (err: any) => { + assert.equal(err.name, 'AbortError'); + assert.equal(err.message, 'This operation was aborted'); + assert.equal(err.code, 20); + return true; + }, + ); }); it('should throw error when EventEmitter emit abort event', async () => { - await assert.rejects(async () => { - const ee = new EventEmitter(); - const p = urllib.request(`${_url}?timeout=2000`, { - signal: ee, - }); - await sleep(100); - ee.emit('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'); - return true; - }); + await assert.rejects( + async () => { + const ee = new EventEmitter(); + const p = urllib.request(`${_url}?timeout=2000`, { + signal: ee, + }); + await sleep(100); + ee.emit('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'); + return true; + }, + ); }); }); diff --git a/test/options.socketErrorRetry.test.ts b/test/options.socketErrorRetry.test.ts index 5831785c..8564c25d 100644 --- a/test/options.socketErrorRetry.test.ts +++ b/test/options.socketErrorRetry.test.ts @@ -1,6 +1,8 @@ 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/index.js'; import { startServer } from './fixtures/server.js'; import { createTempfile } from './utils.js'; @@ -31,15 +33,18 @@ describe('options.socketErrorRetry.test.ts', () => { }); it('should auto retry on socket error and still fail', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - dataType: 'json', - }); - }, (err: any) => { - assert.equal(err.res.retries, 0); - assert.equal(err.res.socketErrorRetries, 1); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + dataType: 'json', + }); + }, + (err: any) => { + assert.equal(err.res.retries, 0); + assert.equal(err.res.socketErrorRetries, 1); + return true; + }, + ); }); it('should auto retry on socket error and success', async () => { @@ -50,35 +55,44 @@ describe('options.socketErrorRetry.test.ts', () => { }); it('should not retry on streaming request', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - streaming: true, - }); - }, (err: any) => { - assert.equal(err.res.retries, 0); - assert.equal(err.res.socketErrorRetries, 0); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + streaming: true, + }); + }, + (err: any) => { + assert.equal(err.res.retries, 0); + assert.equal(err.res.socketErrorRetries, 0); + return true; + }, + ); const writeStream = createWriteStream(tmpfile); - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - writeStream, - }); - }, (err: any) => { - assert.equal(err.res.retries, 0); - assert.equal(err.res.socketErrorRetries, 0); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + writeStream, + }); + }, + (err: any) => { + assert.equal(err.res.retries, 0); + assert.equal(err.res.socketErrorRetries, 0); + return true; + }, + ); - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - files: createReadStream(__filename), - }); - }, (err: any) => { - assert.equal(err.res.retries, 0); - assert.equal(err.res.socketErrorRetries, 0); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + files: createReadStream(__filename), + }); + }, + (err: any) => { + assert.equal(err.res.retries, 0); + assert.equal(err.res.socketErrorRetries, 0); + return true; + }, + ); }); }); diff --git a/test/options.socketPath.test.ts b/test/options.socketPath.test.ts index 3e7fd6e8..bb89727c 100644 --- a/test/options.socketPath.test.ts +++ b/test/options.socketPath.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/socket_server.js'; import { isWindows } from './utils.js'; @@ -70,4 +72,3 @@ describe.skipIf(isWindows())('options.socketPath.test.ts', () => { assert.equal(result2.data.name, 'urllib'); }); }); - diff --git a/test/options.stream.test.ts b/test/options.stream.test.ts index 07f8a71b..f7260011 100644 --- a/test/options.stream.test.ts +++ b/test/options.stream.test.ts @@ -1,12 +1,14 @@ import { strict as assert } from 'node:assert'; import { createReadStream } from 'node:fs'; -import path from 'node:path'; import { writeFile, readFile } from 'node:fs/promises'; -import { createGunzip } from 'node:zlib'; +import path from 'node:path'; import { Readable } from 'node:stream'; -import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; -import tar from 'tar-stream'; +import { createGunzip } from 'node:zlib'; + import FormStream from 'formstream'; +import tar from 'tar-stream'; +import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; + import urllib from '../src/index.js'; import { isReadable } from '../src/utils.js'; import { startServer } from './fixtures/server.js'; @@ -87,7 +89,7 @@ describe('options.stream.test.ts', () => { const response = await urllib.request(`${_url}multipart`, { method: 'post', dataType: 'json', - stream: form, + stream: form as any, headers: form.headers(), }); assert.equal(response.status, 200); @@ -106,21 +108,24 @@ describe('options.stream.test.ts', () => { const stream = createReadStream(tmpfile); assert.equal(stream.destroyed, false); - await assert.rejects(async () => { - await urllib.request(`${_url}block`, { - method: 'post', - timeout: 100, - stream, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 100 ms'); - err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); - // stream should be close after request error fire - assert.equal(stream.destroyed, true); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}block`, { + method: 'post', + timeout: 100, + stream, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 100 ms'); + err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); + // stream should be close after request error fire + assert.equal(stream.destroyed, true); + return true; + }, + ); }); it('should close 10MB size request stream when request timeout', async () => { @@ -128,21 +133,24 @@ describe('options.stream.test.ts', () => { const stream = createReadStream(tmpfile); assert.equal(stream.destroyed, false); - await assert.rejects(async () => { - await urllib.request(`${_url}block`, { - method: 'post', - timeout: 100, - stream, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 100 ms'); - err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); - // stream should be close after request error fire - assert.equal(stream.destroyed, true); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}block`, { + method: 'post', + timeout: 100, + stream, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 100 ms'); + err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); + // stream should be close after request error fire + assert.equal(stream.destroyed, true); + return true; + }, + ); }); it('should throw request error when stream error', async () => { @@ -151,18 +159,21 @@ describe('options.stream.test.ts', () => { stream.on('error', () => { streamError = true; }); - await assert.rejects(async () => { - await urllib.request(`${_url}block`, { - method: 'post', - stream, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'Error'); - assert.match(err.message, /no such file or directory/); - assert.equal(stream.destroyed, true); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}block`, { + method: 'post', + stream, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'Error'); + assert.match(err.message, /no such file or directory/); + assert.equal(stream.destroyed, true); + return true; + }, + ); assert.equal(stream.destroyed, true); assert.equal(streamError, true); }); diff --git a/test/options.streaming.test.ts b/test/options.streaming.test.ts index f0e97dac..d25d37d2 100644 --- a/test/options.streaming.test.ts +++ b/test/options.streaming.test.ts @@ -1,7 +1,9 @@ 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/index.js'; import { isReadable } from '../src/utils.js'; import { startServer } from './fixtures/server.js'; @@ -78,16 +80,20 @@ describe('options.streaming.test.ts', () => { assert.equal(response.headers['content-encoding'], 'br'); // console.log(response.headers); requestHeaders = JSON.parse(response.headers['x-request-headers'] as string); - assert(!requestHeaders['accept-encoding'], - `should not contains accept-encoding header: ${requestHeaders['accept-encoding']}`); + assert( + !requestHeaders['accept-encoding'], + `should not contains accept-encoding header: ${requestHeaders['accept-encoding']}`, + ); assert.equal(response.data, null); // console.log(response.res); // response.res stream is not decompressed assert(isReadable(response.res)); let decoder = createBrotliDecompress(); - bytes = await readableToBytes(pipeline(response.res, decoder, () => { - return; - })); + bytes = await readableToBytes( + pipeline(response.res, decoder, () => { + return; + }), + ); data = bytes.toString(); assert.match(data, /export async function startServer/); @@ -108,9 +114,11 @@ describe('options.streaming.test.ts', () => { // response.res stream is not decompressed assert(isReadable(response.res)); decoder = createBrotliDecompress(); - bytes = await readableToBytes(pipeline(response.res, decoder, () => { - return; - })); + bytes = await readableToBytes( + pipeline(response.res, decoder, () => { + return; + }), + ); data = bytes.toString(); assert.match(data, /export async function startServer/); }); diff --git a/test/options.timeout.test.ts b/test/options.timeout.test.ts index d56d7922..48848200 100644 --- a/test/options.timeout.test.ts +++ b/test/options.timeout.test.ts @@ -1,8 +1,11 @@ import { strict as assert } from 'node:assert'; -import { createSecureServer } from 'node:http2'; import { once } from 'node:events'; +import { createSecureServer } from 'node:http2'; +import { AddressInfo } from 'node:net'; + import selfsigned from 'selfsigned'; import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib, { HttpClientRequestTimeoutError, HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { nodeMajorVersion } from './utils.js'; @@ -25,44 +28,50 @@ describe('options.timeout.test.ts', () => { }); it('should HeadersTimeout 1000ms throw error', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}?timeout=2000`, { - timeout: 10, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 10 ms'); - 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}`); - assert.equal(typeof err.res.rt, 'number'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}?timeout=2000`, { + timeout: 10, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 10 ms'); + 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}`); + assert.equal(typeof err.res.rt, 'number'); + return true; + }, + ); }); it('should timeout support string format', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}?timeout=2000`, { - // @ts-expect-error check string format - timeout: '10', - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 10 ms'); - 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}`); - assert.equal(typeof err.res.rt, 'number'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}?timeout=2000`, { + // @ts-expect-error check string format + timeout: '10', + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 10 ms'); + 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}`); + assert.equal(typeof err.res.rt, 'number'); + return true; + }, + ); }); it('should timeout on h2', async () => { @@ -85,75 +94,87 @@ describe('options.timeout.test.ts', () => { server.listen(0); await once(server, 'listening'); - const url = `https://localhost:${server.address()!.port}`; - await assert.rejects(async () => { - await httpClient.request(url, { - timeout: 10, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 10 ms'); - assert.equal(err.cause.name, 'InformationalError'); - assert.equal(err.cause.message, 'HTTP/2: "stream timeout after 10"'); - assert.equal(err.cause.code, 'UND_ERR_INFO'); - - assert.equal(err.res.status, -1); - assert(err.res.rt > 10, `actual ${err.res.rt}`); - assert.equal(typeof err.res.rt, 'number'); - return true; - }); + const url = `https://localhost:${(server.address() as AddressInfo).port}`; + await assert.rejects( + async () => { + await httpClient.request(url, { + timeout: 10, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 10 ms'); + assert.equal(err.cause.name, 'InformationalError'); + assert.equal(err.cause.message, 'HTTP/2: "stream timeout after 10"'); + assert.equal(err.cause.code, 'UND_ERR_INFO'); + + assert.equal(err.res.status, -1); + assert(err.res.rt > 10, `actual ${err.res.rt}`); + assert.equal(typeof err.res.rt, 'number'); + return true; + }, + ); }); it('should BodyTimeout throw error', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}mock-bytes?timeout=2000`, { - timeout: 100, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 100 ms'); - if (err.cause) { - assert.equal(err.cause.name, 'BodyTimeoutError'); - assert.equal(err.cause.message, 'Body Timeout Error'); - assert.equal(err.cause.code, 'UND_ERR_BODY_TIMEOUT'); - } - assert.equal(err.res.status, 200); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}mock-bytes?timeout=2000`, { + timeout: 100, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 100 ms'); + if (err.cause) { + assert.equal(err.cause.name, 'BodyTimeoutError'); + assert.equal(err.cause.message, 'Body Timeout Error'); + assert.equal(err.cause.code, 'UND_ERR_BODY_TIMEOUT'); + } + assert.equal(err.res.status, 200); + return true; + }, + ); }); it('should timeout 500ms throw error', async () => { - await assert.rejects(async () => { - const response = await urllib.request(`${_url}mock-bytes?timeout=1500`, { - timeout: [ 400, 500 ], - }); - console.log(response.status, response.headers, response.data); - }, (err: any) => { - // console.log(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 500 ms'); - assert.equal(err.res.status, 200); - err.cause && assert.equal(err.cause.name, 'BodyTimeoutError'); - return true; - }); + await assert.rejects( + async () => { + const response = await urllib.request(`${_url}mock-bytes?timeout=1500`, { + timeout: [400, 500], + }); + console.log(response.status, response.headers, response.data); + }, + (err: any) => { + // console.log(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 500 ms'); + assert.equal(err.res.status, 200); + err.cause && assert.equal(err.cause.name, 'BodyTimeoutError'); + return true; + }, + ); }); it('should timeout on server block', async () => { - await assert.rejects(async () => { - await urllib.request(`${_url}block`, { - timeout: 100, - }); - }, (err: HttpClientRequestTimeoutError) => { - // console.log(err); - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 100 ms'); - assert.equal(err.res!.status, -1); - assert(err.headers); - assert.equal(err.status, -1); - err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}block`, { + timeout: 100, + }); + }, + (err: HttpClientRequestTimeoutError) => { + // console.log(err); + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 100 ms'); + assert.equal(err.res!.status, -1); + assert(err.headers); + assert.equal(err.status, -1); + err.cause && assert.equal((err.cause as any).name, 'HeadersTimeoutError'); + return true; + }, + ); }); }); diff --git a/test/options.timing.test.ts b/test/options.timing.test.ts index e1ae0c51..40811f89 100644 --- a/test/options.timing.test.ts +++ b/test/options.timing.test.ts @@ -1,6 +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, { RawResponseWithMeta } from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.type.test.ts b/test/options.type.test.ts index 7bbf3049..bc39a8bb 100644 --- a/test/options.type.test.ts +++ b/test/options.type.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/options.writeStream.test.ts b/test/options.writeStream.test.ts index 5c98bdb5..20f34f96 100644 --- a/test/options.writeStream.test.ts +++ b/test/options.writeStream.test.ts @@ -1,10 +1,12 @@ import { strict as assert } from 'node:assert'; import { createWriteStream } from 'node:fs'; -import { join } from 'node:path'; -import { gunzipSync } from 'node:zlib'; import { stat, readFile } from 'node:fs/promises'; +import { join } from 'node:path'; import { setTimeout as sleep } from 'node:timers/promises'; +import { gunzipSync } from 'node:zlib'; + import { describe, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { createTempfile } from './utils.js'; @@ -82,18 +84,21 @@ describe('options.writeStream.test.ts', () => { writeStreamClosed = true; // console.log('writeStreamClosed'); }); - await assert.rejects(async () => { - await urllib.request(`${_url}mock-bytes?size=1024&timeout=2000`, { - writeStream, - timeout: 100, - }); - }, (err: any) => { - assert.equal(err.name, 'HttpClientRequestTimeoutError'); - assert.equal(err.message, 'Request timeout for 100 ms'); - // writeStream should be close before request error fire - assert.equal(writeStream.destroyed, true); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}mock-bytes?size=1024&timeout=2000`, { + writeStream, + timeout: 100, + }); + }, + (err: any) => { + assert.equal(err.name, 'HttpClientRequestTimeoutError'); + assert.equal(err.message, 'Request timeout for 100 ms'); + // writeStream should be close before request error fire + assert.equal(writeStream.destroyed, true); + return true; + }, + ); await sleep(30); // writeStream close assert.equal(writeStream.destroyed, true); @@ -109,40 +114,46 @@ describe('options.writeStream.test.ts', () => { writeStream.on('error', () => { writeStreamError = true; }); - await assert.rejects(async () => { - await urllib.request(_url, { - writeStream, - }); - }, (err: any) => { - // only Node.js >= 18 has stream.emitError - if (err.message !== 'writeStream is destroyed') { - assert.equal(err.name, 'Error'); - assert.match(err.code, /^ENOENT|ERR_STREAM_UNABLE_TO_PIPE$/); - if (err.code === 'ERR_STREAM_UNABLE_TO_PIPE') { - // change to ERR_STREAM_UNABLE_TO_PIPE on Node.js >= 23 - assert.equal(err.message, 'Cannot pipe to a closed or destroyed stream'); - } else { - assert.match(err.message, /no such file or directory/); + await assert.rejects( + async () => { + await urllib.request(_url, { + writeStream, + }); + }, + (err: any) => { + // only Node.js >= 18 has stream.emitError + if (err.message !== 'writeStream is destroyed') { + assert.equal(err.name, 'Error'); + assert.match(err.code, /^ENOENT|ERR_STREAM_UNABLE_TO_PIPE$/); + if (err.code === 'ERR_STREAM_UNABLE_TO_PIPE') { + // change to ERR_STREAM_UNABLE_TO_PIPE on Node.js >= 23 + assert.equal(err.message, 'Cannot pipe to a closed or destroyed stream'); + } else { + assert.match(err.message, /no such file or directory/); + } } - } - return true; - }); + return true; + }, + ); assert.equal(writeStream.destroyed, true); assert.equal(writeStreamError, true); }); it('should end writeStream when server error', async () => { const writeStream = createWriteStream(tmpfile); - await assert.rejects(async () => { - await urllib.request(`${_url}error`, { - writeStream, - }); - }, (err: any) => { - // console.error(err); - assert.equal(err.name, 'SocketError'); - assert.equal(err.code, 'UND_ERR_SOCKET'); - assert.equal(err.message, 'other side closed'); - return true; - }); + await assert.rejects( + async () => { + await urllib.request(`${_url}error`, { + writeStream, + }); + }, + (err: any) => { + // console.error(err); + assert.equal(err.name, 'SocketError'); + assert.equal(err.code, 'UND_ERR_SOCKET'); + assert.equal(err.message, 'other side closed'); + return true; + }, + ); }); }); diff --git a/test/response-charset-gbk.test.ts b/test/response-charset-gbk.test.ts index 3c929754..47a07d89 100644 --- a/test/response-charset-gbk.test.ts +++ b/test/response-charset-gbk.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/urllib.options.allowH2.test.ts b/test/urllib.options.allowH2.test.ts index 1dd78ddb..6027f20a 100644 --- a/test/urllib.options.allowH2.test.ts +++ b/test/urllib.options.allowH2.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it } from 'vitest'; + import urllib from '../src/index.js'; describe('urllib.options.allowH2.test.ts', () => { diff --git a/test/urllib.options.rejectUnauthorized-false.test.ts b/test/urllib.options.rejectUnauthorized-false.test.ts index 18162dd4..c64ede7c 100644 --- a/test/urllib.options.rejectUnauthorized-false.test.ts +++ b/test/urllib.options.rejectUnauthorized-false.test.ts @@ -1,8 +1,11 @@ import { strict as assert } from 'node:assert'; import { once } from 'node:events'; import { createSecureServer } from 'node:http2'; -import { describe, it, beforeAll, afterAll } from 'vitest'; +import { AddressInfo } from 'node:net'; + import selfsigned from 'selfsigned'; +import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib, { HttpClient } from '../src/index.js'; import { startServer } from './fixtures/server.js'; import { nodeMajorVersion } from './utils.js'; @@ -58,7 +61,7 @@ describe('urllib.options.rejectUnauthorized-false.test.ts', () => { }, }); - const url = `https://localhost:${server.address()!.port}`; + const url = `https://localhost:${(server.address() as AddressInfo).port}`; const response1 = await httpClient.request(url, {}); assert.equal(response1.status, 200); assert.equal(response1.data.toString(), 'hello h2!'); diff --git a/test/user-agent.test.ts b/test/user-agent.test.ts index 3e6c97a5..2bfa8aba 100644 --- a/test/user-agent.test.ts +++ b/test/user-agent.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it, beforeAll, afterAll } from 'vitest'; + import urllib from '../src/index.js'; import { startServer } from './fixtures/server.js'; diff --git a/test/utils.test.ts b/test/utils.test.ts index 8d7f7ec0..a88fcee5 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,5 +1,7 @@ import { strict as assert } from 'node:assert'; + import { describe, it } from 'vitest'; + import { globalId } from '../src/utils.js'; describe('utils.test.ts', () => { diff --git a/test/utils.ts b/test/utils.ts index e3ff1044..589a71f7 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,9 +1,9 @@ -import { Readable } from 'node:stream'; -import { ReadableStream } from 'node:stream/web'; +import { randomUUID } from 'node:crypto'; import { rm, writeFile } from 'node:fs/promises'; -import { join } from 'node:path'; import { tmpdir, platform } from 'node:os'; -import { randomUUID } from 'node:crypto'; +import { join } from 'node:path'; +import { Readable } from 'node:stream'; +import { ReadableStream } from 'node:stream/web'; export async function readableToBytes(stream: Readable | ReadableStream) { const chunks: Buffer[] = []; diff --git a/tsconfig.json b/tsconfig.json index ff41b734..a83410c1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "noImplicitAny": true, "target": "ES2022", "module": "NodeNext", - "moduleResolution": "NodeNext" - } + "moduleResolution": "NodeNext", + }, + "exclude": ["test/fixtures/ts*"], } diff --git a/vite.config.ts b/vite.config.ts index 2b14458a..5dcbc4a8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,18 +2,12 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - include: [ - 'test/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', - ], + include: ['test/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], testTimeout: 60000, coverage: { - include: [ - 'src', - ], + include: ['src'], }, pool: 'threads', - setupFiles: [ - 'test/setup.ts', - ], + setupFiles: ['test/setup.ts'], }, });