From f5a1df6d7b95ded1b90650ce6510297ff3b5752b Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 27 Feb 2026 19:14:29 +0200 Subject: [PATCH 01/37] chore: small fixes to tests --- rollup.config.js | 27 ++++++---------- test/specs/__helpers.js | 2 ++ test/specs/adapter.spec.js | 2 ++ test/specs/api.spec.js | 1 + test/specs/basicAuth.spec.js | 2 ++ test/specs/cancel.spec.js | 2 ++ test/specs/cancel/CancelToken.spec.js | 1 + test/specs/cancel/CanceledError.spec.js | 1 + test/specs/cancel/isCancel.spec.js | 1 + test/specs/core/AxiosError.spec.js | 31 ++++++++++--------- test/specs/core/buildFullPath.spec.js | 1 + test/specs/core/mergeConfig.spec.js | 1 + test/specs/core/settle.spec.js | 1 + test/specs/core/transformData.spec.js | 1 + test/specs/defaults.spec.js | 2 ++ test/specs/formdata.spec.js | 1 + test/specs/headers.spec.js | 2 ++ test/specs/helpers/bind.spec.js | 1 + test/specs/helpers/buildURL.spec.js | 1 + test/specs/helpers/combineURLs.spec.js | 1 + test/specs/helpers/cookies.spec.js | 1 + test/specs/helpers/formDataToJSON.spec.js | 1 + test/specs/helpers/isAbsoluteURL.spec.js | 1 + test/specs/helpers/isAxiosError.spec.js | 1 + test/specs/helpers/isURLSameOrigin.spec.js | 1 + test/specs/helpers/parseHeaders.spec.js | 1 + test/specs/helpers/spread.spec.js | 1 + test/specs/helpers/toFormData.spec.js | 1 + test/specs/helpers/validator.spec.js | 1 + test/specs/instance.spec.js | 2 ++ test/specs/interceptors.spec.js | 2 ++ test/specs/options.spec.js | 3 ++ test/specs/progress.spec.js | 2 ++ test/specs/promise.spec.js | 2 ++ test/specs/requests.spec.js | 2 ++ test/specs/transform.spec.js | 2 ++ test/specs/utils/endsWith.js | 1 + test/specs/utils/extend.spec.js | 1 + test/specs/utils/forEach.spec.js | 1 + test/specs/utils/isX.spec.js | 1 + test/specs/utils/kindOf.js | 1 + test/specs/utils/kindOfTest.js | 1 + test/specs/utils/merge.spec.js | 1 + test/specs/utils/toArray.js | 1 + test/specs/utils/toFlatObject.js | 1 + test/specs/utils/trim.spec.js | 1 + test/specs/xsrf.spec.js | 2 ++ test/unit/adapters/adapters.js | 1 + test/unit/adapters/fetch.js | 1 + test/unit/adapters/http.js | 1 + test/unit/core/Axios.js | 1 + test/unit/core/AxiosHeaders.js | 1 + test/unit/core/prototypePollution.js | 2 ++ test/unit/defaults/transformResponse.js | 1 + test/unit/helpers/composeSignals.js | 1 + .../estimateDataURLDecodedBytes.spec.js | 1 + test/unit/helpers/fromDataURI.js | 1 + test/unit/helpers/parseProtocol.js | 1 + test/unit/helpers/toFormData.js | 1 + test/unit/platform/index.js | 1 + test/unit/regression/SNYK-JS-AXIOS-1038255.js | 1 + test/unit/regression/SNYK-JS-AXIOS-7361793.js | 1 + test/unit/regression/bugs.js | 1 + test/unit/utils/utils.js | 1 + 64 files changed, 104 insertions(+), 32 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index b2741a0550..7d1cd05029 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -75,21 +75,6 @@ export default async () => { banner, }, }), - // browser ESM bundle for CDN with fetch adapter only - // Downsizing from 12.97 kB (gzip) to 12.23 kB (gzip) - /* ...buildConfig({ - input: namedInput, - output: { - file: `dist/esm/${outputFileName}-fetch.js`, - format: "esm", - preferConst: true, - exports: "named", - banner - }, - alias: [ - { find: './xhr.js', replacement: '../helpers/null.js' } - ] - }),*/ // Browser UMD bundle for CDN ...buildConfig({ @@ -118,7 +103,7 @@ export default async () => { }, }), - // Node.js commonjs bundle + // Node.js commonjs bundle (transpiled for Node 12) { input: defaultInput, output: { @@ -128,7 +113,15 @@ export default async () => { exports: 'default', banner, }, - plugins: [autoExternal(), resolve(), commonjs()], + plugins: [ + autoExternal(), + resolve(), + commonjs(), + babel({ + babelHelpers: 'bundled', + presets: [['@babel/preset-env', { targets: { node: '12' } }]], + }), + ], }, ]; }; diff --git a/test/specs/__helpers.js b/test/specs/__helpers.js index 94ace3d820..a00eb2c4a6 100644 --- a/test/specs/__helpers.js +++ b/test/specs/__helpers.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ import _axios from '../../index.js'; window.axios = _axios; diff --git a/test/specs/adapter.spec.js b/test/specs/adapter.spec.js index 4a5bc1eaa5..9e23f27477 100644 --- a/test/specs/adapter.spec.js +++ b/test/specs/adapter.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('adapter', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/api.spec.js b/test/specs/api.spec.js index 11a3be51e4..767474ed40 100644 --- a/test/specs/api.spec.js +++ b/test/specs/api.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ describe('static api', function () { it('should have request method helpers', function () { expect(typeof axios.request).toEqual('function'); diff --git a/test/specs/basicAuth.spec.js b/test/specs/basicAuth.spec.js index ccdef2138f..4c9034211a 100644 --- a/test/specs/basicAuth.spec.js +++ b/test/specs/basicAuth.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ import axios from '../../index'; function validateInvalidCharacterError(error) { diff --git a/test/specs/cancel.spec.js b/test/specs/cancel.spec.js index d91d0c6895..a0b3d24837 100644 --- a/test/specs/cancel.spec.js +++ b/test/specs/cancel.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ const Cancel = axios.Cancel; const CancelToken = axios.CancelToken; import { AbortController as _AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; diff --git a/test/specs/cancel/CancelToken.spec.js b/test/specs/cancel/CancelToken.spec.js index 9264a0c8d5..66e125ae43 100644 --- a/test/specs/cancel/CancelToken.spec.js +++ b/test/specs/cancel/CancelToken.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import CancelToken from '../../../lib/cancel/CancelToken'; import CanceledError from '../../../lib/cancel/CanceledError'; diff --git a/test/specs/cancel/CanceledError.spec.js b/test/specs/cancel/CanceledError.spec.js index df470c4c36..7b9c39db29 100644 --- a/test/specs/cancel/CanceledError.spec.js +++ b/test/specs/cancel/CanceledError.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import CanceledError from '../../../lib/cancel/CanceledError'; describe('Cancel', function () { diff --git a/test/specs/cancel/isCancel.spec.js b/test/specs/cancel/isCancel.spec.js index 4e685487c9..159738dcda 100644 --- a/test/specs/cancel/isCancel.spec.js +++ b/test/specs/cancel/isCancel.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import isCancel from '../../../lib/cancel/isCancel'; import CanceledError from '../../../lib/cancel/CanceledError'; diff --git a/test/specs/core/AxiosError.spec.js b/test/specs/core/AxiosError.spec.js index e5a8bc8c32..409f2017a3 100644 --- a/test/specs/core/AxiosError.spec.js +++ b/test/specs/core/AxiosError.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import AxiosError from '../../../lib/core/AxiosError'; describe('core::AxiosError', function () { @@ -86,24 +87,24 @@ describe('core::AxiosError', function () { }); it('should have message property as enumerable for backward compatibility', () => { - const err = new AxiosError('Test error message', 'ERR_TEST', {foo: 'bar'}); + const err = new AxiosError('Test error message', 'ERR_TEST', { foo: 'bar' }); - // Test Object.keys() includes message - const keys = Object.keys(err); - expect(keys).toContain('message'); + // Test Object.keys() includes message + const keys = Object.keys(err); + expect(keys).toContain('message'); - // Test Object.entries() includes message - const entries = Object.entries(err); - const messageEntry = entries.find(([key]) => key === 'message'); - expect(messageEntry).toBeDefined(); - expect(messageEntry[1]).toBe('Test error message'); + // Test Object.entries() includes message + const entries = Object.entries(err); + const messageEntry = entries.find(([key]) => key === 'message'); + expect(messageEntry).toBeDefined(); + expect(messageEntry[1]).toBe('Test error message'); - // Test spread operator includes message - const spread = {...err}; - expect(spread.message).toBe('Test error message'); + // Test spread operator includes message + const spread = { ...err }; + expect(spread.message).toBe('Test error message'); - // Verify message descriptor is enumerable - const descriptor = Object.getOwnPropertyDescriptor(err, 'message'); - expect(descriptor.enumerable).toBe(true); + // Verify message descriptor is enumerable + const descriptor = Object.getOwnPropertyDescriptor(err, 'message'); + expect(descriptor.enumerable).toBe(true); }); }); diff --git a/test/specs/core/buildFullPath.spec.js b/test/specs/core/buildFullPath.spec.js index ea3ed10162..a6d8048d5c 100644 --- a/test/specs/core/buildFullPath.spec.js +++ b/test/specs/core/buildFullPath.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import buildFullPath from '../../../lib/core/buildFullPath'; describe('helpers::buildFullPath', function () { diff --git a/test/specs/core/mergeConfig.spec.js b/test/specs/core/mergeConfig.spec.js index 4add0b0ef7..45110274ef 100644 --- a/test/specs/core/mergeConfig.spec.js +++ b/test/specs/core/mergeConfig.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import defaults from '../../../lib/defaults'; import mergeConfig from '../../../lib/core/mergeConfig'; import { AxiosHeaders } from '../../../index.js'; diff --git a/test/specs/core/settle.spec.js b/test/specs/core/settle.spec.js index 7a13e965a2..cea58fb653 100644 --- a/test/specs/core/settle.spec.js +++ b/test/specs/core/settle.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import settle from '../../../lib/core/settle'; describe('core::settle', function () { diff --git a/test/specs/core/transformData.spec.js b/test/specs/core/transformData.spec.js index dd3626adf6..190f8b5112 100644 --- a/test/specs/core/transformData.spec.js +++ b/test/specs/core/transformData.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import transformData from '../../../lib/core/transformData'; describe('core::transformData', function () { diff --git a/test/specs/defaults.spec.js b/test/specs/defaults.spec.js index 53a942131a..74a6e0bfec 100644 --- a/test/specs/defaults.spec.js +++ b/test/specs/defaults.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ import defaults from '../../lib/defaults'; import AxiosHeaders from '../../lib/core/AxiosHeaders'; diff --git a/test/specs/formdata.spec.js b/test/specs/formdata.spec.js index 0b8c01c3fe..b7ef2d1fcd 100644 --- a/test/specs/formdata.spec.js +++ b/test/specs/formdata.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import { retryNetwork } from '../helpers/retry.js'; describe('FormData', function () { diff --git a/test/specs/headers.spec.js b/test/specs/headers.spec.js index a95e22b84c..6a0c4ea5b8 100644 --- a/test/specs/headers.spec.js +++ b/test/specs/headers.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ const { AxiosHeaders } = axios; function testHeaderValue(headers, key, val) { diff --git a/test/specs/helpers/bind.spec.js b/test/specs/helpers/bind.spec.js index 1efb30e3f3..bb66a66594 100644 --- a/test/specs/helpers/bind.spec.js +++ b/test/specs/helpers/bind.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import bind from '../../../lib/helpers/bind'; describe('bind', function () { diff --git a/test/specs/helpers/buildURL.spec.js b/test/specs/helpers/buildURL.spec.js index 0f137bafd2..06bb86d2f1 100644 --- a/test/specs/helpers/buildURL.spec.js +++ b/test/specs/helpers/buildURL.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import buildURL from '../../../lib/helpers/buildURL'; describe('helpers::buildURL', function () { diff --git a/test/specs/helpers/combineURLs.spec.js b/test/specs/helpers/combineURLs.spec.js index 92e5116e33..81f4549f21 100644 --- a/test/specs/helpers/combineURLs.spec.js +++ b/test/specs/helpers/combineURLs.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import combineURLs from '../../../lib/helpers/combineURLs'; describe('helpers::combineURLs', function () { diff --git a/test/specs/helpers/cookies.spec.js b/test/specs/helpers/cookies.spec.js index 812f6d0605..ee60fb33f6 100644 --- a/test/specs/helpers/cookies.spec.js +++ b/test/specs/helpers/cookies.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import cookies from '../../../lib/helpers/cookies'; describe('helpers::cookies', function () { diff --git a/test/specs/helpers/formDataToJSON.spec.js b/test/specs/helpers/formDataToJSON.spec.js index deb078023e..4bc3ec4fbc 100644 --- a/test/specs/helpers/formDataToJSON.spec.js +++ b/test/specs/helpers/formDataToJSON.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import formDataToJSON from '../../../lib/helpers/formDataToJSON'; describe('formDataToJSON', function () { diff --git a/test/specs/helpers/isAbsoluteURL.spec.js b/test/specs/helpers/isAbsoluteURL.spec.js index 872f5efbe1..0a6bfaac09 100644 --- a/test/specs/helpers/isAbsoluteURL.spec.js +++ b/test/specs/helpers/isAbsoluteURL.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import isAbsoluteURL from '../../../lib/helpers/isAbsoluteURL'; describe('helpers::isAbsoluteURL', function () { diff --git a/test/specs/helpers/isAxiosError.spec.js b/test/specs/helpers/isAxiosError.spec.js index 8dedea77af..37cbf1b5b1 100644 --- a/test/specs/helpers/isAxiosError.spec.js +++ b/test/specs/helpers/isAxiosError.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import AxiosError from '../../../lib/core/AxiosError'; import isAxiosError from '../../../lib/helpers/isAxiosError'; diff --git a/test/specs/helpers/isURLSameOrigin.spec.js b/test/specs/helpers/isURLSameOrigin.spec.js index fb16b2f4df..e0c418739c 100644 --- a/test/specs/helpers/isURLSameOrigin.spec.js +++ b/test/specs/helpers/isURLSameOrigin.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import isURLSameOrigin from '../../../lib/helpers/isURLSameOrigin'; describe('helpers::isURLSameOrigin', function () { diff --git a/test/specs/helpers/parseHeaders.spec.js b/test/specs/helpers/parseHeaders.spec.js index 60d3895f15..0d2e266d43 100644 --- a/test/specs/helpers/parseHeaders.spec.js +++ b/test/specs/helpers/parseHeaders.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import parseHeaders from '../../../lib/helpers/parseHeaders'; describe('helpers::parseHeaders', function () { diff --git a/test/specs/helpers/spread.spec.js b/test/specs/helpers/spread.spec.js index a9f9855784..7d49cacf09 100644 --- a/test/specs/helpers/spread.spec.js +++ b/test/specs/helpers/spread.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import spread from '../../../lib/helpers/spread'; describe('helpers::spread', function () { diff --git a/test/specs/helpers/toFormData.spec.js b/test/specs/helpers/toFormData.spec.js index 246118e4b9..a6ff198d68 100644 --- a/test/specs/helpers/toFormData.spec.js +++ b/test/specs/helpers/toFormData.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import toFormData from '../../../lib/helpers/toFormData'; describe('toFormData', function () { diff --git a/test/specs/helpers/validator.spec.js b/test/specs/helpers/validator.spec.js index 1b7b194f93..1bffd46dc8 100644 --- a/test/specs/helpers/validator.spec.js +++ b/test/specs/helpers/validator.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ 'use strict'; import validator from '../../../lib/helpers/validator'; diff --git a/test/specs/instance.spec.js b/test/specs/instance.spec.js index 6fb6da07a1..3c5fd9c8ad 100644 --- a/test/specs/instance.spec.js +++ b/test/specs/instance.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('instance', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/interceptors.spec.js b/test/specs/interceptors.spec.js index 07006be4c3..95bf5b8f21 100644 --- a/test/specs/interceptors.spec.js +++ b/test/specs/interceptors.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('interceptors', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/options.spec.js b/test/specs/options.spec.js index 87eb1c42a0..304cd9a559 100644 --- a/test/specs/options.spec.js +++ b/test/specs/options.spec.js @@ -1,3 +1,6 @@ +/* eslint-env mocha */ +/* global jasmine */ + // import AxiosHeaders from "../../lib/core/AxiosHeaders.js"; // import isAbsoluteURL from '../../lib/helpers/isAbsoluteURL.js'; diff --git a/test/specs/progress.spec.js b/test/specs/progress.spec.js index 674615ed57..d5b5e8657c 100644 --- a/test/specs/progress.spec.js +++ b/test/specs/progress.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('progress events', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/promise.spec.js b/test/specs/promise.spec.js index fe046a6986..57179cde26 100644 --- a/test/specs/promise.spec.js +++ b/test/specs/promise.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('promise', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/requests.spec.js b/test/specs/requests.spec.js index 97eeeae7fb..6480f60b34 100644 --- a/test/specs/requests.spec.js +++ b/test/specs/requests.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ describe('requests', function () { beforeEach(function () { jasmine.Ajax.install(); diff --git a/test/specs/transform.spec.js b/test/specs/transform.spec.js index 92a73624fd..f6fcaff27d 100644 --- a/test/specs/transform.spec.js +++ b/test/specs/transform.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ import AxiosError from '../../lib/core/AxiosError'; describe('transform', function () { diff --git a/test/specs/utils/endsWith.js b/test/specs/utils/endsWith.js index 3af65e1be2..edc41291b7 100644 --- a/test/specs/utils/endsWith.js +++ b/test/specs/utils/endsWith.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { kindOf } = utils; diff --git a/test/specs/utils/extend.spec.js b/test/specs/utils/extend.spec.js index 0f1d09fd9f..5e43a02ac4 100644 --- a/test/specs/utils/extend.spec.js +++ b/test/specs/utils/extend.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { extend } = utils; diff --git a/test/specs/utils/forEach.spec.js b/test/specs/utils/forEach.spec.js index dba64cf23c..9745c91787 100644 --- a/test/specs/utils/forEach.spec.js +++ b/test/specs/utils/forEach.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { forEach } = utils; diff --git a/test/specs/utils/isX.spec.js b/test/specs/utils/isX.spec.js index 65710c8d3a..0033a34d1b 100644 --- a/test/specs/utils/isX.spec.js +++ b/test/specs/utils/isX.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; describe('utils::isX', function () { diff --git a/test/specs/utils/kindOf.js b/test/specs/utils/kindOf.js index 3af65e1be2..edc41291b7 100644 --- a/test/specs/utils/kindOf.js +++ b/test/specs/utils/kindOf.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { kindOf } = utils; diff --git a/test/specs/utils/kindOfTest.js b/test/specs/utils/kindOfTest.js index da9a743ab9..7891ac47be 100644 --- a/test/specs/utils/kindOfTest.js +++ b/test/specs/utils/kindOfTest.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import { kindOfTest } from '../../../lib/utils'; describe('utils::kindOfTest', function () { diff --git a/test/specs/utils/merge.spec.js b/test/specs/utils/merge.spec.js index 053863c205..0cba2efd5a 100644 --- a/test/specs/utils/merge.spec.js +++ b/test/specs/utils/merge.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { merge } = utils; diff --git a/test/specs/utils/toArray.js b/test/specs/utils/toArray.js index 4601436b12..752917a402 100644 --- a/test/specs/utils/toArray.js +++ b/test/specs/utils/toArray.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { toArray } = utils; diff --git a/test/specs/utils/toFlatObject.js b/test/specs/utils/toFlatObject.js index 4dbbf16cca..b36e654dd0 100644 --- a/test/specs/utils/toFlatObject.js +++ b/test/specs/utils/toFlatObject.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; const { toFlatObject } = utils; diff --git a/test/specs/utils/trim.spec.js b/test/specs/utils/trim.spec.js index bbded1fbc6..90131a7dcd 100644 --- a/test/specs/utils/trim.spec.js +++ b/test/specs/utils/trim.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import utils from '../../../lib/utils'; describe('utils::trim', function () { diff --git a/test/specs/xsrf.spec.js b/test/specs/xsrf.spec.js index 83d5847290..91761b9159 100644 --- a/test/specs/xsrf.spec.js +++ b/test/specs/xsrf.spec.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +/* global jasmine */ import cookies from '../../lib/helpers/cookies'; describe('xsrf', function () { diff --git a/test/unit/adapters/adapters.js b/test/unit/adapters/adapters.js index 283830185e..c81cd3017c 100644 --- a/test/unit/adapters/adapters.js +++ b/test/unit/adapters/adapters.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import adapters from '../../../lib/adapters/adapters.js'; import assert from 'assert'; diff --git a/test/unit/adapters/fetch.js b/test/unit/adapters/fetch.js index 1d995e02e3..c18f17402d 100644 --- a/test/unit/adapters/fetch.js +++ b/test/unit/adapters/fetch.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import { startHTTPServer, diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 61fd883b0d..c3ac482edc 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import axios from '../../../index.js'; import http from 'http'; import https from 'https'; diff --git a/test/unit/core/Axios.js b/test/unit/core/Axios.js index 2645130359..a0647ad327 100644 --- a/test/unit/core/Axios.js +++ b/test/unit/core/Axios.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import Axios from '../../../lib/core/Axios.js'; import assert from 'assert'; diff --git a/test/unit/core/AxiosHeaders.js b/test/unit/core/AxiosHeaders.js index b5c1c955ad..36b2581312 100644 --- a/test/unit/core/AxiosHeaders.js +++ b/test/unit/core/AxiosHeaders.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import AxiosHeaders from '../../../lib/core/AxiosHeaders.js'; import assert from 'assert'; diff --git a/test/unit/core/prototypePollution.js b/test/unit/core/prototypePollution.js index eaf146b846..810fd0d8b4 100644 --- a/test/unit/core/prototypePollution.js +++ b/test/unit/core/prototypePollution.js @@ -1,3 +1,5 @@ +/* eslint-disable no-prototype-builtins */ +/* eslint-env mocha */ 'use strict'; import assert from 'assert'; diff --git a/test/unit/defaults/transformResponse.js b/test/unit/defaults/transformResponse.js index 6f6940c434..5418114f7f 100644 --- a/test/unit/defaults/transformResponse.js +++ b/test/unit/defaults/transformResponse.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import defaults from '../../../lib/defaults/index.js'; import transformData from '../../../lib/core/transformData.js'; import assert from 'assert'; diff --git a/test/unit/helpers/composeSignals.js b/test/unit/helpers/composeSignals.js index 997082a4a6..5fe2d28414 100644 --- a/test/unit/helpers/composeSignals.js +++ b/test/unit/helpers/composeSignals.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import composeSignals from '../../../lib/helpers/composeSignals.js'; diff --git a/test/unit/helpers/estimateDataURLDecodedBytes.spec.js b/test/unit/helpers/estimateDataURLDecodedBytes.spec.js index 8453c6ce2b..b2f7fb8559 100644 --- a/test/unit/helpers/estimateDataURLDecodedBytes.spec.js +++ b/test/unit/helpers/estimateDataURLDecodedBytes.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import estimateDataURLDecodedBytes from '../../../lib/helpers/estimateDataURLDecodedBytes.js'; diff --git a/test/unit/helpers/fromDataURI.js b/test/unit/helpers/fromDataURI.js index 434ab42631..7885d8b2b7 100644 --- a/test/unit/helpers/fromDataURI.js +++ b/test/unit/helpers/fromDataURI.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import fromDataURI from '../../../lib/helpers/fromDataURI.js'; diff --git a/test/unit/helpers/parseProtocol.js b/test/unit/helpers/parseProtocol.js index c3f8076b7f..3bcc1054a9 100644 --- a/test/unit/helpers/parseProtocol.js +++ b/test/unit/helpers/parseProtocol.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import utils from '../../../lib/utils.js'; import parseProtocol from '../../../lib/helpers/parseProtocol.js'; diff --git a/test/unit/helpers/toFormData.js b/test/unit/helpers/toFormData.js index 902d25bea3..c2b1584530 100644 --- a/test/unit/helpers/toFormData.js +++ b/test/unit/helpers/toFormData.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import toFormData from '../../../lib/helpers/toFormData.js'; import FormData from 'form-data'; diff --git a/test/unit/platform/index.js b/test/unit/platform/index.js index 27e388f69b..6a5d9c3c01 100644 --- a/test/unit/platform/index.js +++ b/test/unit/platform/index.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import platform from '../../../lib/platform/index.js'; import assert from 'assert'; diff --git a/test/unit/regression/SNYK-JS-AXIOS-1038255.js b/test/unit/regression/SNYK-JS-AXIOS-1038255.js index ffc4b115a9..c07a1e7ff6 100644 --- a/test/unit/regression/SNYK-JS-AXIOS-1038255.js +++ b/test/unit/regression/SNYK-JS-AXIOS-1038255.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ // https://snyk.io/vuln/SNYK-JS-AXIOS-1038255 // https://github.com/axios/axios/issues/3407 // https://github.com/axios/axios/issues/3369 diff --git a/test/unit/regression/SNYK-JS-AXIOS-7361793.js b/test/unit/regression/SNYK-JS-AXIOS-7361793.js index fc2135ff94..1af7a94e7a 100644 --- a/test/unit/regression/SNYK-JS-AXIOS-7361793.js +++ b/test/unit/regression/SNYK-JS-AXIOS-7361793.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ // https://security.snyk.io/vuln/SNYK-JS-AXIOS-7361793 // https://github.com/axios/axios/issues/6463 diff --git a/test/unit/regression/bugs.js b/test/unit/regression/bugs.js index dbdb77d3e3..4e709ab622 100644 --- a/test/unit/regression/bugs.js +++ b/test/unit/regression/bugs.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import http from 'http'; import axios from '../../../index.js'; diff --git a/test/unit/utils/utils.js b/test/unit/utils/utils.js index 48aa7ea763..f0a8980167 100644 --- a/test/unit/utils/utils.js +++ b/test/unit/utils/utils.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ import assert from 'assert'; import utils from '../../../lib/utils.js'; import FormData from 'form-data'; From 7426abd9a73e1871a9bd842303bd2832094552de Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Sun, 1 Mar 2026 13:46:50 +0200 Subject: [PATCH 02/37] feat: transitional move to vitests --- package-lock.json | 2568 +++++++++++++++++++++------ package.json | 12 +- tests/browser/smoke.browser.test.js | 10 + tests/setup/browser.setup.js | 5 + tests/unit/smoke.test.js | 7 + vitest.config.js | 29 + 6 files changed, 2051 insertions(+), 580 deletions(-) create mode 100644 tests/browser/smoke.browser.test.js create mode 100644 tests/setup/browser.setup.js create mode 100644 tests/unit/smoke.test.js create mode 100644 vitest.config.js diff --git a/package-lock.json b/package-lock.json index 4f96a745ec..2cfc1271a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,8 @@ "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-multi-entry": "^4.1.0", "@rollup/plugin-node-resolve": "^9.0.0", + "@vitest/browser": "^4.0.18", + "@vitest/browser-playwright": "^4.0.18", "abortcontroller-polyfill": "^1.7.8", "auto-changelog": "^2.5.0", "body-parser": "^1.20.4", @@ -60,6 +62,7 @@ "mocha": "^10.8.2", "multer": "^1.4.4", "pacote": "^20.0.0", + "playwright": "^1.58.2", "prettier": "^3.8.1", "pretty-bytes": "^6.1.1", "rollup": "^2.79.2", @@ -71,7 +74,8 @@ "stream-throttle": "^0.1.3", "string-replace-async": "^3.0.2", "tar-stream": "^3.1.7", - "typescript": "^4.9.5" + "typescript": "^4.9.5", + "vitest": "^4.0.18" } }, "node_modules/@babel/code-frame": { @@ -105,6 +109,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1923,231 +1928,673 @@ "node": ">=v18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.10.0" + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=18" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", @@ -2674,6 +3121,13 @@ "node": ">=14" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/plugin-alias": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", @@ -2790,88 +3244,438 @@ "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.0.8" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-multi-entry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.1.0.tgz", - "integrity": "sha512-nellK5pr50W0JA2+bDJbG8F79GBP802J40YRoC0wyfpTAeAn5mJ4eaFiB/MN+YoX9hgb/6RJoZl9leDjZnUFKw==", + "dependencies": { + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-multi-entry": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.1.0.tgz", + "integrity": "sha512-nellK5pr50W0JA2+bDJbG8F79GBP802J40YRoC0wyfpTAeAn5mJ4eaFiB/MN+YoX9hgb/6RJoZl9leDjZnUFKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-virtual": "^2.0.3", + "matched": "^5.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", + "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-virtual": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.1.0.tgz", + "integrity": "sha512-CPPAtlKT53HFqC8jFHb/V5WErpU8Hrq2TyCR0A7kPQMlF2wNUf0o1xuAc+Qxj8NCZM0Z3Yvl+FbUXfJjVWqDwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@rollup/plugin-virtual": "^2.0.3", - "matched": "^5.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", - "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-virtual": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.1.0.tgz", - "integrity": "sha512-CPPAtlKT53HFqC8jFHb/V5WErpU8Hrq2TyCR0A7kPQMlF2wNUf0o1xuAc+Qxj8NCZM0Z3Yvl+FbUXfJjVWqDwA==", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@sigstore/bundle": { "version": "3.1.0", @@ -3022,6 +3826,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -3072,6 +3883,17 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", @@ -3082,6 +3904,13 @@ "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", @@ -3096,98 +3925,305 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", + "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/puppeteer": { + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", + "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/puppeteer-core": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@types/puppeteer-core/-/puppeteer-core-5.4.0.tgz", + "integrity": "sha512-yqRPuv4EFcSkTyin6Yy17pN6Qz2vwVwTCJIDYMXbE3j8vTPhv0nCQlZOl5xfi0WHUkqvQsjAR8hAfjeMCoetwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/puppeteer": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/which": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", + "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitest/browser": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.0.18.tgz", + "integrity": "sha512-gVQqh7paBz3gC+ZdcCmNSWJMk70IUjDeVqi+5m5vYpEHsIwRgw3Y545jljtajhkekIpIp5Gg8oK7bctgY0E2Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/mocker": "4.0.18", + "@vitest/utils": "4.0.18", + "magic-string": "^0.30.21", + "pixelmatch": "7.1.0", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.0.3", + "ws": "^8.18.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.0.18.tgz", + "integrity": "sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/browser": "4.0.18", + "@vitest/mocker": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "4.0.18" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": false + } + } + }, + "node_modules/@vitest/browser/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@types/estree": "^1.0.0" } }, - "node_modules/@types/node": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", - "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/@types/puppeteer": { - "version": "5.4.7", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", - "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@types/puppeteer-core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@types/puppeteer-core/-/puppeteer-core-5.4.0.tgz", - "integrity": "sha512-yqRPuv4EFcSkTyin6Yy17pN6Qz2vwVwTCJIDYMXbE3j8vTPhv0nCQlZOl5xfi0WHUkqvQsjAR8hAfjeMCoetwg==", + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, "license": "MIT", "dependencies": { - "@types/puppeteer": "*" + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/@types/which": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.2.tgz", - "integrity": "sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==", + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "@types/node": "*" + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, "node_modules/@wdio/config": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.12.1.tgz", @@ -3278,7 +4314,6 @@ "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", @@ -3290,24 +4325,21 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-code-frame": { "version": "1.9.0", @@ -3315,7 +4347,6 @@ "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/wast-printer": "1.9.0" } @@ -3325,8 +4356,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/@webassemblyjs/helper-module-context": { "version": "1.9.0", @@ -3334,7 +4364,6 @@ "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0" } @@ -3344,8 +4373,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.9.0", @@ -3353,7 +4381,6 @@ "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -3367,7 +4394,6 @@ "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -3378,7 +4404,6 @@ "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -3388,8 +4413,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.9.0", @@ -3397,7 +4421,6 @@ "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -3415,7 +4438,6 @@ "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", @@ -3430,7 +4452,6 @@ "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", @@ -3444,7 +4465,6 @@ "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-api-error": "1.9.0", @@ -3460,7 +4480,6 @@ "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/floating-point-hex-parser": "1.9.0", @@ -3476,7 +4495,6 @@ "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/wast-parser": "1.9.0", @@ -3488,16 +4506,14 @@ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true, - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/abbrev": { "version": "3.0.1", @@ -3536,6 +4552,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3569,6 +4586,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3586,7 +4604,6 @@ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "ajv": ">=5.0.0" } @@ -3718,8 +4735,7 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/arch": { "version": "2.2.0", @@ -4069,7 +5085,6 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -4081,8 +5096,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/assert": { "version": "1.5.1", @@ -4090,7 +5104,6 @@ "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "object.assign": "^4.1.4", "util": "^0.10.4" @@ -4111,8 +5124,7 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/assert/node_modules/util": { "version": "0.10.4", @@ -4120,11 +5132,20 @@ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "2.0.3" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -4944,16 +5965,14 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/bn.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/body-parser": { "version": "1.20.4", @@ -5042,8 +6061,7 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -5058,7 +6076,6 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -5074,7 +6091,6 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -5087,7 +6103,6 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -5101,7 +6116,6 @@ "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^5.2.1", "randombytes": "^2.1.0", @@ -5117,7 +6131,6 @@ "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "bn.js": "^5.2.2", "browserify-rsa": "^4.1.1", @@ -5138,8 +6151,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "2.3.8", @@ -5147,7 +6159,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5163,8 +6174,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/string_decoder": { "version": "1.1.1", @@ -5172,7 +6182,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -5182,8 +6191,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-zlib": { "version": "0.2.0", @@ -5191,7 +6199,6 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pako": "~1.0.5" } @@ -5216,6 +6223,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5315,8 +6323,7 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/builtin-modules": { "version": "3.3.0", @@ -5336,8 +6343,7 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/builtins": { "version": "2.0.1", @@ -5839,6 +6845,16 @@ "node": ">=4" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", @@ -5961,7 +6977,6 @@ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.0" } @@ -5972,7 +6987,6 @@ "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", @@ -6511,8 +7525,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/constant-case": { "version": "3.0.4", @@ -6531,8 +7544,7 @@ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -6630,7 +7642,6 @@ "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -6647,7 +7658,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -6730,6 +7740,7 @@ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -6835,7 +7846,6 @@ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" @@ -6846,8 +7856,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", @@ -6855,7 +7864,6 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -6870,7 +7878,6 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -6920,7 +7927,6 @@ "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserify-cipher": "^1.0.1", "browserify-sign": "^4.2.3", @@ -6967,8 +7973,7 @@ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/d": { "version": "1.0.2", @@ -7472,7 +8477,6 @@ "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -7638,7 +8642,6 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -7650,8 +8653,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/doctrine": { "version": "3.0.0", @@ -7685,7 +8687,6 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.4", "npm": ">=1.2" @@ -8076,7 +9077,6 @@ "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -8092,8 +9092,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -8122,31 +9121,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -8193,7 +9167,6 @@ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "dev": true, - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", @@ -8208,8 +9181,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/enhanced-resolve/node_modules/memory-fs": { "version": "0.5.0", @@ -8217,7 +9189,6 @@ "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -8232,7 +9203,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8248,8 +9218,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/enhanced-resolve/node_modules/string_decoder": { "version": "1.1.1", @@ -8257,7 +9226,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -8314,7 +9282,6 @@ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -8350,6 +9317,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -8447,6 +9421,48 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -8484,6 +9500,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -8852,7 +9869,6 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -8873,7 +9889,6 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -9070,6 +10085,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -9376,8 +10401,7 @@ "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", "deprecated": "This module is no longer supported.", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/figures": { "version": "1.7.0", @@ -9517,7 +10541,6 @@ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "commondir": "^1.0.1", "make-dir": "^2.0.0", @@ -9533,7 +10556,6 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^3.0.0" }, @@ -9547,7 +10569,6 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -9562,7 +10583,6 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -9577,7 +10597,6 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -9594,7 +10613,6 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.0.0" }, @@ -9608,7 +10626,6 @@ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -9619,7 +10636,6 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -9630,7 +10646,6 @@ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "find-up": "^3.0.0" }, @@ -9644,7 +10659,6 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver" } @@ -10073,7 +11087,6 @@ "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -10086,8 +11099,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fs-write-stream-atomic/node_modules/readable-stream": { "version": "2.3.8", @@ -10095,7 +11107,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -10111,8 +11122,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fs-write-stream-atomic/node_modules/string_decoder": { "version": "1.1.1", @@ -10120,7 +11130,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -11178,7 +12187,6 @@ "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1" @@ -11237,7 +12245,6 @@ "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -11356,8 +12363,7 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/https-proxy-agent": { "version": "7.0.6", @@ -11438,8 +12444,7 @@ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ignore": { "version": "5.3.2", @@ -11553,8 +12558,7 @@ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/inflight": { "version": "1.0.6", @@ -12276,7 +13280,8 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", "integrity": "sha512-ra97U4qu3OCcIxvN6eg3kyy8bLrID/TgxafSGMMICg3SFx5C/sUfDPpiOh7yoIsHdtjrOVdtT9rieYhqOsh9Ww==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/jest-worker": { "version": "26.6.2", @@ -12467,6 +13472,7 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -13608,7 +14614,6 @@ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4.3.0 <5.0.0 || >=5.10" } @@ -14375,7 +15380,6 @@ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -14418,7 +15422,6 @@ "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -14429,8 +15432,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/memory-fs/node_modules/readable-stream": { "version": "2.3.8", @@ -14438,7 +15440,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14454,8 +15455,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/memory-fs/node_modules/string_decoder": { "version": "1.1.1", @@ -14463,7 +15463,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -14589,7 +15588,6 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -14603,8 +15601,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/mime": { "version": "2.6.0", @@ -14688,8 +15685,7 @@ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/minimatch": { "version": "9.0.9", @@ -14876,7 +15872,6 @@ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -14902,7 +15897,6 @@ "node >= 0.8" ], "license": "MIT", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -14915,8 +15909,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/mississippi/node_modules/pump": { "version": "3.0.3", @@ -14924,7 +15917,6 @@ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -14936,7 +15928,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14952,8 +15943,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/mississippi/node_modules/string_decoder": { "version": "1.1.1", @@ -14961,7 +15951,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -15438,7 +16427,6 @@ "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -15455,7 +16443,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -15463,6 +16450,16 @@ "rimraf": "bin.js" } }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -15565,6 +16562,25 @@ "license": "MIT", "optional": true }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -15898,7 +16914,6 @@ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", @@ -15931,7 +16946,6 @@ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -15943,8 +16957,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-libs-browser/node_modules/readable-stream": { "version": "2.3.8", @@ -15952,7 +16965,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15968,8 +16980,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-libs-browser/node_modules/string_decoder": { "version": "1.1.1", @@ -15977,7 +16988,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -16493,6 +17503,17 @@ "node": ">=0.10.0" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -16605,8 +17626,7 @@ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/os-filter-obj": { "version": "2.0.0", @@ -16829,8 +17849,7 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true, - "license": "(MIT AND Zlib)", - "peer": true + "license": "(MIT AND Zlib)" }, "node_modules/parallel-transform": { "version": "1.2.0", @@ -16838,7 +17857,6 @@ "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cyclist": "^1.0.1", "inherits": "^2.0.3", @@ -16850,8 +17868,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/parallel-transform/node_modules/readable-stream": { "version": "2.3.8", @@ -16859,7 +17876,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16875,8 +17891,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/parallel-transform/node_modules/string_decoder": { "version": "1.1.1", @@ -16884,7 +17899,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -16919,7 +17933,6 @@ "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", @@ -17041,8 +18054,7 @@ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/path-case": { "version": "3.0.4", @@ -17156,13 +18168,19 @@ "node": ">=4" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pbkdf2": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -17255,6 +18273,19 @@ "node": ">=0.10.0" } }, + "node_modules/pixelmatch": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", + "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", + "dev": true, + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -17334,6 +18365,63 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -17354,6 +18442,35 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17429,7 +18546,6 @@ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6.0" } @@ -17456,8 +18572,7 @@ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/promise-retry": { "version": "2.0.1", @@ -17505,8 +18620,7 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/pseudomap": { "version": "1.0.2", @@ -17544,7 +18658,6 @@ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -17559,8 +18672,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/pump": { "version": "2.0.1", @@ -17708,7 +18820,6 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", "dev": true, - "peer": true, "engines": { "node": ">=0.4.x" } @@ -17763,7 +18874,6 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -18585,7 +19695,6 @@ "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash-base": "^3.1.2", "inherits": "^2.0.4" @@ -18600,7 +19709,6 @@ "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.4", "readable-stream": "^2.3.8", @@ -18616,8 +19724,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ripemd160/node_modules/readable-stream": { "version": "2.3.8", @@ -18625,7 +19732,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -18641,8 +19747,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ripemd160/node_modules/string_decoder": { "version": "1.1.1", @@ -18650,7 +19755,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -18660,8 +19764,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/roarr": { "version": "2.15.4", @@ -18687,6 +19790,7 @@ "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -18879,7 +19983,6 @@ "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "aproba": "^1.1.1" } @@ -19375,8 +20478,7 @@ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -19391,7 +20493,6 @@ "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "dev": true, "license": "(MIT AND BSD-3-Clause)", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", @@ -19506,6 +20607,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -19545,6 +20653,7 @@ "dev": true, "hasInstallScript": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@sinonjs/formatio": "^2.0.0", "diff": "^3.1.0", @@ -19588,6 +20697,21 @@ "node": ">=4" } }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -19886,8 +21010,7 @@ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", @@ -19899,6 +21022,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -20093,6 +21226,13 @@ "node": "*" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -20144,13 +21284,19 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" @@ -20161,8 +21307,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stream-browserify/node_modules/readable-stream": { "version": "2.3.8", @@ -20170,7 +21315,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -20185,9 +21329,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true + "dev": true, + "license": "MIT" }, "node_modules/stream-browserify/node_modules/string_decoder": { "version": "1.1.1", @@ -20195,7 +21338,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -20206,7 +21348,6 @@ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -20225,7 +21366,6 @@ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", @@ -20239,8 +21379,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stream-http/node_modules/readable-stream": { "version": "2.3.8", @@ -20248,7 +21387,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -20264,8 +21402,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stream-http/node_modules/string_decoder": { "version": "1.1.1", @@ -20273,7 +21410,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -20633,7 +21769,6 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -20825,7 +21960,6 @@ "integrity": "sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", @@ -20868,7 +22002,6 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -20879,7 +22012,6 @@ "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "bluebird": "^3.5.5", "chownr": "^1.1.1", @@ -20903,16 +22035,14 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/terser-webpack-plugin/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/is-wsl": { "version": "1.1.0", @@ -20920,7 +22050,6 @@ "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -20930,8 +22059,7 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/rimraf": { "version": "2.7.1", @@ -20940,7 +22068,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -20954,7 +22081,6 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -20970,7 +22096,6 @@ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "randombytes": "^2.1.0" } @@ -20981,7 +22106,6 @@ "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "figgy-pudding": "^3.5.1" } @@ -20992,7 +22116,6 @@ "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -21011,7 +22134,6 @@ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -21022,7 +22144,6 @@ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -21032,8 +22153,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", @@ -21190,7 +22310,6 @@ "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "setimmediate": "^1.0.4" }, @@ -21212,6 +22331,13 @@ "node": ">=0.12" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", @@ -21263,6 +22389,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -21270,6 +22397,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmp": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", @@ -21299,8 +22436,7 @@ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/to-buffer": { "version": "1.2.2", @@ -21446,6 +22582,16 @@ "node": ">=0.6" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -21522,8 +22668,7 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tuf-js": { "version": "3.1.0", @@ -21655,6 +22800,7 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -22043,7 +23189,6 @@ "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "punycode": "^1.4.1", "qs": "^6.12.3" @@ -22091,7 +23236,6 @@ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "2.0.3" } @@ -22108,8 +23252,7 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/utils-merge": { "version": "1.0.1", @@ -22332,13 +23475,287 @@ "node": ">=0.10.0" } }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "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 + } + } + }, + "node_modules/vite/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/void-elements": { "version": "2.0.1", @@ -22356,7 +23773,6 @@ "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" @@ -22373,7 +23789,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "chokidar": "^2.1.8" } @@ -22385,7 +23800,6 @@ "dev": true, "license": "ISC", "optional": true, - "peer": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -22401,7 +23815,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=8" }, @@ -22416,7 +23829,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -22431,7 +23843,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -22458,7 +23869,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -22477,7 +23887,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -22489,7 +23898,6 @@ "dev": true, "license": "ISC", "optional": true, - "peer": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -22504,7 +23912,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -22519,7 +23926,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=0.12.0" } @@ -22531,7 +23937,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -22546,7 +23951,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "is-number": "^7.0.0" }, @@ -22686,7 +24090,6 @@ "integrity": "sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", @@ -22737,7 +24140,6 @@ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -22749,7 +24151,6 @@ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -22781,7 +24182,6 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -22792,7 +24192,6 @@ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -22807,7 +24206,6 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } @@ -22817,8 +24215,7 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { "version": "1.0.0", @@ -22826,7 +24223,6 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", @@ -22885,6 +24281,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -22908,7 +24321,6 @@ "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "errno": "~0.1.7" } diff --git a/package.json b/package.json index 7eabb0c64f..63f7fa40ca 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,10 @@ "test:node": "npm run test:mocha", "test:node:coverage": "c8 npm run test:mocha", "test:browser": "npm run test:karma", + "test:vitest": "vitest run", + "test:vitest:unit": "vitest run --project unit", + "test:vitest:browser": "vitest run --project browser", + "test:vitest:watch": "vitest", "test:package": "npm run test:eslint && npm run test:exports", "test:eslint": "node bin/ssl_hotfix.js eslint lib/**/*.js", "test:mocha": "node bin/ssl_hotfix.js mocha test/unit/**/*.js --timeout 30000 --exit", @@ -100,6 +104,8 @@ "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-multi-entry": "^4.1.0", "@rollup/plugin-node-resolve": "^9.0.0", + "@vitest/browser": "^4.0.18", + "@vitest/browser-playwright": "^4.0.18", "abortcontroller-polyfill": "^1.7.8", "auto-changelog": "^2.5.0", "body-parser": "^1.20.4", @@ -136,6 +142,7 @@ "mocha": "^10.8.2", "multer": "^1.4.4", "pacote": "^20.0.0", + "playwright": "^1.58.2", "prettier": "^3.8.1", "pretty-bytes": "^6.1.1", "rollup": "^2.79.2", @@ -147,7 +154,8 @@ "stream-throttle": "^0.1.3", "string-replace-async": "^3.0.2", "tar-stream": "^3.1.7", - "typescript": "^4.9.5" + "typescript": "^4.9.5", + "vitest": "^4.0.18" }, "browser": { "./dist/node/axios.cjs": "./dist/browser/axios.cjs", @@ -223,4 +231,4 @@ ], "report-dir": "./coverage" } -} \ No newline at end of file +} diff --git a/tests/browser/smoke.browser.test.js b/tests/browser/smoke.browser.test.js new file mode 100644 index 0000000000..d046e787ad --- /dev/null +++ b/tests/browser/smoke.browser.test.js @@ -0,0 +1,10 @@ +import { expect, test } from 'vitest'; + +test('runs in browser environment', () => { + document.body.innerHTML = '
vitest browser smoke
'; + + const el = document.querySelector('[data-testid="smoke"]'); + + expect(el?.textContent).toBe('vitest browser smoke'); + expect(globalThis.window).toBeDefined(); +}); diff --git a/tests/setup/browser.setup.js b/tests/setup/browser.setup.js new file mode 100644 index 0000000000..9a0dea9ba8 --- /dev/null +++ b/tests/setup/browser.setup.js @@ -0,0 +1,5 @@ +import { afterEach } from 'vitest'; + +afterEach(() => { + document.body.innerHTML = ''; +}); diff --git a/tests/unit/smoke.test.js b/tests/unit/smoke.test.js new file mode 100644 index 0000000000..184998afe8 --- /dev/null +++ b/tests/unit/smoke.test.js @@ -0,0 +1,7 @@ +import { describe, expect, test } from 'vitest'; + +describe('vitest unit smoke', () => { + test('runs in node environment', () => { + expect(typeof process.versions.node).toBe('string'); + }); +}); diff --git a/vitest.config.js b/vitest.config.js new file mode 100644 index 0000000000..a03cf54caa --- /dev/null +++ b/vitest.config.js @@ -0,0 +1,29 @@ +import { defineConfig } from 'vitest/config'; +import { playwright } from '@vitest/browser-playwright'; + +export default defineConfig({ + test: { + testTimeout: 10000, + projects: [ + { + test: { + name: 'unit', + environment: 'node', + include: ['tests/unit/**/*.test.js'], + }, + }, + { + test: { + name: 'browser', + include: ['tests/browser/**/*.browser.test.js'], + browser: { + enabled: true, + provider: playwright(), + instances: [{ browser: 'chromium' }], + }, + setupFiles: ['tests/setup/browser.setup.js'], + }, + }, + ], + }, +}); From 7976db144d3cd93a6a00da943ec7886ebc1f4f47 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Sun, 1 Mar 2026 16:55:46 +0200 Subject: [PATCH 03/37] feat: moving unit tests in progress --- tests/unit/composeSignals.test.js | 40 +++ .../unit/estimateDataURLDecodedBytes.test.js | 31 +++ tests/unit/fromDataURI.test.js | 13 + tests/unit/parseProtocol.test.js | 28 ++ tests/unit/platform.test.js | 23 ++ tests/unit/regression.test.js | 263 ++++++++++++++++++ tests/unit/smoke.test.js | 7 - tests/unit/toFormData.test.js | 140 ++++++++++ tests/unit/transformResponse.test.js | 70 +++++ tests/unit/utils.test.js | 172 ++++++++++++ 10 files changed, 780 insertions(+), 7 deletions(-) create mode 100644 tests/unit/composeSignals.test.js create mode 100644 tests/unit/estimateDataURLDecodedBytes.test.js create mode 100644 tests/unit/fromDataURI.test.js create mode 100644 tests/unit/parseProtocol.test.js create mode 100644 tests/unit/platform.test.js create mode 100644 tests/unit/regression.test.js delete mode 100644 tests/unit/smoke.test.js create mode 100644 tests/unit/toFormData.test.js create mode 100644 tests/unit/transformResponse.test.js create mode 100644 tests/unit/utils.test.js diff --git a/tests/unit/composeSignals.test.js b/tests/unit/composeSignals.test.js new file mode 100644 index 0000000000..e17ffb6751 --- /dev/null +++ b/tests/unit/composeSignals.test.js @@ -0,0 +1,40 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import composeSignals from '../../lib/helpers/composeSignals.js'; + +describe('helpers::composeSignals', function () { + const runIfAbortController = typeof AbortController === 'function' ? it : it.skip; + + runIfAbortController('should abort when any of the signals abort', function () { + let called; + + const controllerA = new AbortController(); + const controllerB = new AbortController(); + + const signal = composeSignals([controllerA.signal, controllerB.signal]); + + signal.addEventListener('abort', function () { + called = true; + }); + + controllerA.abort(new Error('test')); + + assert.ok(called); + }); + + runIfAbortController('should abort on timeout', async function () { + const signal = composeSignals([], 100); + + await new Promise(function (resolve) { + signal.addEventListener('abort', resolve); + }); + + assert.match(String(signal.reason), /timeout of 100ms exceeded/); + }); + + it('should return undefined if signals and timeout are not provided', function () { + const signal = composeSignals([]); + + assert.strictEqual(signal, undefined); + }); +}); diff --git a/tests/unit/estimateDataURLDecodedBytes.test.js b/tests/unit/estimateDataURLDecodedBytes.test.js new file mode 100644 index 0000000000..ddff64e8a2 --- /dev/null +++ b/tests/unit/estimateDataURLDecodedBytes.test.js @@ -0,0 +1,31 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import estimateDataURLDecodedBytes from '../../lib/helpers/estimateDataURLDecodedBytes.js'; + +describe('estimateDataURLDecodedBytes', function () { + it('should return 0 for non-data URLs', function () { + assert.strictEqual(estimateDataURLDecodedBytes('http://example.com'), 0); + }); + + it('should calculate length for simple non-base64 data URL', function () { + const url = 'data:,Hello'; + assert.strictEqual(estimateDataURLDecodedBytes(url), Buffer.byteLength('Hello', 'utf8')); + }); + + it('should calculate decoded length for base64 data URL', function () { + const str = 'Hello'; + const b64 = Buffer.from(str, 'utf8').toString('base64'); + const url = `data:text/plain;base64,${b64}`; + assert.strictEqual(estimateDataURLDecodedBytes(url), str.length); + }); + + it('should handle base64 with = padding', function () { + const url = 'data:text/plain;base64,TQ=='; + assert.strictEqual(estimateDataURLDecodedBytes(url), 1); + }); + + it('should handle base64 with %3D padding', function () { + const url = 'data:text/plain;base64,TQ%3D%3D'; + assert.strictEqual(estimateDataURLDecodedBytes(url), 1); + }); +}); diff --git a/tests/unit/fromDataURI.test.js b/tests/unit/fromDataURI.test.js new file mode 100644 index 0000000000..f034bd7db8 --- /dev/null +++ b/tests/unit/fromDataURI.test.js @@ -0,0 +1,13 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import fromDataURI from '../../lib/helpers/fromDataURI.js'; + +describe('helpers::fromDataURI', function () { + it('should return buffer from data uri', function () { + const buffer = Buffer.from('123'); + + const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); + + assert.deepStrictEqual(fromDataURI(dataURI, false), buffer); + }); +}); diff --git a/tests/unit/parseProtocol.test.js b/tests/unit/parseProtocol.test.js new file mode 100644 index 0000000000..87813654bb --- /dev/null +++ b/tests/unit/parseProtocol.test.js @@ -0,0 +1,28 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import utils from '../../lib/utils.js'; +import parseProtocol from '../../lib/helpers/parseProtocol.js'; + +describe('helpers::parseProtocol', function () { + it('should parse protocol part if it exists', function () { + utils.forEach( + { + 'http://username:password@example.com/': 'http', + 'ftp:google.com': 'ftp', + 'sms:+15105550101?body=hello%20there': 'sms', + 'tel:0123456789': 'tel', + '//google.com': '', + 'google.com': '', + 'admin://etc/default/grub': 'admin', + 'stratum+tcp://server:port': 'stratum+tcp', + '/api/resource:customVerb': '', + 'https://stackoverflow.com/questions/': 'https', + 'mailto:jsmith@example.com': 'mailto', + 'chrome-extension://1234/.html': 'chrome-extension', + }, + function (expectedProtocol, url) { + assert.strictEqual(parseProtocol(url), expectedProtocol); + } + ); + }); +}); diff --git a/tests/unit/platform.test.js b/tests/unit/platform.test.js new file mode 100644 index 0000000000..d60aed3be1 --- /dev/null +++ b/tests/unit/platform.test.js @@ -0,0 +1,23 @@ +import { describe, it } from 'vitest'; +import platform from '../../lib/platform/index.js'; +import assert from 'assert'; + +describe('generateString', function () { + it('should generate a string of the specified length using the default alphabet', function () { + const size = 10; + const str = platform.generateString(size); + + assert.strictEqual(str.length, size); + }); + + it('should generate a string using only characters from the default alphabet', function () { + const size = 10; + const alphabet = platform.ALPHABET.ALPHA_DIGIT; + + const str = platform.generateString(size, alphabet); + + for (let char of str) { + assert.ok(alphabet.includes(char), `Character ${char} is not in the alphabet`); + } + }); +}); diff --git a/tests/unit/regression.test.js b/tests/unit/regression.test.js new file mode 100644 index 0000000000..731127cd34 --- /dev/null +++ b/tests/unit/regression.test.js @@ -0,0 +1,263 @@ +/** + * Combined regression tests (issues 4999, 5028, 7364 + SSRF SNYK-1038255, SNYK-7361793). + */ +import { describe, it, beforeEach, afterEach, vi } from 'vitest'; +import assert from 'assert'; +import http from 'http'; +import axios from '../../index.js'; +import platform from '../../lib/platform/index.js'; + +describe('regression', function () { + describe('issues', function () { + describe('4999', function () { + // Depends on network: https://postman-echo.com + it('should not fail with query parsing', async function () { + const { data } = await axios.get('https://postman-echo.com/get?foo1=bar1&foo2=bar2'); + + assert.strictEqual(data.args.foo1, 'bar1'); + assert.strictEqual(data.args.foo2, 'bar2'); + }); + }); + + describe('5028', function () { + it('should handle set-cookie headers as an array', async function () { + const cookie1 = + 'something=else; path=/; expires=Wed, 12 Apr 2023 12:03:42 GMT; samesite=lax; secure; httponly'; + const cookie2 = + 'something-ssr.sig=n4MlwVAaxQAxhbdJO5XbUpDw-lA; path=/; expires=Wed, 12 Apr 2023 12:03:42 GMT; samesite=lax; secure; httponly'; + + const server = http + .createServer((req, res) => { + res.setHeader('Set-Cookie', [cookie1, cookie2]); + res.writeHead(200); + res.write('Hi there'); + res.end(); + }) + .listen(0); + + const request = axios.create(); + + request.interceptors.response.use((res) => { + assert.deepStrictEqual(res.headers['set-cookie'], [cookie1, cookie2]); + }); + + try { + await request({ url: `http://localhost:${server.address().port}` }); + } finally { + server.close(); + } + }); + }); + + describe('7364', function () { + it('fetch: should have status code in axios error', async function () { + const isFetchSupported = typeof fetch === 'function'; + if (!isFetchSupported) { + vi.skip(); + } + + const server = http + .createServer((req, res) => { + res.statusCode = 400; + res.end(); + }) + .listen(0); + + const instance = axios.create({ + baseURL: `http://localhost:${server.address().port}`, + adapter: 'fetch', + }); + + try { + await instance.get('/status/400'); + } catch (error) { + assert.equal(error.name, 'AxiosError'); + assert.equal(error.isAxiosError, true); + assert.equal(error.status, 400); + } finally { + server.close(); + } + }); + + it('http: should have status code in axios error', async function () { + const server = http + .createServer((req, res) => { + res.statusCode = 400; + res.end(); + }) + .listen(0); + + const instance = axios.create({ + baseURL: `http://localhost:${server.address().port}`, + adapter: 'http', + }); + + try { + await instance.get('/status/400'); + } catch (error) { + assert.equal(error.name, 'AxiosError'); + assert.equal(error.isAxiosError, true); + assert.equal(error.status, 400); + } finally { + server.close(); + } + }); + }); + }); + + // https://snyk.io/vuln/SNYK-JS-AXIOS-1038255 + // https://github.com/axios/axios/issues/3407 + // https://github.com/axios/axios/issues/3369 + describe('SSRF SNYK-JS-AXIOS-1038255', () => { + let fail = false; + let proxy; + let server; + let location; + let evilPort; + let proxyPort; + + beforeEach(() => { + fail = false; + server = http + .createServer(function (req, res) { + fail = true; + res.end('rm -rf /'); + }) + .listen(0); + evilPort = server.address().port; + + proxy = http + .createServer(function (req, res) { + if ( + new URL(req.url, 'http://' + req.headers.host).toString() === + 'http://localhost:' + evilPort + '/' + ) { + return res.end( + JSON.stringify({ + msg: 'Protected', + headers: req.headers, + }) + ); + } + res.writeHead(302, { location }); + res.end(); + }) + .listen(0); + proxyPort = proxy.address().port; + location = 'http://localhost:' + evilPort; + }); + + afterEach(() => { + server.close(); + proxy.close(); + }); + + it('obeys proxy settings when following redirects', async () => { + const response = await axios({ + method: 'get', + url: 'http://www.google.com/', + proxy: { + host: 'localhost', + port: proxyPort, + auth: { + username: 'sam', + password: 'password', + }, + }, + }); + + assert.strictEqual(fail, false); + assert.strictEqual(response.data.msg, 'Protected'); + assert.strictEqual(response.data.headers.host, 'localhost:' + evilPort); + assert.strictEqual( + response.data.headers['proxy-authorization'], + 'Basic ' + Buffer.from('sam:password').toString('base64') + ); + + return response; + }); + }); + + // https://security.snyk.io/vuln/SNYK-JS-AXIOS-7361793 + // https://github.com/axios/axios/issues/6463 + describe('SSRF SNYK-JS-AXIOS-7361793', () => { + let goodServer; + let badServer; + let goodPort; + let badPort; + + beforeEach(() => { + goodServer = http + .createServer(function (req, res) { + res.write('good'); + res.end(); + }) + .listen(0); + goodPort = goodServer.address().port; + + badServer = http + .createServer(function (req, res) { + res.write('bad'); + res.end(); + }) + .listen(0); + badPort = badServer.address().port; + }); + + afterEach(() => { + goodServer.close(); + badServer.close(); + }); + + it('should not fetch in server-side mode', async () => { + const ssrfAxios = axios.create({ + baseURL: 'http://localhost:' + String(goodPort), + }); + + const userId = '/localhost:' + String(badPort); + + try { + await ssrfAxios.get(`/${userId}`); + } catch (error) { + assert.ok(error.message.startsWith('Invalid URL')); + return; + } + assert.fail('Expected an error to be thrown'); + }); + + describe('client-side mode', () => { + let savedHasBrowserEnv; + let savedOrigin; + + beforeEach(() => { + assert.ok(platform.hasBrowserEnv !== undefined); + savedHasBrowserEnv = platform.hasBrowserEnv; + savedOrigin = platform.origin; + platform.hasBrowserEnv = true; + platform.origin = 'http://localhost:' + String(goodPort); + }); + + afterEach(() => { + platform.hasBrowserEnv = savedHasBrowserEnv; + platform.origin = savedOrigin; + }); + + it('resolves URL relative to origin and returns bad server body', async () => { + const ssrfAxios = axios.create({ + baseURL: 'http://localhost:' + String(goodPort), + }); + + const userId = '/localhost:' + String(badPort); + + const response = await ssrfAxios.get(`/${userId}`); + assert.strictEqual(response.data, 'bad'); + assert.strictEqual(response.config.baseURL, 'http://localhost:' + String(goodPort)); + assert.strictEqual(response.config.url, '//localhost:' + String(badPort)); + assert.strictEqual( + response.request.res.responseUrl, + 'http://localhost:' + String(badPort) + '/' + ); + }); + }); + }); +}); diff --git a/tests/unit/smoke.test.js b/tests/unit/smoke.test.js deleted file mode 100644 index 184998afe8..0000000000 --- a/tests/unit/smoke.test.js +++ /dev/null @@ -1,7 +0,0 @@ -import { describe, expect, test } from 'vitest'; - -describe('vitest unit smoke', () => { - test('runs in node environment', () => { - expect(typeof process.versions.node).toBe('string'); - }); -}); diff --git a/tests/unit/toFormData.test.js b/tests/unit/toFormData.test.js new file mode 100644 index 0000000000..d3a3629039 --- /dev/null +++ b/tests/unit/toFormData.test.js @@ -0,0 +1,140 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import FormData from 'form-data'; +import toFormData from '../../lib/helpers/toFormData.js'; + +describe('helpers::toFormData', function () { + function createRNFormDataSpy() { + const calls = []; + return { + calls, + append(key, value) { + calls.push([key, value]); + }, + getParts() { + return []; + }, + }; + } + + it('should convert a flat object to FormData', function () { + const data = { + foo: 'bar', + baz: 123, + }; + + const formData = toFormData(data, new FormData()); + + assert.ok(formData instanceof FormData); + assert.ok(formData._streams.length > 0); + }); + + it('should convert a nested object to FormData', function () { + const data = { + foo: { + bar: 'baz', + }, + }; + + const formData = toFormData(data, new FormData()); + + assert.ok(formData instanceof FormData); + }); + + it('should throw Error on circular reference', function () { + const data = { + foo: 'bar', + }; + data.self = data; + + try { + toFormData(data, new FormData()); + assert.fail('Should have thrown an error'); + } catch (err) { + assert.strictEqual(err.message, 'Circular reference detected in self'); + } + }); + + it('should handle arrays', function () { + const data = { + arr: [1, 2, 3], + }; + + const formData = toFormData(data, new FormData()); + assert.ok(formData instanceof FormData); + }); + + it('should append root-level React Native blob without recursion', function () { + const formData = createRNFormDataSpy(); + + const blob = { + uri: 'file://test.png', + type: 'image/png', + name: 'test.png', + }; + + toFormData({ file: blob }, formData); + + assert.strictEqual(formData.calls.length, 1); + assert.strictEqual(formData.calls[0][0], 'file'); + assert.strictEqual(formData.calls[0][1], blob); + }); + + it('should append nested React Native blob without recursion', function () { + const formData = createRNFormDataSpy(); + + const blob = { + uri: 'file://nested.png', + type: 'image/png', + name: 'nested.png', + }; + + toFormData({ nested: { file: blob } }, formData); + + assert.strictEqual(formData.calls.length, 1); + assert.strictEqual(formData.calls[0][0], 'nested[file]'); + assert.strictEqual(formData.calls[0][1], blob); + }); + + it('should append deeply nested React Native blob without recursion', function () { + const formData = createRNFormDataSpy(); + + const blob = { + uri: 'file://deep.png', + name: 'deep.png', + }; + + toFormData({ a: { b: { c: blob } } }, formData); + + assert.strictEqual(formData.calls.length, 1); + assert.strictEqual(formData.calls[0][0], 'a[b][c]'); + assert.strictEqual(formData.calls[0][1], blob); + }); + + it('should NOT recurse into React Native blob properties', function () { + const formData = createRNFormDataSpy(); + + const blob = { + uri: 'file://nope.png', + type: 'image/png', + name: 'nope.png', + }; + + toFormData({ file: blob }, formData); + + const keys = formData.calls.map(function (call) { + return call[0]; + }); + + assert.deepStrictEqual(keys, ['file']); + assert.ok(!keys.some(function (key) { + return key.includes('uri'); + })); + assert.ok(!keys.some(function (key) { + return key.includes('type'); + })); + assert.ok(!keys.some(function (key) { + return key.includes('name'); + })); + }); +}); diff --git a/tests/unit/transformResponse.test.js b/tests/unit/transformResponse.test.js new file mode 100644 index 0000000000..3d88585760 --- /dev/null +++ b/tests/unit/transformResponse.test.js @@ -0,0 +1,70 @@ +import { describe, it } from 'vitest'; +import defaults from '../../lib/defaults/index.js'; +import transformData from '../../lib/core/transformData.js'; +import assert from 'assert'; + +describe('transformResponse', function () { + describe('200 request', function () { + it('parses json', function () { + const data = '{"message": "hello, world"}'; + const result = transformData.call( + { + data, + response: { + headers: { 'content-type': 'application/json' }, + status: 200, + }, + }, + defaults.transformResponse + ); + assert.strictEqual(result.message, 'hello, world'); + }); + + it('ignores XML', function () { + const data = 'hello, world'; + const result = transformData.call( + { + data, + response: { + headers: { 'content-type': 'text/xml' }, + status: 200, + }, + }, + defaults.transformResponse + ); + assert.strictEqual(result, data); + }); + }); + + describe('204 request', function () { + it('does not parse the empty string', function () { + const data = ''; + const result = transformData.call( + { + data, + response: { + headers: { 'content-type': undefined }, + status: 204, + }, + }, + defaults.transformResponse + ); + assert.strictEqual(result, ''); + }); + + it('does not parse undefined', function () { + const data = undefined; + const result = transformData.call( + { + data, + response: { + headers: { 'content-type': undefined }, + status: 200, + }, + }, + defaults.transformResponse + ); + assert.strictEqual(result, data); + }); + }); +}); diff --git a/tests/unit/utils.test.js b/tests/unit/utils.test.js new file mode 100644 index 0000000000..77d4b20f51 --- /dev/null +++ b/tests/unit/utils.test.js @@ -0,0 +1,172 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import utils from '../../lib/utils.js'; +import FormData from 'form-data'; +import stream from 'stream'; + +describe('utils', function () { + it('should validate Stream', function () { + assert.strictEqual(utils.isStream(new stream.Readable()), true); + assert.strictEqual(utils.isStream({ foo: 'bar' }), false); + }); + + it('should validate Buffer', function () { + assert.strictEqual(utils.isBuffer(Buffer.from('a')), true); + assert.strictEqual(utils.isBuffer(null), false); + assert.strictEqual(utils.isBuffer(undefined), false); + }); + + describe('utils::isFormData', function () { + it('should detect the FormData instance provided by the `form-data` package', function () { + [1, 'str', {}, new RegExp()].forEach(function (thing) { + assert.equal(utils.isFormData(thing), false); + }); + assert.equal(utils.isFormData(new FormData()), true); + }); + + it('should not call toString method on built-in objects instances', () => { + const buf = Buffer.from('123'); + + buf.toString = () => assert.fail('should not be called'); + + assert.equal(utils.isFormData(buf), false); + }); + + it('should not call toString method on built-in objects instances, even if append method exists', () => { + const buf = Buffer.from('123'); + + buf.append = () => {}; + + buf.toString = () => assert.fail('should not be called'); + + assert.equal(utils.isFormData(buf), false); + }); + + it('should detect custom FormData instances by toStringTag signature and append method presence', () => { + class FormData { + append() {} + + get [Symbol.toStringTag]() { + return 'FormData'; + } + } + assert.equal(utils.isFormData(new FormData()), true); + }); + }); + + describe('toJSON', function () { + it('should convert to a plain object without circular references', function () { + const obj = { a: [0] }; + const source = { x: 1, y: 2, obj }; + source.circular1 = source; + obj.a[1] = obj; + + assert.deepStrictEqual(utils.toJSONObject(source), { + x: 1, + y: 2, + obj: { a: [0] }, + }); + }); + + it('should use objects with defined toJSON method without rebuilding', function () { + const objProp = {}; + const obj = { + objProp, + toJSON() { + return { ok: 1 }; + }, + }; + const source = { x: 1, y: 2, obj }; + + const jsonObject = utils.toJSONObject(source); + + assert.strictEqual(jsonObject.obj.objProp, objProp); + assert.strictEqual( + JSON.stringify(jsonObject), + JSON.stringify({ x: 1, y: 2, obj: { ok: 1 } }) + ); + }); + }); + + describe('Buffer RangeError Fix', function () { + it('should handle large Buffer in isEmptyObject without RangeError', function () { + const largeBuffer = Buffer.alloc(1024 * 1024 * 200); + + const result = utils.isEmptyObject(largeBuffer); + + assert.strictEqual(result, false); + }); + + it('should handle large Buffer in forEach without RangeError', function () { + const largeBuffer = Buffer.alloc(1024 * 1024 * 200); + let count = 0; + + utils.forEach(largeBuffer, () => count++); + + assert.strictEqual(count, 0); + }); + + it('should handle large Buffer in findKey without RangeError', function () { + const largeBuffer = Buffer.alloc(1024 * 1024 * 200); + + const result = utils.findKey(largeBuffer, 'test'); + + assert.strictEqual(result, null); + }); + }); + + describe('utils::isReactNativeBlob', function () { + it('should return true for objects with uri property', function () { + assert.strictEqual(utils.isReactNativeBlob({ uri: 'file://path/to/file' }), true); + assert.strictEqual(utils.isReactNativeBlob({ uri: 'content://media/image' }), true); + }); + + it('should return true for React Native blob-like objects with optional name and type', function () { + assert.strictEqual(utils.isReactNativeBlob({ + uri: 'file://path/to/file', + name: 'image.png', + type: 'image/png' + }), true); + }); + + it('should return false for objects without uri property', function () { + assert.strictEqual(utils.isReactNativeBlob({ path: 'file://path' }), false); + assert.strictEqual(utils.isReactNativeBlob({ url: 'http://example.com' }), false); + assert.strictEqual(utils.isReactNativeBlob({}), false); + }); + + it('should return false for non-objects', function () { + assert.strictEqual(utils.isReactNativeBlob(null), false); + assert.strictEqual(utils.isReactNativeBlob(undefined), false); + assert.strictEqual(utils.isReactNativeBlob('string'), false); + assert.strictEqual(utils.isReactNativeBlob(123), false); + assert.strictEqual(utils.isReactNativeBlob(false), false); + }); + + it('should return true even if uri is empty string', function () { + assert.strictEqual(utils.isReactNativeBlob({ uri: '' }), true); + }); + }); + + describe('utils::isReactNative', function () { + it('should return true for FormData with getParts method', function () { + const mockReactNativeFormData = { + append: function () {}, + getParts: function () { + return []; + } + }; + assert.strictEqual(utils.isReactNative(mockReactNativeFormData), true); + }); + + it('should return false for standard FormData without getParts method', function () { + const standardFormData = new FormData(); + assert.strictEqual(utils.isReactNative(standardFormData), false); + }); + + it('should return false for objects without getParts method', function () { + assert.strictEqual(utils.isReactNative({ append: function () {} }), false); + assert.strictEqual(utils.isReactNative({}), false); + }); + }); +}); From 00f4d5feb4cb269ecafb7af625e041e2e4cc895e Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Sun, 1 Mar 2026 17:47:04 +0200 Subject: [PATCH 04/37] feat: moving more unit tests over --- tests/unit/axios.test.js | 55 ++ tests/unit/axiosHeaders.test.js | 497 ++++++++++++++++++ tests/unit/composeSignals.test.js | 12 +- .../unit/estimateDataURLDecodedBytes.test.js | 12 +- tests/unit/fromDataURI.test.js | 4 +- tests/unit/parseProtocol.test.js | 6 +- tests/unit/platform.test.js | 6 +- tests/unit/prototypePollution.test.js | 211 ++++++++ tests/unit/regression.test.js | 26 +- tests/unit/toFormData.test.js | 42 +- tests/unit/transformResponse.test.js | 14 +- tests/unit/utils.test.js | 67 +-- 12 files changed, 855 insertions(+), 97 deletions(-) create mode 100644 tests/unit/axios.test.js create mode 100644 tests/unit/axiosHeaders.test.js create mode 100644 tests/unit/prototypePollution.test.js diff --git a/tests/unit/axios.test.js b/tests/unit/axios.test.js new file mode 100644 index 0000000000..00ab31fe2d --- /dev/null +++ b/tests/unit/axios.test.js @@ -0,0 +1,55 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import Axios from '../../lib/core/Axios.js'; + +describe('Axios', () => { + describe('handle un-writable error stack', () => { + const testUnwritableErrorStack = async (stackAttributes) => { + const axios = new Axios({}); + // Mock axios._request to return an Error with an un-writable stack property. + axios._request = () => { + const mockError = new Error('test-error'); + Object.defineProperty(mockError, 'stack', stackAttributes); + throw mockError; + }; + + try { + await axios.request('test-url', {}); + } catch (e) { + assert.strictEqual(e.message, 'test-error'); + } + }; + + it('should support errors with a defined but un-writable stack', async () => { + await testUnwritableErrorStack({ value: {}, writable: false }); + }); + + it('should support errors with an undefined and un-writable stack', async () => { + await testUnwritableErrorStack({ value: undefined, writable: false }); + }); + + it('should support errors with a custom getter/setter for the stack property', async () => { + await testUnwritableErrorStack({ + get: () => ({}), + set: () => { + throw new Error('read-only'); + }, + }); + }); + + it('should support errors with a custom getter/setter for the stack property (null case)', async () => { + await testUnwritableErrorStack({ + get: () => null, + set: () => { + throw new Error('read-only'); + }, + }); + }); + }); + + it('should not throw if the config argument is omitted', () => { + const axios = new Axios(); + + assert.deepStrictEqual(axios.defaults, {}); + }); +}); diff --git a/tests/unit/axiosHeaders.test.js b/tests/unit/axiosHeaders.test.js new file mode 100644 index 0000000000..a378f4a273 --- /dev/null +++ b/tests/unit/axiosHeaders.test.js @@ -0,0 +1,497 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import AxiosHeaders from '../../lib/core/AxiosHeaders.js'; + +const [nodeMajorVersion] = process.versions.node.split('.').map((v) => parseInt(v, 10)); + +describe('AxiosHeaders', () => { + it('should support headers argument', () => { + const headers = new AxiosHeaders({ + x: 1, + y: 2, + }); + + assert.strictEqual(headers.get('x'), '1'); + assert.strictEqual(headers.get('y'), '2'); + }); + + describe('set', () => { + it('should support adding a single header', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar'); + + assert.strictEqual(headers.get('foo'), 'bar'); + }); + + it('should support adding multiple headers', () => { + const headers = new AxiosHeaders(); + + headers.set({ + foo: 'value1', + bar: 'value2', + }); + + assert.strictEqual(headers.get('foo'), 'value1'); + assert.strictEqual(headers.get('bar'), 'value2'); + }); + + it('should support adding multiple headers from raw headers string', () => { + const headers = new AxiosHeaders(); + + headers.set(`foo:value1\nbar:value2`); + + assert.strictEqual(headers.get('foo'), 'value1'); + assert.strictEqual(headers.get('bar'), 'value2'); + }); + + it('should not rewrite header the header if the value is false', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'value1'); + + headers.set('foo', 'value2', false); + + assert.strictEqual(headers.get('foo'), 'value1'); + + headers.set('foo', 'value2'); + + assert.strictEqual(headers.get('foo'), 'value2'); + + headers.set('foo', 'value3', true); + + assert.strictEqual(headers.get('foo'), 'value3'); + }); + + it('should not rewrite the header if its value is false, unless rewrite options is set to true', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', false); + headers.set('foo', 'value2'); + + assert.strictEqual(headers.get('foo'), false); + + headers.set('foo', 'value2', true); + + assert.strictEqual(headers.get('foo'), 'value2'); + }); + + it('should support iterables as a key-value source object', () => { + const headers = new AxiosHeaders(); + + headers.set(new Map([['x', '123']])); + + assert.strictEqual(headers.get('x'), '123'); + }); + + const runIfNode18OrHigher = nodeMajorVersion >= 18 ? it : it.skip; + runIfNode18OrHigher('should support setting multiple header values from an iterable source', () => { + const headers = new AxiosHeaders(); + const nativeHeaders = new Headers(); + + nativeHeaders.append('set-cookie', 'foo'); + nativeHeaders.append('set-cookie', 'bar'); + nativeHeaders.append('set-cookie', 'baz'); + nativeHeaders.append('y', 'qux'); + + headers.set(nativeHeaders); + + assert.deepStrictEqual(headers.get('set-cookie'), ['foo', 'bar', 'baz']); + assert.strictEqual(headers.get('y'), 'qux'); + }); + }); + + it('should support uppercase name mapping for names overlapped by class methods', () => { + const headers = new AxiosHeaders({ + set: 'foo', + }); + + headers.set('get', 'bar'); + + assert.strictEqual(headers.get('Set'), 'foo'); + assert.strictEqual(headers.get('Get'), 'bar'); + }); + + describe('get', () => { + describe('filter', () => { + it('should support RegExp', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.get('foo', /^bar=(\w+)/)[1], 'value1'); + assert.strictEqual(headers.get('foo', /^foo=/), null); + }); + + it('should support function', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual( + headers.get('foo', (value, header) => { + assert.strictEqual(value, 'bar=value1'); + assert.strictEqual(header, 'foo'); + return value; + }), + 'bar=value1' + ); + assert.strictEqual( + headers.get('foo', () => false), + false + ); + }); + }); + }); + + describe('has', () => { + it('should return true if the header is defined, otherwise false', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo'), true); + assert.strictEqual(headers.has('bar'), false); + }); + + describe('filter', () => { + it('should support RegExp', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo', /^bar=(\w+)/), true); + assert.strictEqual(headers.has('foo', /^foo=/), false); + }); + + it('should support function', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual( + headers.has('foo', (value, header) => { + assert.strictEqual(value, 'bar=value1'); + assert.strictEqual(header, 'foo'); + return true; + }), + true + ); + assert.strictEqual( + headers.has('foo', () => false), + false + ); + }); + + it('should support string pattern', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo', 'value1'), true); + assert.strictEqual(headers.has('foo', 'value2'), false); + }); + }); + }); + + describe('delete', () => { + it('should delete the header', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo'), true); + + headers.delete('foo'); + + assert.strictEqual(headers.has('foo'), false); + }); + + it('should return true if the header has been deleted, otherwise false', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.delete('bar'), false); + + assert.strictEqual(headers.delete('foo'), true); + }); + + it('should support headers array', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'x'); + headers.set('bar', 'y'); + headers.set('baz', 'z'); + + assert.strictEqual(headers.delete(['foo', 'baz']), true); + + assert.strictEqual(headers.has('foo'), false); + assert.strictEqual(headers.has('bar'), true); + assert.strictEqual(headers.has('baa'), false); + }); + + describe('filter', () => { + it('should support RegExp', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo'), true); + + headers.delete('foo', /baz=/); + + assert.strictEqual(headers.has('foo'), true); + + headers.delete('foo', /bar=/); + + assert.strictEqual(headers.has('foo'), false); + }); + + it('should support function', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + headers.delete('foo', (value, header) => { + assert.strictEqual(value, 'bar=value1'); + assert.strictEqual(header, 'foo'); + return false; + }); + + assert.strictEqual(headers.has('foo'), true); + + assert.strictEqual( + headers.delete('foo', () => true), + true + ); + + assert.strictEqual(headers.has('foo'), false); + }); + + it('should support string pattern', () => { + const headers = new AxiosHeaders(); + + headers.set('foo', 'bar=value1'); + + assert.strictEqual(headers.has('foo'), true); + + headers.delete('foo', 'baz'); + + assert.strictEqual(headers.has('foo'), true); + + headers.delete('foo', 'bar'); + + assert.strictEqual(headers.has('foo'), false); + }); + }); + }); + + describe('clear', () => { + it('should clear all headers', () => { + const headers = new AxiosHeaders({ x: 1, y: 2 }); + + headers.clear(); + + assert.deepStrictEqual({ ...headers.toJSON() }, {}); + }); + + it('should clear matching headers if a matcher was specified', () => { + const headers = new AxiosHeaders({ foo: 1, 'x-foo': 2, bar: 3 }); + + assert.deepStrictEqual({ ...headers.toJSON() }, { foo: '1', 'x-foo': '2', bar: '3' }); + + headers.clear(/^x-/); + + assert.deepStrictEqual({ ...headers.toJSON() }, { foo: '1', bar: '3' }); + }); + }); + + describe('toJSON', () => { + it('should return headers object with original headers case', () => { + const headers = new AxiosHeaders({ + Foo: 'x', + bAr: 'y', + }); + + assert.deepStrictEqual( + { ...headers.toJSON() }, + { + Foo: 'x', + bAr: 'y', + } + ); + }); + }); + + describe('accessors', () => { + it('should support get accessor', () => { + const headers = new AxiosHeaders({ + foo: 1, + }); + + headers.constructor.accessor('foo'); + + assert.strictEqual(typeof headers.getFoo, 'function'); + assert.strictEqual(headers.getFoo(), '1'); + }); + + it('should support set accessor', () => { + const headers = new AxiosHeaders({ + foo: 1, + }); + + headers.constructor.accessor('foo'); + + assert.strictEqual(typeof headers.setFoo, 'function'); + headers.setFoo(2); + assert.strictEqual(headers.getFoo(), '2'); + }); + + it('should support has accessor', () => { + const headers = new AxiosHeaders({ + foo: 1, + }); + + headers.constructor.accessor('foo'); + + assert.strictEqual(typeof headers.hasFoo, 'function'); + assert.strictEqual(headers.hasFoo(), true); + }); + }); + + it('should be caseless', () => { + const headers = new AxiosHeaders({ + fOo: 1, + }); + + assert.strictEqual(headers.get('Foo'), '1'); + assert.strictEqual(headers.get('foo'), '1'); + + headers.set('foo', 2); + + assert.strictEqual(headers.get('foO'), '2'); + assert.strictEqual(headers.get('fOo'), '2'); + + assert.strictEqual(headers.has('fOo'), true); + + headers.delete('FOO'); + + assert.strictEqual(headers.has('fOo'), false); + }); + + describe('normalize()', () => { + it('should support auto-formatting', () => { + const headers = new AxiosHeaders({ + fOo: 1, + 'x-foo': 2, + 'y-bar-bAz': 3, + }); + + assert.deepStrictEqual( + { ...headers.normalize(true).toJSON() }, + { + Foo: '1', + 'X-Foo': '2', + 'Y-Bar-Baz': '3', + } + ); + }); + + it('should support external defined values', () => { + const headers = new AxiosHeaders({ + foo: '1', + }); + + headers.Foo = 2; + headers.bar = 3; + + assert.deepStrictEqual( + { ...headers.normalize().toJSON() }, + { + foo: '2', + bar: '3', + } + ); + }); + + it('should support array values', () => { + const headers = new AxiosHeaders({ + foo: [1, 2, 3], + }); + + assert.deepStrictEqual( + { ...headers.normalize().toJSON() }, + { + foo: ['1', '2', '3'], + } + ); + }); + }); + + describe('AxiosHeaders.concat', () => { + it('should concatenate plain headers into an AxiosHeader instance', () => { + const a = { a: 1 }; + const b = { b: 2 }; + const c = { c: 3 }; + const headers = AxiosHeaders.concat(a, b, c); + + assert.deepStrictEqual( + { ...headers.toJSON() }, + { + a: '1', + b: '2', + c: '3', + } + ); + }); + + it('should concatenate raw headers into an AxiosHeader instance', () => { + const a = 'a:1\nb:2'; + const b = 'c:3\nx:4'; + const headers = AxiosHeaders.concat(a, b); + + assert.deepStrictEqual( + { ...headers.toJSON() }, + { + a: '1', + b: '2', + c: '3', + x: '4', + } + ); + }); + + it('should concatenate Axios headers into a new AxiosHeader instance', () => { + const a = new AxiosHeaders({ x: 1 }); + const b = new AxiosHeaders({ y: 2 }); + const headers = AxiosHeaders.concat(a, b); + + assert.deepStrictEqual( + { ...headers.toJSON() }, + { + x: '1', + y: '2', + } + ); + }); + }); + + describe('toString', () => { + it('should serialize AxiosHeader instance to a raw headers string', () => { + assert.deepStrictEqual(new AxiosHeaders({ x: 1, y: 2 }).toString(), 'x: 1\ny: 2'); + }); + }); + + describe('getSetCookie', () => { + it('should return set-cookie', () => { + const headers = new AxiosHeaders('Set-Cookie: key=val;\n' + 'Set-Cookie: key2=val2;\n'); + + assert.deepStrictEqual(headers.getSetCookie(), ['key=val;', 'key2=val2;']); + }); + + it('should return empty set-cookie', () => { + assert.deepStrictEqual(new AxiosHeaders().getSetCookie(), []); + }); + }); +}); diff --git a/tests/unit/composeSignals.test.js b/tests/unit/composeSignals.test.js index e17ffb6751..8bbd5c62b0 100644 --- a/tests/unit/composeSignals.test.js +++ b/tests/unit/composeSignals.test.js @@ -2,10 +2,10 @@ import { describe, it } from 'vitest'; import assert from 'assert'; import composeSignals from '../../lib/helpers/composeSignals.js'; -describe('helpers::composeSignals', function () { +describe('helpers::composeSignals', () => { const runIfAbortController = typeof AbortController === 'function' ? it : it.skip; - runIfAbortController('should abort when any of the signals abort', function () { + runIfAbortController('should abort when any of the signals abort', () => { let called; const controllerA = new AbortController(); @@ -13,7 +13,7 @@ describe('helpers::composeSignals', function () { const signal = composeSignals([controllerA.signal, controllerB.signal]); - signal.addEventListener('abort', function () { + signal.addEventListener('abort', () => { called = true; }); @@ -22,17 +22,17 @@ describe('helpers::composeSignals', function () { assert.ok(called); }); - runIfAbortController('should abort on timeout', async function () { + runIfAbortController('should abort on timeout', async () => { const signal = composeSignals([], 100); - await new Promise(function (resolve) { + await new Promise((resolve) => { signal.addEventListener('abort', resolve); }); assert.match(String(signal.reason), /timeout of 100ms exceeded/); }); - it('should return undefined if signals and timeout are not provided', function () { + it('should return undefined if signals and timeout are not provided', () => { const signal = composeSignals([]); assert.strictEqual(signal, undefined); diff --git a/tests/unit/estimateDataURLDecodedBytes.test.js b/tests/unit/estimateDataURLDecodedBytes.test.js index ddff64e8a2..0ad64a7429 100644 --- a/tests/unit/estimateDataURLDecodedBytes.test.js +++ b/tests/unit/estimateDataURLDecodedBytes.test.js @@ -2,29 +2,29 @@ import { describe, it } from 'vitest'; import assert from 'assert'; import estimateDataURLDecodedBytes from '../../lib/helpers/estimateDataURLDecodedBytes.js'; -describe('estimateDataURLDecodedBytes', function () { - it('should return 0 for non-data URLs', function () { +describe('estimateDataURLDecodedBytes', () => { + it('should return 0 for non-data URLs', () => { assert.strictEqual(estimateDataURLDecodedBytes('http://example.com'), 0); }); - it('should calculate length for simple non-base64 data URL', function () { + it('should calculate length for simple non-base64 data URL', () => { const url = 'data:,Hello'; assert.strictEqual(estimateDataURLDecodedBytes(url), Buffer.byteLength('Hello', 'utf8')); }); - it('should calculate decoded length for base64 data URL', function () { + it('should calculate decoded length for base64 data URL', () => { const str = 'Hello'; const b64 = Buffer.from(str, 'utf8').toString('base64'); const url = `data:text/plain;base64,${b64}`; assert.strictEqual(estimateDataURLDecodedBytes(url), str.length); }); - it('should handle base64 with = padding', function () { + it('should handle base64 with = padding', () => { const url = 'data:text/plain;base64,TQ=='; assert.strictEqual(estimateDataURLDecodedBytes(url), 1); }); - it('should handle base64 with %3D padding', function () { + it('should handle base64 with %3D padding', () => { const url = 'data:text/plain;base64,TQ%3D%3D'; assert.strictEqual(estimateDataURLDecodedBytes(url), 1); }); diff --git a/tests/unit/fromDataURI.test.js b/tests/unit/fromDataURI.test.js index f034bd7db8..ef4f1e37d2 100644 --- a/tests/unit/fromDataURI.test.js +++ b/tests/unit/fromDataURI.test.js @@ -2,8 +2,8 @@ import { describe, it } from 'vitest'; import assert from 'assert'; import fromDataURI from '../../lib/helpers/fromDataURI.js'; -describe('helpers::fromDataURI', function () { - it('should return buffer from data uri', function () { +describe('helpers::fromDataURI', () => { + it('should return buffer from data uri', () => { const buffer = Buffer.from('123'); const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); diff --git a/tests/unit/parseProtocol.test.js b/tests/unit/parseProtocol.test.js index 87813654bb..6a295f3611 100644 --- a/tests/unit/parseProtocol.test.js +++ b/tests/unit/parseProtocol.test.js @@ -3,8 +3,8 @@ import assert from 'assert'; import utils from '../../lib/utils.js'; import parseProtocol from '../../lib/helpers/parseProtocol.js'; -describe('helpers::parseProtocol', function () { - it('should parse protocol part if it exists', function () { +describe('helpers::parseProtocol', () => { + it('should parse protocol part if it exists', () => { utils.forEach( { 'http://username:password@example.com/': 'http', @@ -20,7 +20,7 @@ describe('helpers::parseProtocol', function () { 'mailto:jsmith@example.com': 'mailto', 'chrome-extension://1234/.html': 'chrome-extension', }, - function (expectedProtocol, url) { + (expectedProtocol, url) => { assert.strictEqual(parseProtocol(url), expectedProtocol); } ); diff --git a/tests/unit/platform.test.js b/tests/unit/platform.test.js index d60aed3be1..caa249cad6 100644 --- a/tests/unit/platform.test.js +++ b/tests/unit/platform.test.js @@ -2,15 +2,15 @@ import { describe, it } from 'vitest'; import platform from '../../lib/platform/index.js'; import assert from 'assert'; -describe('generateString', function () { - it('should generate a string of the specified length using the default alphabet', function () { +describe('generateString', () => { + it('should generate a string of the specified length using the default alphabet', () => { const size = 10; const str = platform.generateString(size); assert.strictEqual(str.length, size); }); - it('should generate a string using only characters from the default alphabet', function () { + it('should generate a string using only characters from the default alphabet', () => { const size = 10; const alphabet = platform.ALPHABET.ALPHA_DIGIT; diff --git a/tests/unit/prototypePollution.test.js b/tests/unit/prototypePollution.test.js new file mode 100644 index 0000000000..0d78163133 --- /dev/null +++ b/tests/unit/prototypePollution.test.js @@ -0,0 +1,211 @@ +/* eslint-disable no-prototype-builtins */ +import { afterEach, describe, it } from 'vitest'; +import assert from 'assert'; +import utils from '../../lib/utils.js'; +import mergeConfig from '../../lib/core/mergeConfig.js'; + +describe('Prototype Pollution Protection', () => { + afterEach(() => { + // Clean up any pollution that might have occurred. + delete Object.prototype.polluted; + }); + + describe('utils.merge', () => { + it('should filter __proto__ key at top level', () => { + const result = utils.merge({}, { __proto__: { polluted: 'yes' }, safe: 'value' }); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.safe, 'value'); + assert.strictEqual(result.hasOwnProperty('__proto__'), false); + }); + + it('should filter constructor key at top level', () => { + const result = utils.merge({}, { constructor: { polluted: 'yes' }, safe: 'value' }); + + assert.strictEqual(result.safe, 'value'); + assert.strictEqual(result.hasOwnProperty('constructor'), false); + }); + + it('should filter prototype key at top level', () => { + const result = utils.merge({}, { prototype: { polluted: 'yes' }, safe: 'value' }); + + assert.strictEqual(result.safe, 'value'); + assert.strictEqual(result.hasOwnProperty('prototype'), false); + }); + + it('should filter __proto__ key in nested objects', () => { + const result = utils.merge( + {}, + { + headers: { + __proto__: { polluted: 'nested' }, + 'Content-Type': 'application/json', + }, + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.headers['Content-Type'], 'application/json'); + assert.strictEqual(result.headers.hasOwnProperty('__proto__'), false); + }); + + it('should filter constructor key in nested objects', () => { + const result = utils.merge( + {}, + { + headers: { + constructor: { prototype: { polluted: 'nested' } }, + 'Content-Type': 'application/json', + }, + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.headers['Content-Type'], 'application/json'); + assert.strictEqual(result.headers.hasOwnProperty('constructor'), false); + }); + + it('should filter prototype key in nested objects', () => { + const result = utils.merge( + {}, + { + headers: { + prototype: { polluted: 'nested' }, + 'Content-Type': 'application/json', + }, + } + ); + + assert.strictEqual(result.headers['Content-Type'], 'application/json'); + assert.strictEqual(result.headers.hasOwnProperty('prototype'), false); + }); + + it('should filter dangerous keys in deeply nested objects', () => { + const result = utils.merge( + {}, + { + level1: { + level2: { + __proto__: { polluted: 'deep' }, + prototype: { polluted: 'deep' }, + safe: 'value', + }, + }, + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.level1.level2.safe, 'value'); + assert.strictEqual(result.level1.level2.hasOwnProperty('__proto__'), false); + }); + + it('should still merge regular properties correctly', () => { + const result = utils.merge({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 }); + + assert.strictEqual(result.a, 1); + assert.strictEqual(result.b.c, 2); + assert.strictEqual(result.b.d, 3); + assert.strictEqual(result.e, 4); + }); + + it('should handle JSON.parse payloads safely', () => { + const malicious = JSON.parse('{"__proto__": {"polluted": "yes"}}'); + const result = utils.merge({}, malicious); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.hasOwnProperty('__proto__'), false); + }); + + it('should handle nested JSON.parse payloads safely', () => { + const malicious = JSON.parse( + '{"headers": {"constructor": {"prototype": {"polluted": "yes"}}}}' + ); + const result = utils.merge({}, malicious); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.headers.hasOwnProperty('constructor'), false); + }); + }); + + describe('mergeConfig', () => { + it('should filter dangerous keys at top level', () => { + const result = mergeConfig( + {}, + { + __proto__: { polluted: 'yes' }, + constructor: { polluted: 'yes' }, + prototype: { polluted: 'yes' }, + url: '/api/test', + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.url, '/api/test'); + assert.strictEqual(result.hasOwnProperty('__proto__'), false); + assert.strictEqual(result.hasOwnProperty('constructor'), false); + assert.strictEqual(result.hasOwnProperty('prototype'), false); + }); + + it('should filter dangerous keys in headers', () => { + const result = mergeConfig( + {}, + { + headers: { + __proto__: { polluted: 'yes' }, + 'Content-Type': 'application/json', + }, + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.headers['Content-Type'], 'application/json'); + assert.strictEqual(result.headers.hasOwnProperty('__proto__'), false); + }); + + it('should filter dangerous keys in custom config properties', () => { + const result = mergeConfig( + {}, + { + customProp: { + __proto__: { polluted: 'yes' }, + safe: 'value', + }, + } + ); + + assert.strictEqual(Object.prototype.polluted, undefined); + assert.strictEqual(result.customProp.safe, 'value'); + assert.strictEqual(result.customProp.hasOwnProperty('__proto__'), false); + }); + + it('should still merge configs correctly', () => { + const config1 = { + baseURL: 'https://api.example.com', + timeout: 1000, + headers: { + common: { + Accept: 'application/json', + }, + }, + }; + + const config2 = { + url: '/users', + timeout: 5000, + headers: { + common: { + 'Content-Type': 'application/json', + }, + }, + }; + + const result = mergeConfig(config1, config2); + + assert.strictEqual(result.baseURL, 'https://api.example.com'); + assert.strictEqual(result.url, '/users'); + assert.strictEqual(result.timeout, 5000); + assert.strictEqual(result.headers.common.Accept, 'application/json'); + assert.strictEqual(result.headers.common['Content-Type'], 'application/json'); + }); + }); +}); diff --git a/tests/unit/regression.test.js b/tests/unit/regression.test.js index 731127cd34..90a4b5d2d6 100644 --- a/tests/unit/regression.test.js +++ b/tests/unit/regression.test.js @@ -7,11 +7,11 @@ import http from 'http'; import axios from '../../index.js'; import platform from '../../lib/platform/index.js'; -describe('regression', function () { - describe('issues', function () { - describe('4999', function () { +describe('regression', () => { + describe('issues', () => { + describe('4999', () => { // Depends on network: https://postman-echo.com - it('should not fail with query parsing', async function () { + it('should not fail with query parsing', async () => { const { data } = await axios.get('https://postman-echo.com/get?foo1=bar1&foo2=bar2'); assert.strictEqual(data.args.foo1, 'bar1'); @@ -19,8 +19,8 @@ describe('regression', function () { }); }); - describe('5028', function () { - it('should handle set-cookie headers as an array', async function () { + describe('5028', () => { + it('should handle set-cookie headers as an array', async () => { const cookie1 = 'something=else; path=/; expires=Wed, 12 Apr 2023 12:03:42 GMT; samesite=lax; secure; httponly'; const cookie2 = @@ -49,8 +49,8 @@ describe('regression', function () { }); }); - describe('7364', function () { - it('fetch: should have status code in axios error', async function () { + describe('7364', () => { + it('fetch: should have status code in axios error', async () => { const isFetchSupported = typeof fetch === 'function'; if (!isFetchSupported) { vi.skip(); @@ -79,7 +79,7 @@ describe('regression', function () { } }); - it('http: should have status code in axios error', async function () { + it('http: should have status code in axios error', async () => { const server = http .createServer((req, res) => { res.statusCode = 400; @@ -119,7 +119,7 @@ describe('regression', function () { beforeEach(() => { fail = false; server = http - .createServer(function (req, res) { + .createServer((req, res) => { fail = true; res.end('rm -rf /'); }) @@ -127,7 +127,7 @@ describe('regression', function () { evilPort = server.address().port; proxy = http - .createServer(function (req, res) { + .createServer((req, res) => { if ( new URL(req.url, 'http://' + req.headers.host).toString() === 'http://localhost:' + evilPort + '/' @@ -188,7 +188,7 @@ describe('regression', function () { beforeEach(() => { goodServer = http - .createServer(function (req, res) { + .createServer((req, res) => { res.write('good'); res.end(); }) @@ -196,7 +196,7 @@ describe('regression', function () { goodPort = goodServer.address().port; badServer = http - .createServer(function (req, res) { + .createServer((req, res) => { res.write('bad'); res.end(); }) diff --git a/tests/unit/toFormData.test.js b/tests/unit/toFormData.test.js index d3a3629039..f499d3d715 100644 --- a/tests/unit/toFormData.test.js +++ b/tests/unit/toFormData.test.js @@ -3,21 +3,21 @@ import assert from 'assert'; import FormData from 'form-data'; import toFormData from '../../lib/helpers/toFormData.js'; -describe('helpers::toFormData', function () { - function createRNFormDataSpy() { +describe('helpers::toFormData', () => { + const createRNFormDataSpy = () => { const calls = []; return { calls, - append(key, value) { + append: (key, value) => { calls.push([key, value]); }, - getParts() { + getParts: () => { return []; }, }; - } + }; - it('should convert a flat object to FormData', function () { + it('should convert a flat object to FormData', () => { const data = { foo: 'bar', baz: 123, @@ -29,7 +29,7 @@ describe('helpers::toFormData', function () { assert.ok(formData._streams.length > 0); }); - it('should convert a nested object to FormData', function () { + it('should convert a nested object to FormData', () => { const data = { foo: { bar: 'baz', @@ -41,7 +41,7 @@ describe('helpers::toFormData', function () { assert.ok(formData instanceof FormData); }); - it('should throw Error on circular reference', function () { + it('should throw Error on circular reference', () => { const data = { foo: 'bar', }; @@ -55,7 +55,7 @@ describe('helpers::toFormData', function () { } }); - it('should handle arrays', function () { + it('should handle arrays', () => { const data = { arr: [1, 2, 3], }; @@ -64,7 +64,7 @@ describe('helpers::toFormData', function () { assert.ok(formData instanceof FormData); }); - it('should append root-level React Native blob without recursion', function () { + it('should append root-level React Native blob without recursion', () => { const formData = createRNFormDataSpy(); const blob = { @@ -80,7 +80,7 @@ describe('helpers::toFormData', function () { assert.strictEqual(formData.calls[0][1], blob); }); - it('should append nested React Native blob without recursion', function () { + it('should append nested React Native blob without recursion', () => { const formData = createRNFormDataSpy(); const blob = { @@ -96,7 +96,7 @@ describe('helpers::toFormData', function () { assert.strictEqual(formData.calls[0][1], blob); }); - it('should append deeply nested React Native blob without recursion', function () { + it('should append deeply nested React Native blob without recursion', () => { const formData = createRNFormDataSpy(); const blob = { @@ -111,7 +111,7 @@ describe('helpers::toFormData', function () { assert.strictEqual(formData.calls[0][1], blob); }); - it('should NOT recurse into React Native blob properties', function () { + it('should NOT recurse into React Native blob properties', () => { const formData = createRNFormDataSpy(); const blob = { @@ -122,19 +122,11 @@ describe('helpers::toFormData', function () { toFormData({ file: blob }, formData); - const keys = formData.calls.map(function (call) { - return call[0]; - }); + const keys = formData.calls.map((call) => call[0]); assert.deepStrictEqual(keys, ['file']); - assert.ok(!keys.some(function (key) { - return key.includes('uri'); - })); - assert.ok(!keys.some(function (key) { - return key.includes('type'); - })); - assert.ok(!keys.some(function (key) { - return key.includes('name'); - })); + assert.ok(!keys.some((key) => key.includes('uri'))); + assert.ok(!keys.some((key) => key.includes('type'))); + assert.ok(!keys.some((key) => key.includes('name'))); }); }); diff --git a/tests/unit/transformResponse.test.js b/tests/unit/transformResponse.test.js index 3d88585760..2892e775b4 100644 --- a/tests/unit/transformResponse.test.js +++ b/tests/unit/transformResponse.test.js @@ -3,9 +3,9 @@ import defaults from '../../lib/defaults/index.js'; import transformData from '../../lib/core/transformData.js'; import assert from 'assert'; -describe('transformResponse', function () { - describe('200 request', function () { - it('parses json', function () { +describe('transformResponse', () => { + describe('200 request', () => { + it('parses json', () => { const data = '{"message": "hello, world"}'; const result = transformData.call( { @@ -20,7 +20,7 @@ describe('transformResponse', function () { assert.strictEqual(result.message, 'hello, world'); }); - it('ignores XML', function () { + it('ignores XML', () => { const data = 'hello, world'; const result = transformData.call( { @@ -36,8 +36,8 @@ describe('transformResponse', function () { }); }); - describe('204 request', function () { - it('does not parse the empty string', function () { + describe('204 request', () => { + it('does not parse the empty string', () => { const data = ''; const result = transformData.call( { @@ -52,7 +52,7 @@ describe('transformResponse', function () { assert.strictEqual(result, ''); }); - it('does not parse undefined', function () { + it('does not parse undefined', () => { const data = undefined; const result = transformData.call( { diff --git a/tests/unit/utils.test.js b/tests/unit/utils.test.js index 77d4b20f51..7979de81ef 100644 --- a/tests/unit/utils.test.js +++ b/tests/unit/utils.test.js @@ -4,21 +4,21 @@ import utils from '../../lib/utils.js'; import FormData from 'form-data'; import stream from 'stream'; -describe('utils', function () { - it('should validate Stream', function () { +describe('utils', () => { + it('should validate Stream', () => { assert.strictEqual(utils.isStream(new stream.Readable()), true); assert.strictEqual(utils.isStream({ foo: 'bar' }), false); }); - it('should validate Buffer', function () { + it('should validate Buffer', () => { assert.strictEqual(utils.isBuffer(Buffer.from('a')), true); assert.strictEqual(utils.isBuffer(null), false); assert.strictEqual(utils.isBuffer(undefined), false); }); - describe('utils::isFormData', function () { - it('should detect the FormData instance provided by the `form-data` package', function () { - [1, 'str', {}, new RegExp()].forEach(function (thing) { + describe('utils::isFormData', () => { + it('should detect the FormData instance provided by the `form-data` package', () => { + [1, 'str', {}, new RegExp()].forEach((thing) => { assert.equal(utils.isFormData(thing), false); }); assert.equal(utils.isFormData(new FormData()), true); @@ -54,8 +54,8 @@ describe('utils', function () { }); }); - describe('toJSON', function () { - it('should convert to a plain object without circular references', function () { + describe('toJSON', () => { + it('should convert to a plain object without circular references', () => { const obj = { a: [0] }; const source = { x: 1, y: 2, obj }; source.circular1 = source; @@ -68,7 +68,7 @@ describe('utils', function () { }); }); - it('should use objects with defined toJSON method without rebuilding', function () { + it('should use objects with defined toJSON method without rebuilding', () => { const objProp = {}; const obj = { objProp, @@ -88,8 +88,8 @@ describe('utils', function () { }); }); - describe('Buffer RangeError Fix', function () { - it('should handle large Buffer in isEmptyObject without RangeError', function () { + describe('Buffer RangeError Fix', () => { + it('should handle large Buffer in isEmptyObject without RangeError', () => { const largeBuffer = Buffer.alloc(1024 * 1024 * 200); const result = utils.isEmptyObject(largeBuffer); @@ -97,7 +97,7 @@ describe('utils', function () { assert.strictEqual(result, false); }); - it('should handle large Buffer in forEach without RangeError', function () { + it('should handle large Buffer in forEach without RangeError', () => { const largeBuffer = Buffer.alloc(1024 * 1024 * 200); let count = 0; @@ -106,7 +106,7 @@ describe('utils', function () { assert.strictEqual(count, 0); }); - it('should handle large Buffer in findKey without RangeError', function () { + it('should handle large Buffer in findKey without RangeError', () => { const largeBuffer = Buffer.alloc(1024 * 1024 * 200); const result = utils.findKey(largeBuffer, 'test'); @@ -115,27 +115,30 @@ describe('utils', function () { }); }); - describe('utils::isReactNativeBlob', function () { - it('should return true for objects with uri property', function () { + describe('utils::isReactNativeBlob', () => { + it('should return true for objects with uri property', () => { assert.strictEqual(utils.isReactNativeBlob({ uri: 'file://path/to/file' }), true); assert.strictEqual(utils.isReactNativeBlob({ uri: 'content://media/image' }), true); }); - it('should return true for React Native blob-like objects with optional name and type', function () { - assert.strictEqual(utils.isReactNativeBlob({ - uri: 'file://path/to/file', - name: 'image.png', - type: 'image/png' - }), true); + it('should return true for React Native blob-like objects with optional name and type', () => { + assert.strictEqual( + utils.isReactNativeBlob({ + uri: 'file://path/to/file', + name: 'image.png', + type: 'image/png', + }), + true + ); }); - it('should return false for objects without uri property', function () { + it('should return false for objects without uri property', () => { assert.strictEqual(utils.isReactNativeBlob({ path: 'file://path' }), false); assert.strictEqual(utils.isReactNativeBlob({ url: 'http://example.com' }), false); assert.strictEqual(utils.isReactNativeBlob({}), false); }); - it('should return false for non-objects', function () { + it('should return false for non-objects', () => { assert.strictEqual(utils.isReactNativeBlob(null), false); assert.strictEqual(utils.isReactNativeBlob(undefined), false); assert.strictEqual(utils.isReactNativeBlob('string'), false); @@ -143,29 +146,29 @@ describe('utils', function () { assert.strictEqual(utils.isReactNativeBlob(false), false); }); - it('should return true even if uri is empty string', function () { + it('should return true even if uri is empty string', () => { assert.strictEqual(utils.isReactNativeBlob({ uri: '' }), true); }); }); - describe('utils::isReactNative', function () { - it('should return true for FormData with getParts method', function () { + describe('utils::isReactNative', () => { + it('should return true for FormData with getParts method', () => { const mockReactNativeFormData = { - append: function () {}, - getParts: function () { + append: () => {}, + getParts: () => { return []; - } + }, }; assert.strictEqual(utils.isReactNative(mockReactNativeFormData), true); }); - it('should return false for standard FormData without getParts method', function () { + it('should return false for standard FormData without getParts method', () => { const standardFormData = new FormData(); assert.strictEqual(utils.isReactNative(standardFormData), false); }); - it('should return false for objects without getParts method', function () { - assert.strictEqual(utils.isReactNative({ append: function () {} }), false); + it('should return false for objects without getParts method', () => { + assert.strictEqual(utils.isReactNative({ append: () => {} }), false); assert.strictEqual(utils.isReactNative({}), false); }); }); From e65b0f21499043e18d79c9fc6b150157f94e94f5 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Mon, 2 Mar 2026 16:21:40 +0200 Subject: [PATCH 05/37] feat: more tests moved --- .../rewrite_helper_tests_a2f815ee.plan.md | 55 + tests/setup/server.js | 251 ++ tests/setup/unit.setup.js | 6 + tests/unit/adapters/adapters.test.js | 48 + tests/unit/adapters/axios.png | Bin 0 -> 1716 bytes tests/unit/adapters/cert.pem | 17 + tests/unit/adapters/error-details.test.js | 83 + tests/unit/adapters/fetch.test.js | 531 +++ tests/unit/adapters/http.test.js | 3114 +++++++++++++++++ tests/unit/adapters/key.pem | 27 + vitest.config.js | 1 + 11 files changed, 4133 insertions(+) create mode 100644 .cursor/plans/rewrite_helper_tests_a2f815ee.plan.md create mode 100644 tests/setup/server.js create mode 100644 tests/setup/unit.setup.js create mode 100644 tests/unit/adapters/adapters.test.js create mode 100644 tests/unit/adapters/axios.png create mode 100644 tests/unit/adapters/cert.pem create mode 100644 tests/unit/adapters/error-details.test.js create mode 100644 tests/unit/adapters/fetch.test.js create mode 100644 tests/unit/adapters/http.test.js create mode 100644 tests/unit/adapters/key.pem diff --git a/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md b/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md new file mode 100644 index 0000000000..53614da0ba --- /dev/null +++ b/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md @@ -0,0 +1,55 @@ +--- +name: Rewrite helper tests +overview: Migrate coverage intent from legacy helper tests into the `tests/unit` Vitest suite, while keeping legacy files untouched and avoiding config/script changes. +todos: + - id: map-legacy-to-vitest + content: Create legacy-to-tests/unit parity checklist for all helper test files + status: completed + - id: port-missing-cases + content: Port missing legacy assertions/edge cases into corresponding tests/unit files + status: completed + - id: normalize-vitest-style + content: Align rewritten tests with current repository Vitest conventions + status: completed + - id: run-vitest-unit + content: Run targeted and full unit Vitest tests to validate rewrite + status: completed + - id: verify-legacy-untouched + content: Ensure test/unit/helpers files remain unchanged + status: completed +isProject: false +--- + +# Rewrite Helper Tests To Vitest + +## Scope And Constraints + +- Keep legacy helper tests untouched in `[/Users/jay/Code/OpenSource/axiosV1/test/unit/helpers](file:///Users/jay/Code/OpenSource/axiosV1/test/unit/helpers)`. +- Rewrite/refresh the helper test coverage in `[/Users/jay/Code/OpenSource/axiosV1/tests/unit](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit)` only. +- Make no changes to test config/scripts (Vitest already targets `tests/unit/**/*.test.js` in `[/Users/jay/Code/OpenSource/axiosV1/vitest.config.js](file:///Users/jay/Code/OpenSource/axiosV1/vitest.config.js)`). + +## Implementation Plan + +1. Build a case-by-case parity matrix from legacy helper files to Vitest files: + +- `composeSignals` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/composeSignals.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/composeSignals.test.js)` +- `estimateDataURLDecodedBytes` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/estimateDataURLDecodedBytes.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/estimateDataURLDecodedBytes.test.js)` +- `fromDataURI` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/fromDataURI.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/fromDataURI.test.js)` +- `parseProtocol` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/parseProtocol.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/parseProtocol.test.js)` +- `toFormData` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/toFormData.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/toFormData.test.js)` + +1. For each mapped file, port any missing assertions/edge cases from legacy tests into the `tests/unit` version without changing runtime behavior under test. +2. Normalize each rewritten file to the repo’s current Vitest style: + +- Use `vitest` imports (`describe`/`it` and hooks as needed). +- Keep assertion style aligned with existing repo convention (`assert`-based checks where already standard). +- Replace Mocha-only idioms (e.g., `this.skip`) with Vitest-compatible conditional patterns (`it.skip`/runtime guards). + +1. Add brief, targeted comments only where logic is non-obvious (for example, environment-gated abort/controller coverage or React Native FormData spy behavior). +2. Run focused verification on just touched unit tests, then run the full unit Vitest project to ensure no regressions. + +## Verification + +- Run targeted files first (fast feedback): `npm run test:vitest:unit -- tests/unit/{composeSignals,estimateDataURLDecodedBytes,fromDataURI,parseProtocol,toFormData}.test.js` +- Run full unit suite: `npm run test:vitest:unit` +- Confirm legacy files remain unchanged in `[/Users/jay/Code/OpenSource/axiosV1/test/unit/helpers](file:///Users/jay/Code/OpenSource/axiosV1/test/unit/helpers)`. diff --git a/tests/setup/server.js b/tests/setup/server.js new file mode 100644 index 0000000000..6005322d98 --- /dev/null +++ b/tests/setup/server.js @@ -0,0 +1,251 @@ +import http from 'http'; +import http2 from 'http2'; +import stream from 'stream'; +import getStream from 'get-stream'; +import { Throttle } from 'stream-throttle'; +import formidable from 'formidable'; +import selfsigned from 'selfsigned'; + +export const LOCAL_SERVER_URL = 'http://localhost:4444'; + +export const SERVER_HANDLER_STREAM_ECHO = (req, res) => req.pipe(res); + +export const setTimeoutAsync = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +const certificate = selfsigned.generate(null, { keySize: 2048 }); +const trackedServers = new Set(); + +const untrackServer = (server) => { + trackedServers.delete(server); +}; + +export const startHTTPServer = (handlerOrOptions, options) => { + const { + handler, + useBuffering = false, + rate = undefined, + port = 4444, + keepAlive = 1000, + useHTTP2, + key = certificate.private, + cert = certificate.cert, + } = Object.assign( + typeof handlerOrOptions === 'function' + ? { + handler: handlerOrOptions, + } + : handlerOrOptions || {}, + options + ); + + return new Promise((resolve, reject) => { + const serverHandler = + handler || + async function (req, res) { + try { + req.headers['content-length'] && res.setHeader('content-length', req.headers['content-length']); + + let dataStream = req; + + if (useBuffering) { + dataStream = stream.Readable.from(await getStream(req)); + } + + const streams = [dataStream]; + + if (rate) { + streams.push(new Throttle({ rate })); + } + + streams.push(res); + + stream.pipeline(streams, (err) => { + err && console.log('Server warning: ' + err.message); + }); + } catch (err) { + console.warn('HTTP server error:', err); + } + }; + + const server = useHTTP2 + ? http2.createSecureServer({ key, cert }, serverHandler) + : http.createServer(serverHandler); + + const sessions = new Set(); + + if (useHTTP2) { + server.on('session', (session) => { + sessions.add(session); + + session.once('close', () => { + sessions.delete(session); + }); + }); + + server.closeAllSessions = () => { + for (const session of sessions) { + session.destroy(); + } + }; + } else { + server.keepAliveTimeout = keepAlive; + } + + server.listen(port, function (err) { + if (err) { + reject(err); + return; + } + + trackedServers.add(this); + resolve(this); + }); + }); +}; + +export const stopHTTPServer = async (server, timeout = 10000) => { + if (server) { + if (typeof server.closeAllConnections === 'function') { + server.closeAllConnections(); + } + + if (typeof server.closeAllSessions === 'function') { + server.closeAllSessions(); + } + + await Promise.race([new Promise((resolve) => server.close(resolve)), setTimeoutAsync(timeout)]); + untrackServer(server); + } +}; + +export const stopAllTrackedHTTPServers = async (timeout = 10000) => { + const servers = Array.from(trackedServers); + await Promise.all(servers.map((server) => stopHTTPServer(server, timeout))); +}; + +export const handleFormData = (req) => { + return new Promise((resolve, reject) => { + const form = new formidable.IncomingForm(); + + form.parse(req, (err, fields, files) => { + if (err) { + return reject(err); + } + + resolve({ fields, files }); + }); + }); +}; + +export const nodeVersion = process.versions.node.split('.').map((v) => parseInt(v, 10)); + +export const generateReadable = (length = 1024 * 1024, chunkSize = 10 * 1024, sleep = 50) => { + return stream.Readable.from( + (async function* () { + let dataLength = 0; + + while (dataLength < length) { + const leftBytes = length - dataLength; + + const chunk = Buffer.alloc(leftBytes > chunkSize ? chunkSize : leftBytes); + + dataLength += chunk.length; + + yield chunk; + + if (sleep) { + await setTimeoutAsync(sleep); + } + } + })() + ); +}; + +export const makeReadableStream = (chunk = 'chunk', n = 10, timeout = 100) => { + return new ReadableStream( + { + async pull(controller) { + await setTimeoutAsync(timeout); + n-- ? controller.enqueue(chunk) : controller.close(); + }, + }, + { + highWaterMark: 1, + } + ); +}; + +export const makeEchoStream = (echo) => + new WritableStream({ + write(chunk) { + echo && console.log('Echo chunk', chunk); + }, + }); + +export const startTestServer = async (port) => { + const handler = async (req) => { + const parsed = new URL(req.url, `http://localhost:${port}`); + + const params = Object.fromEntries(parsed.searchParams); + + const response = { + url: req.url, + pathname: parsed.pathname, + params, + method: req.method, + headers: req.headers, + }; + + const contentType = req.headers['content-type'] || ''; + + const { delay = 0 } = params; + + if (+delay) { + await setTimeoutAsync(+delay); + } + + switch (parsed.pathname.replace(/\/$/, '')) { + case '/echo/json': + default: + if (contentType.startsWith('multipart/')) { + const { fields, files } = await handleFormData(req); + response.form = fields; + response.files = files; + } else { + response.body = (await getStream(req, { encoding: 'buffer' })).toString('hex'); + } + + return { + body: response, + }; + } + }; + + return await startHTTPServer( + (req, res) => { + res.setHeader('Access-Control-Allow-Origin', `*`); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', '*'); + res.setHeader('Access-Control-Max-Age', '86400'); + + if (req.method === 'OPTIONS') { + res.writeHead(204); + res.end(); + return; + } + + Promise.resolve(handler(req, res)).then((result) => { + const { status = 200, headers = {}, body } = result || {}; + + res.statusCode = status; + + Object.entries(headers).forEach(([header, value]) => { + res.setHeader(header, value); + }); + + res.end(JSON.stringify(body, null, 2)); + }); + }, + { port } + ); +}; diff --git a/tests/setup/unit.setup.js b/tests/setup/unit.setup.js new file mode 100644 index 0000000000..efdf84912e --- /dev/null +++ b/tests/setup/unit.setup.js @@ -0,0 +1,6 @@ +import { afterEach } from 'vitest'; +import { stopAllTrackedHTTPServers } from './server.js'; + +afterEach(async () => { + await stopAllTrackedHTTPServers(); +}); diff --git a/tests/unit/adapters/adapters.test.js b/tests/unit/adapters/adapters.test.js new file mode 100644 index 0000000000..32af566dc4 --- /dev/null +++ b/tests/unit/adapters/adapters.test.js @@ -0,0 +1,48 @@ +import { beforeEach, describe, it } from 'vitest'; +import assert from 'assert'; +import adapters from '../../../lib/adapters/adapters.js'; + +describe('adapters', () => { + const store = { ...adapters.adapters }; + + beforeEach(() => { + Object.keys(adapters.adapters).forEach((name) => { + delete adapters.adapters[name]; + }); + + Object.assign(adapters.adapters, store); + }); + + it('should support loading by fn handle', () => { + const adapter = () => {}; + assert.strictEqual(adapters.getAdapter(adapter), adapter); + }); + + it('should support loading by name', () => { + const adapter = () => {}; + adapters.adapters.testadapter = adapter; + assert.strictEqual(adapters.getAdapter('testAdapter'), adapter); + }); + + it('should detect adapter unavailable status', () => { + adapters.adapters.testadapter = null; + assert.throws(() => adapters.getAdapter('testAdapter'), /is not available in the build/); + }); + + it('should detect adapter unsupported status', () => { + adapters.adapters.testadapter = false; + assert.throws(() => adapters.getAdapter('testAdapter'), /is not supported by the environment/); + }); + + it('should pick suitable adapter from the list', () => { + const adapter = () => {}; + + Object.assign(adapters.adapters, { + foo: false, + bar: null, + baz: adapter, + }); + + assert.strictEqual(adapters.getAdapter(['foo', 'bar', 'baz']), adapter); + }); +}); diff --git a/tests/unit/adapters/axios.png b/tests/unit/adapters/axios.png new file mode 100644 index 0000000000000000000000000000000000000000..8511175953c2ef062ebb6d073df7715a4037a7f6 GIT binary patch literal 1716 zcmah~>08o?8pUPYQWI2~NG&GZmrRXter~w0hzld6xs*aST8Ilw)5I0G%$o~2gq9Aj zh?bO^x!gOZb*EH79nCR!YYlwPQbNjGUQ{3k;beZYCD5Qq^xPzKS25=`5G3sj z6lRG>X&{h_pPwf>oEE)$yH{v^N;4-h&!vH(W&D5?aKOq;aYQKq#$lK`t0NFlU#sG4 zF8v`6f4oOv&czT*YHGM!!9=O9WWs)}peQSg`?^Cu--(hr(QFEVgOvquL|Kx*i|{Fu zVAt(*@d?+xvrvlL)t|w;yKm=Oq)#vR?ACnaX2TL=5jn|d@WqsC+p^#nzmVHe507o( zAb*~2gbvuPVkq<-G1szZXF2tvKg91b3!82GO5oTihF#A^n{Ipv&~)g}M$ zI=N2opw}&oJ;1mzRW6I<&CW2bi!iTpor4LIfu`V>f-C`>3~?N)Fj9^Bge=1F7?`+J zS?#wLH;Z%4sI{4T7Ut{H;j6Z9#g@Idrt=pY={NA1S(YJ?*zYDhvNt4?cLBhf*+tKE zRNVR@sMjcX3oZ}57O<^JrQE>nDatjwl7iysfq@;jR(Zn_M0%2fa+}KP*o*=4;rU8E zwT6?%UNrM>J$i%Fa(hl9ez~%YGbWL!~VHXG$hwYt#d- zF;#~1L%S#0W=Lk{_1f<6eKu5Rny`rhYlK%WAZ(2(n8p-06eb_HWU2`VF^1i(>HoUY z*=CJN7(C-5PzdAI=6bZmcZ_a(5&+_Q1M0!O)n2_sim+aZx~aUO#Dp-Xz?a6$0p?iq`v_>j?oI2lm-2_9TM&&C`k( ztP2t2o?%#Yc7nCmk|gbOtH(rQXC$@!W!dX9<~z3BfWd{8^QvD?InI;2wI}0{I#oQZE^Tg%ai2EibVx}3FI~> zF}a=w%+C?AnG*NewY${=_#^BU}zQt*t zQSR$-LIXvI!o3MXl)t#w|Gh1q_pT8uN9VtaURnXCn zPciy;3V>I^gDpsz+Ww5iScNF}g$WlkuX_CI#{m&UhnaoJTGUFUxl*+O&JUmB2~7sj*MJ(lr* D`%5b= literal 0 HcmV?d00001 diff --git a/tests/unit/adapters/cert.pem b/tests/unit/adapters/cert.pem new file mode 100644 index 0000000000..42dcc29b0d --- /dev/null +++ b/tests/unit/adapters/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCCQDbqELLwgbPdDANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMjAwNjI2MjIxMTQ3WhcNNDcxMTExMjIxMTQ3WjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD6 +Ogt99/dZ0UgbCuVV1RZ9n28Ov3DzrJCkjperQoXomIq3Fr4RUI1a2rwe3mtl3UzE +1IVZVvWPGdEsEQHwXfAsP/jFGTwI3HDyOhcqzFQSKsjvqJWYkOOb+2r3SBrFlRZW +09k/3lC+hx2XtuuG68u4Xgn3AlUvm2vplgCN7eiYcGeNwVuf2eHdOqTRTqiYCZLi +T8GtdYMDXOrwsGZs/jUKd9U0ar/lqwMhmw07yzlVDM2MWM2tyq/asQ7Sf7vuoMFu +oAtDJ3E+bK1k/7SNhdyP4RonhyUCkWG+mzoKDS1qgXroTiQSDUksAvOCTcj8BNIT +ee+Lcn9FaTKNJiKiU9q/AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFi5ZpaUj+mU +dsgOka+j2/njgNXux3cOjhm7z/N7LeTuDENAOrYa5b+j5JX/YM7RKHrkbXHsQbfs +GB3ufH6QhSiCd/AdsXp/TbCE/8gdq8ykkjwVP1bvBle9oPH7x1aO/WP/odsepYUv +o9aOZW4iNQVmwamU62ezglf3QD7HPeE4LnZueaFtuzRoC+aWT9v0MIeUPJLe3WDQ +FEySwUuthMDJEv92/TeK0YOiunmseCu2mvdiDj6E3C9xa5q2DWgl+msu7+bPgvYO +GuWaoNeQQGk7ebBO3Hk3IyaGx6Cbd8ty+YaZW7dUT+m7KCs1VkxdcDMjZJVWiJy4 +4HcEcKboG4Y= +-----END CERTIFICATE----- diff --git a/tests/unit/adapters/error-details.test.js b/tests/unit/adapters/error-details.test.js new file mode 100644 index 0000000000..479c3221d9 --- /dev/null +++ b/tests/unit/adapters/error-details.test.js @@ -0,0 +1,83 @@ +import { describe, it } from 'vitest'; +import assert from 'assert'; +import https from 'https'; +import net from 'net'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import axios from '../../../index.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +async function getClosedPort() { + return await new Promise((resolve) => { + const srv = net.createServer(); + srv.listen(0, '127.0.0.1', () => { + const { port } = srv.address(); + srv.close(() => resolve(port)); + }); + }); +} + +describe('adapters - network-error details', () => { + it('should expose ECONNREFUSED and set error.cause on connection refusal', async () => { + const port = await getClosedPort(); + + try { + await axios.get(`http://127.0.0.1:${port}`, { timeout: 500 }); + assert.fail('request unexpectedly succeeded'); + } catch (err) { + assert.ok(err instanceof Error, 'should be an Error'); + assert.strictEqual(err.isAxiosError, true, 'isAxiosError should be true'); + + assert.strictEqual(err.code, 'ECONNREFUSED'); + assert.ok('cause' in err, 'error.cause should exist'); + assert.ok(err.cause instanceof Error, 'cause should be an Error'); + assert.strictEqual(err.cause && err.cause.code, 'ECONNREFUSED'); + + assert.strictEqual(typeof err.message, 'string'); + } + }); + + it('should expose self-signed TLS error and set error.cause', async () => { + const certsDir = path.resolve(__dirname, '../../../test/unit/adapters'); + const keyPath = path.join(certsDir, 'key.pem'); + const certPath = path.join(certsDir, 'cert.pem'); + + const key = fs.readFileSync(keyPath); + const cert = fs.readFileSync(certPath); + + const httpsServer = https.createServer({ key, cert }, (req, res) => res.end('ok')); + + await new Promise((resolve) => httpsServer.listen(0, '127.0.0.1', resolve)); + const { port } = httpsServer.address(); + + try { + await axios.get(`https://127.0.0.1:${port}`, { + timeout: 500, + httpsAgent: new https.Agent({ rejectUnauthorized: true }), + }); + assert.fail('request unexpectedly succeeded'); + } catch (err) { + const codeStr = String(err.code); + assert.ok( + /SELF_SIGNED|UNABLE_TO_VERIFY_LEAF_SIGNATURE|DEPTH_ZERO/.test(codeStr), + `unexpected TLS code: ${codeStr}` + ); + + assert.ok('cause' in err, 'error.cause should exist'); + assert.ok(err.cause instanceof Error, 'cause should be an Error'); + + const causeCode = String(err.cause && err.cause.code); + assert.ok( + /SELF_SIGNED|UNABLE_TO_VERIFY_LEAF_SIGNATURE|DEPTH_ZERO/.test(causeCode), + `unexpected cause code: ${causeCode}` + ); + + assert.strictEqual(typeof err.message, 'string'); + } finally { + await new Promise((resolve) => httpsServer.close(resolve)); + } + }); +}); diff --git a/tests/unit/adapters/fetch.test.js b/tests/unit/adapters/fetch.test.js new file mode 100644 index 0000000000..08a620c293 --- /dev/null +++ b/tests/unit/adapters/fetch.test.js @@ -0,0 +1,531 @@ +import { afterEach, describe, it, vi } from 'vitest'; +import assert from 'assert'; +import { + startHTTPServer, + stopHTTPServer, + LOCAL_SERVER_URL, + setTimeoutAsync, + makeReadableStream, + generateReadable, + makeEchoStream, +} from '../../setup/server.js'; +import axios from '../../../index.js'; +import stream from 'stream'; +import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; +import util from 'util'; +import NodeFormData from 'form-data'; + +const pipelineAsync = util.promisify(stream.pipeline); + +const fetchAxios = axios.create({ + baseURL: LOCAL_SERVER_URL, + adapter: 'fetch', +}); + +let server; + +describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () => { + afterEach(async () => { + await stopHTTPServer(server); + + server = null; + }); + + describe('responses', () => { + it('should support text response type', async () => { + const originalData = 'my data'; + + server = await startHTTPServer((req, res) => res.end(originalData)); + + const { data } = await fetchAxios.get('/', { + responseType: 'text', + }); + + assert.deepStrictEqual(data, originalData); + }); + + it('should support arraybuffer response type', async () => { + const originalData = 'my data'; + + server = await startHTTPServer((req, res) => res.end(originalData)); + + const { data } = await fetchAxios.get('/', { + responseType: 'arraybuffer', + }); + + assert.deepStrictEqual( + data, + Uint8Array.from(await new TextEncoder().encode(originalData)).buffer + ); + }); + + it('should support blob response type', async () => { + const originalData = 'my data'; + + server = await startHTTPServer((req, res) => res.end(originalData)); + + const { data } = await fetchAxios.get('/', { + responseType: 'blob', + }); + + assert.deepStrictEqual(data, new Blob([originalData])); + }); + + it('should support stream response type', async () => { + const originalData = 'my data'; + + server = await startHTTPServer((req, res) => res.end(originalData)); + + const { data } = await fetchAxios.get('/', { + responseType: 'stream', + }); + + assert.ok(data instanceof ReadableStream, 'data is not instanceof ReadableStream'); + + const response = new Response(data); + + assert.deepStrictEqual(await response.text(), originalData); + }); + + it('should support formData response type', async () => { + const originalData = new FormData(); + + originalData.append('x', '123'); + + server = await startHTTPServer(async (req, res) => { + const response = await new Response(originalData); + + res.setHeader('Content-Type', response.headers.get('Content-Type')); + + res.end(await response.text()); + }); + + const { data } = await fetchAxios.get('/', { + responseType: 'formdata', + }); + + assert.ok(data instanceof FormData, 'data is not instanceof FormData'); + + assert.deepStrictEqual( + Object.fromEntries(data.entries()), + Object.fromEntries(originalData.entries()) + ); + }, 5000); + + it('should support json response type', async () => { + const originalData = { x: 'my data' }; + + server = await startHTTPServer((req, res) => res.end(JSON.stringify(originalData))); + + const { data } = await fetchAxios.get('/', { + responseType: 'json', + }); + + assert.deepStrictEqual(data, originalData); + }); + }); + + describe('progress', () => { + describe('upload', () => { + it('should support upload progress capturing', async () => { + server = await startHTTPServer({ + rate: 100 * 1024, + }); + + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + const readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await fetchAxios.post('/', readable, { + onUploadProgress: ({ loaded, total, progress, bytes, upload }) => { + console.log( + `Upload Progress ${loaded} from ${total} bytes (${(progress * 100).toFixed(1)}%)` + ); + + samples.push({ + loaded, + total, + progress, + bytes, + upload, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + }); + + await setTimeoutAsync(500); + + assert.strictEqual(data, content); + + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + upload: true, + }; + } + })() + ) + ); + }, 15000); + + it('should not fail with get method', async () => { + server = await startHTTPServer((req, res) => res.end('OK')); + + const { data } = await fetchAxios.get('/', { + onUploadProgress() {}, + }); + + assert.strictEqual(data, 'OK'); + }); + }); + + describe('download', () => { + it('should support download progress capturing', async () => { + server = await startHTTPServer({ + rate: 100 * 1024, + }); + + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + const readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await fetchAxios.post('/', readable, { + onDownloadProgress: ({ loaded, total, progress, bytes, download }) => { + console.log( + `Download Progress ${loaded} from ${total} bytes (${(progress * 100).toFixed(1)}%)` + ); + + samples.push({ + loaded, + total, + progress, + bytes, + download, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + maxRedirects: 0, + }); + + await setTimeoutAsync(500); + + assert.strictEqual(data, content); + + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + download: true, + }; + } + })() + ) + ); + }, 15000); + }); + }); + + it('should support basic auth', async () => { + server = await startHTTPServer((req, res) => res.end(req.headers.authorization)); + + const user = 'foo'; + const headers = { Authorization: 'Bearer 1234' }; + const res = await axios.get(`http://${user}@localhost:4444/`, { headers }); + + const base64 = Buffer.from(`${user}:`, 'utf8').toString('base64'); + assert.equal(res.data, `Basic ${base64}`); + }); + + it('should support stream.Readable as a payload', async () => { + server = await startHTTPServer(); + + const { data } = await fetchAxios.post('/', stream.Readable.from('OK')); + + assert.strictEqual(data, 'OK'); + }); + + describe('request aborting', () => { + it('should be able to abort the request stream', async () => { + server = await startHTTPServer({ + rate: 100000, + useBuffering: true, + }); + + const controller = new AbortController(); + + setTimeout(() => { + controller.abort(); + }, 500); + + await assert.rejects(async () => { + await fetchAxios.post('/', makeReadableStream(), { + responseType: 'stream', + signal: controller.signal, + }); + }, /CanceledError/); + }); + + it('should be able to abort the response stream', async () => { + server = await startHTTPServer((req, res) => { + pipelineAsync(generateReadable(10000, 10), res).catch(() => { + // Client-side abort intentionally closes the stream early in this test. + }); + }); + + const controller = new AbortController(); + + setTimeout(() => { + controller.abort(new Error('test')); + }, 800); + + const { data } = await fetchAxios.get('/', { + responseType: 'stream', + signal: controller.signal, + }); + + await assert.rejects(async () => { + await data.pipeTo(makeEchoStream()); + }, /^(AbortError|CanceledError):/); + }); + }); + + it('should support a timeout', async () => { + server = await startHTTPServer(async (req, res) => { + await setTimeoutAsync(1000); + res.end('OK'); + }); + + const timeout = 500; + + const ts = Date.now(); + + await assert.rejects(async () => { + await fetchAxios('/', { + timeout, + }); + }, /timeout/); + + const passed = Date.now() - ts; + + assert.ok(passed >= timeout - 5, `early cancellation detected (${passed} ms)`); + }); + + it('should combine baseURL and url', async () => { + server = await startHTTPServer(); + + const res = await fetchAxios('/foo'); + + assert.equal(res.config.baseURL, LOCAL_SERVER_URL); + assert.equal(res.config.url, '/foo'); + }); + + it('should support params', async () => { + server = await startHTTPServer((req, res) => res.end(req.url)); + + const { data } = await fetchAxios.get('/?test=1', { + params: { + foo: 1, + bar: 2, + }, + }); + + assert.strictEqual(data, '/?test=1&foo=1&bar=2'); + }); + + it('should handle fetch failed error as an AxiosError with ERR_NETWORK code', async () => { + try { + await fetchAxios('http://notExistsUrl.in.nowhere'); + assert.fail('should fail'); + } catch (err) { + assert.strictEqual(String(err), 'AxiosError: Network Error'); + assert.strictEqual(err.cause && err.cause.code, 'ENOTFOUND'); + } + }); + + it('should get response headers', async () => { + server = await startHTTPServer((req, res) => { + res.setHeader('foo', 'bar'); + res.end(req.url); + }); + + const { headers } = await fetchAxios.get('/', { + responseType: 'stream', + }); + + assert.strictEqual(headers.get('foo'), 'bar'); + }); + + describe('fetch adapter - Content-Type handling', () => { + it('should set correct Content-Type for FormData automatically', async () => { + const form = new NodeFormData(); + form.append('foo', 'bar'); + + server = await startHTTPServer((req, res) => { + const contentType = req.headers['content-type']; + assert.match(contentType, /^multipart\/form-data; boundary=/i); + res.end('OK'); + }); + + await fetchAxios.post('/form', form); + }); + }); + + describe('env config', () => { + it('should respect env fetch API configuration', async () => { + const { data, headers } = await fetchAxios.get('/', { + env: { + fetch() { + return { + headers: { + foo: '1', + }, + text: async () => 'test', + }; + }, + }, + }); + + assert.strictEqual(headers.get('foo'), '1'); + assert.strictEqual(data, 'test'); + }); + + it('should be able to request with lack of Request object', async () => { + const form = new FormData(); + + form.append('x', '1'); + + const { data, headers } = await fetchAxios.post('/', form, { + onUploadProgress() { + // dummy listener to activate streaming + }, + env: { + Request: null, + fetch() { + return { + headers: { + foo: '1', + }, + text: async () => 'test', + }; + }, + }, + }); + + assert.strictEqual(headers.get('foo'), '1'); + assert.strictEqual(data, 'test'); + }); + + it('should be able to handle response with lack of Response object', async () => { + const { data, headers } = await fetchAxios.get('/', { + onDownloadProgress() { + // dummy listener to activate streaming + }, + env: { + Request: null, + Response: null, + fetch() { + return { + headers: { + foo: '1', + }, + text: async () => 'test', + }; + }, + }, + }); + + assert.strictEqual(headers.get('foo'), '1'); + assert.strictEqual(data, 'test'); + }); + + it('should fallback to the global on undefined env value', async () => { + server = await startHTTPServer((req, res) => res.end('OK')); + + const { data } = await fetchAxios.get('/', { + env: { + fetch: undefined, + }, + }); + + assert.strictEqual(data, 'OK'); + }); + + it('should use current global fetch when env fetch is not specified', async () => { + const globalFetch = global.fetch; + + vi.stubGlobal('fetch', async () => { + return { + headers: { + foo: '1', + }, + text: async () => 'global', + }; + }); + + try { + server = await startHTTPServer((req, res) => res.end('OK')); + + const { data } = await fetchAxios.get('/', { + env: { + fetch: undefined, + }, + }); + + assert.strictEqual(data, 'global'); + } finally { + vi.stubGlobal('fetch', globalFetch); + } + }); + }); +}); diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js new file mode 100644 index 0000000000..b72f68477e --- /dev/null +++ b/tests/unit/adapters/http.test.js @@ -0,0 +1,3114 @@ +import { afterEach, describe, it as vitestIt } from 'vitest'; +import axios from '../../../index.js'; +import http from 'http'; +import https from 'https'; +import net from 'net'; +import url from 'url'; +import zlib from 'zlib'; +import stream from 'stream'; +import util from 'util'; +import assert from 'assert'; +import fs from 'fs'; +import path from 'path'; +import { lookup } from 'dns'; +let server, server2, proxy; +import AxiosError from '../../../lib/core/AxiosError.js'; +import FormDataLegacy from 'form-data'; +import formidable from 'formidable'; +import express from 'express'; +import multer from 'multer'; +import bodyParser from 'body-parser'; +const isBlobSupported = typeof Blob !== 'undefined'; +import devNull from 'dev-null'; +import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; +import { __setProxy } from '../../../lib/adapters/http.js'; +import { + FormData as FormDataPolyfill, + Blob as BlobPolyfill, + File as FilePolyfill, +} from 'formdata-node'; +import getStream from 'get-stream'; +import { + startHTTPServer, + stopHTTPServer, + LOCAL_SERVER_URL, + SERVER_HANDLER_STREAM_ECHO, + handleFormData, + generateReadable, +} from '../../setup/server.js'; + +const LOCAL_SERVER_URL2 = 'https://localhost:5555'; +const SERVER_PORT = 4444; +const SERVER_PORT2 = 5555; + +const FormDataSpecCompliant = typeof FormData !== 'undefined' ? FormData : FormDataPolyfill; +const BlobSpecCompliant = typeof Blob !== 'undefined' ? Blob : BlobPolyfill; +const FileSpecCompliant = typeof File !== 'undefined' ? File : FilePolyfill; + +const __filename = url.fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +function setTimeoutAsync(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +const pipelineAsync = util.promisify(stream.pipeline); +const finishedAsync = util.promisify(stream.finished); +const gzip = util.promisify(zlib.gzip); +const deflate = util.promisify(zlib.deflate); +const deflateRaw = util.promisify(zlib.deflateRaw); +const brotliCompress = util.promisify(zlib.brotliCompress); + +function toleranceRange(positive, negative) { + const p = 1 + positive / 100; + const n = 1 - negative / 100; + + return (actualValue, value) => { + return actualValue > value ? actualValue <= value * p : actualValue >= value * n; + }; +} + +const nodeVersion = process.versions.node.split('.').map((v) => parseInt(v, 10)); +const nodeMajorVersion = nodeVersion[0]; + +var noop = () => {}; + +const wrapDoneCallback = (testFn) => { + if (typeof testFn !== 'function' || testFn.length === 0) { + return testFn; + } + + return () => + new Promise((resolve, reject) => { + let settled = false; + + const done = (err) => { + if (settled) { + return; + } + + settled = true; + err ? reject(err) : resolve(); + }; + + try { + const maybePromise = testFn(done); + + if (maybePromise && typeof maybePromise.then === 'function') { + maybePromise.then(() => done(), done); + } + } catch (err) { + done(err); + } + }); +}; + +const it = (name, testFn, timeout) => vitestIt(name, wrapDoneCallback(testFn), timeout); +it.skip = (name, testFn, timeout) => vitestIt.skip(name, wrapDoneCallback(testFn), timeout); + +describe('supports http with nodejs', function () { + afterEach(async function () { + await Promise.all([stopHTTPServer(server), stopHTTPServer(server2), stopHTTPServer(proxy)]); + + server = null; + server2 = null; + proxy = null; + + delete process.env.http_proxy; + delete process.env.https_proxy; + delete process.env.no_proxy; + }); + + it('should support IPv4 literal strings', function (done) { + var data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }) + .listen(4444, function () { + axios + .get('http://127.0.0.1:4444/') + .then(function (res) { + assert.deepEqual(res.data, data); + done(); + }) + .catch(done); + }); + }); + + it('should support IPv6 literal strings', function (done) { + var data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }) + .listen(4444, function () { + axios + .get('http://[::1]:4444/') + .then(function (res) { + assert.deepEqual(res.data, data); + done(); + }) + .catch(done); + }); + }); + + it('should throw an error if the timeout property is not parsable as a number', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + var success = false, + failure = false; + var error; + + axios + .get('http://localhost:4444/', { + timeout: { strangeTimeout: 250 }, + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.code, AxiosError.ERR_BAD_OPTION_VALUE); + assert.equal(error.message, 'error trying to parse `config.timeout` to int'); + done(); + }, 300); + }); + }); + + it('should parse the timeout property', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + var success = false, + failure = false; + var error; + + axios + .get('http://localhost:4444/', { + timeout: '250', + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.code, 'ECONNABORTED'); + assert.equal(error.message, 'timeout of 250ms exceeded'); + done(); + }, 300); + }); + }); + + it('should respect the timeout property', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + var success = false, + failure = false; + var error; + + axios + .get('http://localhost:4444/', { + timeout: 250, + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.code, 'ECONNABORTED'); + assert.equal(error.message, 'timeout of 250ms exceeded'); + done(); + }, 300); + }); + }); + + it('should respect the timeoutErrorMessage property', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + var success = false, + failure = false; + var error; + + axios + .get('http://localhost:4444/', { + timeout: 250, + timeoutErrorMessage: 'oops, timeout', + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.strictEqual(success, false, 'request should not succeed'); + assert.strictEqual(failure, true, 'request should fail'); + assert.strictEqual(error.code, 'ECONNABORTED'); + assert.strictEqual(error.message, 'oops, timeout'); + done(); + }, 300); + }); + }); + + it('should allow passing JSON', function (done) { + var data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.deepEqual(res.data, data); + done(); + }) + .catch(done); + }); + }); + + it('should allow passing JSON with BOM', function (done) { + var data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'application/json'); + var bomBuffer = Buffer.from([0xef, 0xbb, 0xbf]); + var jsonBuffer = Buffer.from(JSON.stringify(data)); + res.end(Buffer.concat([bomBuffer, jsonBuffer])); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.deepEqual(res.data, data); + done(); + }) + .catch(done); + }); + }); + + it('should redirect', function (done) { + var str = 'test response'; + + server = http + .createServer(function (req, res) { + var parsed = url.parse(req.url); + + if (parsed.pathname === '/one') { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + } else { + res.end(str); + } + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/one') + .then(function (res) { + assert.equal(res.data, str); + assert.equal(res.request.path, '/two'); + done(); + }) + .catch(done); + }); + }); + + it('should not redirect', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + maxRedirects: 0, + validateStatus: function () { + return true; + }, + }) + .then(function (res) { + assert.equal(res.status, 302); + assert.equal(res.headers['location'], '/foo'); + done(); + }) + .catch(done); + }); + }); + + it('should support max redirects', function (done) { + var i = 1; + server = http + .createServer(function (req, res) { + res.setHeader('Location', '/' + i); + res.statusCode = 302; + res.end(); + i++; + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + maxRedirects: 3, + }) + .catch(function (error) { + assert.equal(error.code, AxiosError.ERR_FR_TOO_MANY_REDIRECTS); + assert.equal(error.message, 'Maximum number of redirects exceeded'); + done(); + }) + .catch(done); + }); + }); + + it('should support beforeRedirect', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + maxRedirects: 3, + beforeRedirect: function (options, responseDetails) { + if (options.path === '/foo' && responseDetails.headers.location === '/foo') { + throw new Error('Provided path is not allowed'); + } + }, + }) + .catch(function (error) { + assert.equal(error.message, 'Redirected request failed: Provided path is not allowed'); + done(); + }) + .catch(done); + }); + }); + + it('should support beforeRedirect and proxy with redirect', async () => { + let requestCount = 0; + let totalRedirectCount = 5; + + server = await startHTTPServer( + function (req, res) { + requestCount += 1; + if (requestCount <= totalRedirectCount) { + res.setHeader('Location', 'http://localhost:4444'); + res.writeHead(302); + } + res.end(); + }, + { port: 4444 } + ); + + let proxyUseCount = 0; + proxy = await startHTTPServer( + function (req, res) { + proxyUseCount += 1; + const targetUrl = new URL(req.url, 'http://' + req.headers.host); + const opts = { + host: targetUrl.hostname, + port: targetUrl.port, + path: targetUrl.path, + method: req.method, + }; + + const request = http.get(opts, function (response) { + res.writeHead(response.statusCode, response.headers); + stream.pipeline(response, res, () => {}); + }); + + request.on('error', (err) => { + console.warn('request error', err); + res.statusCode = 500; + res.end(); + }); + }, + { port: 4000 } + ); + + let configBeforeRedirectCount = 0; + + await axios + .get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + }, + maxRedirects: totalRedirectCount, + beforeRedirect: function (options) { + configBeforeRedirectCount += 1; + }, + }) + .then(function (res) { + assert.equal( + totalRedirectCount, + configBeforeRedirectCount, + 'should invoke config.beforeRedirect option on every redirect' + ); + assert.equal( + totalRedirectCount + 1, + proxyUseCount, + 'should go through proxy on every redirect' + ); + }); + }); + + it('should wrap HTTP errors and keep stack', async function () { + if (nodeMajorVersion <= 12) { + return; // node 12 support for async stack traces appears lacking + return; + } + + server = await startHTTPServer((req, res) => { + res.statusCode = 400; + res.end(); + }); + + return assert.rejects( + async function findMeInStackTrace() { + await axios.head('http://localhost:4444/one'); + }, + function (err) { + assert.equal(err.name, 'AxiosError'); + assert.equal(err.isAxiosError, true); + const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]; + assert.equal(matches.length, 1, err.stack); + return true; + } + ); + }); + + it('should wrap interceptor errors and keep stack', function (done) { + if (nodeMajorVersion <= 12) { + return; // node 12 support for async stack traces appears lacking + return; + } + const axiosInstance = axios.create(); + axiosInstance.interceptors.request.use((res) => { + throw new Error('from request interceptor'); + }); + server = http + .createServer(function (req, res) { + res.end(); + }) + .listen(4444, function () { + void assert + .rejects( + async function findMeInStackTrace() { + await axiosInstance.get('http://localhost:4444/one'); + }, + function (err) { + assert.equal(err.name, 'Error'); + assert.equal(err.message, 'from request interceptor'); + const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]; + assert.equal(matches.length, 1, err.stack); + return true; + } + ) + .then(done) + .catch(done); + }); + }); + + it('should preserve the HTTP verb on redirect', function (done) { + server = http + .createServer(function (req, res) { + if (req.method.toLowerCase() !== 'head') { + res.statusCode = 400; + res.end(); + return; + } + + var parsed = url.parse(req.url); + if (parsed.pathname === '/one') { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + } else { + res.end(); + } + }) + .listen(4444, function () { + axios + .head('http://localhost:4444/one') + .then(function (res) { + assert.equal(res.status, 200); + done(); + }) + .catch(done); + }); + }); + + describe('compression', async () => { + it('should support transparent gunzip', function (done) { + var data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + zlib.gzip(JSON.stringify(data), function (err, zipped) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.deepEqual(res.data, data); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support gunzip error handling', async () => { + server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end('invalid response'); + }); + + await assert.rejects(async () => { + await axios.get(LOCAL_SERVER_URL); + }); + }); + + it('should support disabling automatic decompression of response data', function (done) { + var data = 'Test data'; + + zlib.gzip(data, function (err, zipped) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html;charset=utf-8'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + decompress: false, + responseType: 'arraybuffer', + }) + .then(function (res) { + assert.equal(res.data.toString('base64'), zipped.toString('base64')); + done(); + }) + .catch(done); + }); + }); + }); + + describe('algorithms', () => { + const responseBody = 'str'; + + for (const [typeName, zipped] of Object.entries({ + gzip: gzip(responseBody), + GZIP: gzip(responseBody), + compress: gzip(responseBody), + deflate: deflate(responseBody), + 'deflate-raw': deflateRaw(responseBody), + br: brotliCompress(responseBody), + })) { + const type = typeName.split('-')[0]; + + describe(`${typeName} decompression`, async () => { + it(`should support decompression`, async () => { + server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.end(await zipped); + }); + + const { data } = await axios.get(LOCAL_SERVER_URL); + + assert.strictEqual(data, responseBody); + }); + + it(`should not fail if response content-length header is missing (${type})`, async () => { + server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.removeHeader('Content-Length'); + res.end(await zipped); + }); + + const { data } = await axios.get(LOCAL_SERVER_URL); + + assert.strictEqual(data, responseBody); + }); + + it('should not fail with chunked responses (without Content-Length header)', async () => { + server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.setHeader('Transfer-Encoding', 'chunked'); + res.removeHeader('Content-Length'); + res.write(await zipped); + res.end(); + }); + + const { data } = await axios.get(LOCAL_SERVER_URL); + + assert.strictEqual(data, responseBody); + }); + + it('should not fail with an empty response without content-length header (Z_BUF_ERROR)', async () => { + server = await startHTTPServer((req, res) => { + res.setHeader('Content-Encoding', type); + res.removeHeader('Content-Length'); + res.end(); + }); + + const { data } = await axios.get(LOCAL_SERVER_URL); + + assert.strictEqual(data, ''); + }); + + it('should not fail with an empty response with content-length header (Z_BUF_ERROR)', async () => { + server = await startHTTPServer((req, res) => { + res.setHeader('Content-Encoding', type); + res.end(); + }); + + await axios.get(LOCAL_SERVER_URL); + }); + }); + } + }); + }); + + it('should support UTF8', function (done) { + var str = Array(100000).join('ж'); + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.equal(res.data, str); + done(); + }) + .catch(done); + }); + }); + + it('should support basic auth', function (done) { + server = http + .createServer(function (req, res) { + res.end(req.headers.authorization); + }) + .listen(4444, function () { + var user = 'foo'; + var headers = { Authorization: 'Bearer 1234' }; + axios + .get('http://' + user + '@localhost:4444/', { headers: headers }) + .then(function (res) { + var base64 = Buffer.from(user + ':', 'utf8').toString('base64'); + assert.equal(res.data, 'Basic ' + base64); + done(); + }) + .catch(done); + }); + }); + + it('should support basic auth with a header', function (done) { + server = http + .createServer(function (req, res) { + res.end(req.headers.authorization); + }) + .listen(4444, function () { + var auth = { username: 'foo', password: 'bar' }; + var headers = { AuThOrIzAtIoN: 'Bearer 1234' }; // wonky casing to ensure caseless comparison + axios + .get('http://localhost:4444/', { auth: auth, headers: headers }) + .then(function (res) { + var base64 = Buffer.from('foo:bar', 'utf8').toString('base64'); + assert.equal(res.data, 'Basic ' + base64); + done(); + }) + .catch(done); + }); + }); + + it('should provides a default User-Agent header', function (done) { + server = http + .createServer(function (req, res) { + res.end(req.headers['user-agent']); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.ok( + /^axios\/[\d.]+[-]?[a-z]*[.]?[\d]+$/.test(res.data), + `User-Agent header does not match: ${res.data}` + ); + done(); + }) + .catch(done); + }); + }); + + it('should allow the User-Agent header to be overridden', function (done) { + server = http + .createServer(function (req, res) { + res.end(req.headers['user-agent']); + }) + .listen(4444, function () { + var headers = { 'UsEr-AgEnT': 'foo bar' }; // wonky casing to ensure caseless comparison + axios + .get('http://localhost:4444/', { headers }) + .then(function (res) { + assert.equal(res.data, 'foo bar'); + done(); + }) + .catch(done); + }); + }); + + it('should allow the Content-Length header to be overridden', function (done) { + server = http + .createServer(function (req, res) { + assert.strictEqual(req.headers['content-length'], '42'); + res.end(); + }) + .listen(4444, function () { + var headers = { 'CoNtEnT-lEnGtH': '42' }; // wonky casing to ensure caseless comparison + axios + .post('http://localhost:4444/', 'foo', { headers }) + .then(function () { + done(); + }) + .catch(done); + }); + }); + + it('should support max content length', async function () { + server = await startHTTPServer( + function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(Array(5000).join('#')); + }, + { port: 4444 } + ); + + await assert.rejects(() => { + return axios.get('http://localhost:4444/', { + maxContentLength: 2000, + maxRedirects: 0, + }); + }, /maxContentLength size of 2000 exceeded/); + }); + + it('should support max content length for redirected', function (done) { + var str = Array(100000).join('ж'); + + server = http + .createServer(function (req, res) { + var parsed = url.parse(req.url); + + if (parsed.pathname === '/two') { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + } else { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + } + }) + .listen(4444, function () { + var success = false, + failure = false, + error; + + axios + .get('http://localhost:4444/one', { + maxContentLength: 2000, + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.message, 'maxContentLength size of 2000 exceeded'); + done(); + }, 100); + }); + }); + + it('should support max body length', function (done) { + var data = Array(100000).join('ж'); + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(); + }) + .listen(4444, function () { + var success = false, + failure = false, + error; + + axios + .post( + 'http://localhost:4444/', + { + data: data, + }, + { + maxBodyLength: 2000, + } + ) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.message, 'Request body larger than maxBodyLength limit'); + done(); + }, 100); + }); + }); + + it('should properly support default max body length (follow-redirects as well)', function (done) { + // taken from https://github.com/follow-redirects/follow-redirects/blob/22e81fc37132941fb83939d1dc4c2282b5c69521/index.js#L461 + var followRedirectsMaxBodyDefaults = 10 * 1024 * 1024; + var data = Array(2 * followRedirectsMaxBodyDefaults).join('ж'); + + server = http + .createServer(function (req, res) { + // consume the req stream + req.on('data', noop); + // and wait for the end before responding, otherwise an ECONNRESET error will be thrown + req.on('end', () => { + res.end('OK'); + }); + }) + .listen(4444, function (err) { + if (err) { + return done(err); + } + // send using the default -1 (unlimited axios maxBodyLength) + axios + .post('http://localhost:4444/', { + data: data, + }) + .then(function (res) { + assert.equal(res.data, 'OK', 'should handle response'); + done(); + }) + .catch(done); + }); + }); + + it('should display error while parsing params', function (done) { + server = http + .createServer(function () {}) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + params: { + errorParam: new Date(undefined), + }, + }) + .catch(function (err) { + assert.deepEqual(err.exists, true); + done(); + }) + .catch(done); + }); + }); + + it('should support sockets', function (done) { + // Different sockets for win32 vs darwin/linux + var socketName = './test.sock'; + + if (process.platform === 'win32') { + socketName = '\\\\.\\pipe\\libuv-test'; + } + + server = net + .createServer(function (socket) { + socket.on('data', function () { + socket.end('HTTP/1.1 200 OK\r\n\r\n'); + }); + }) + .listen(socketName, function () { + axios({ + socketPath: socketName, + url: 'http://localhost:4444/socket', + }) + .then(function (resp) { + assert.equal(resp.status, 200); + assert.equal(resp.statusText, 'OK'); + done(); + }) + .catch(done); + }); + }); + + describe('streams', function () { + it('should support streams', function (done) { + server = http + .createServer(function (req, res) { + req.pipe(res); + }) + .listen(4444, function () { + axios + .post('http://localhost:4444/', fs.createReadStream(__filename), { + responseType: 'stream', + }) + .then(function (res) { + var stream = res.data; + var string = ''; + stream.on('data', function (chunk) { + string += chunk.toString('utf8'); + }); + stream.on('end', function () { + assert.equal(string, fs.readFileSync(__filename, 'utf8')); + done(); + }); + }) + .catch(done); + }); + }); + + it('should pass errors for a failed stream', async function () { + server = await startHTTPServer(); + + var notExitPath = path.join(__dirname, 'does_not_exist'); + + try { + await axios.post(LOCAL_SERVER_URL, fs.createReadStream(notExitPath)); + assert.fail('expected ENOENT error'); + } catch (err) { + assert.equal(err.message, `ENOENT: no such file or directory, open \'${notExitPath}\'`); + } + }); + + it('should destroy the response stream with an error on request stream destroying', async function () { + server = await startHTTPServer(); + + let stream = generateReadable(); + + setTimeout(function () { + stream.destroy(); + }, 1000); + + const { data } = await axios.post(LOCAL_SERVER_URL, stream, { responseType: 'stream' }); + + let streamError; + + data.on('error', function (err) { + streamError = err; + }); + + try { + await pipelineAsync(data, devNull()); + assert.fail('stream was not aborted'); + } catch (e) { + console.log(`pipeline error: ${e}`); + } finally { + assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); + } + }); + }); + + it('should support buffers', function (done) { + var buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) + server = http + .createServer(function (req, res) { + assert.equal(req.headers['content-length'], buf.length.toString()); + req.pipe(res); + }) + .listen(4444, function () { + axios + .post('http://localhost:4444/', buf, { + responseType: 'stream', + }) + .then(function (res) { + var stream = res.data; + var string = ''; + stream.on('data', function (chunk) { + string += chunk.toString('utf8'); + }); + stream.on('end', function () { + assert.equal(string, buf.toString()); + done(); + }); + }) + .catch(done); + }); + }); + + it('should support HTTP proxies', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }) + .listen(4000, function () { + axios + .get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + }, + }) + .then(function (res) { + assert.equal(res.data, '123456789', 'should pass through proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support HTTPS proxies', function (done) { + var options = { + key: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/key.pem')), + cert: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/cert.pem')), + }; + + server = https + .createServer(options, function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }) + .listen(4444, function () { + proxy = https + .createServer(options, function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + protocol: parsed.protocol, + rejectUnauthorized: false, + }; + + https.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }) + .listen(4000, function () { + axios + .get('https://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + protocol: 'https:', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }) + .then(function (res) { + assert.equal(res.data, '123456789', 'should pass through proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should not pass through disabled proxy', function (done) { + // set the env variable + process.env.http_proxy = 'http://does-not-exists.example.com:4242/'; + + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('123456789'); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + proxy: false, + }) + .then(function (res) { + assert.equal(res.data, '123456789', 'should not pass through proxy'); + done(); + }) + .catch(done); + }); + }); + + it('should support proxy set via env var', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }) + .listen(4000, function () { + // set the env variable + process.env.http_proxy = 'http://localhost:4000/'; + + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.equal( + res.data, + '45671234', + 'should use proxy set by process.env.http_proxy' + ); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support HTTPS proxy set via env var', function (done) { + var options = { + key: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/key.pem')), + cert: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/cert.pem')), + }; + + server = https + .createServer(options, function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }) + .listen(4444, function () { + proxy = https + .createServer(options, function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + protocol: parsed.protocol, + rejectUnauthorized: false, + }; + + https.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }) + .listen(4000, function () { + process.env.https_proxy = 'https://localhost:4000/'; + + axios + .get('https://localhost:4444/', { + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }) + .then(function (res) { + assert.equal(res.data, '123456789', 'should pass through proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should re-evaluate proxy on redirect when proxy set via env var', function (done) { + process.env.http_proxy = 'http://localhost:4000'; + process.env.no_proxy = 'localhost:4000'; + + var proxyUseCount = 0; + + server = http + .createServer(function (req, res) { + res.setHeader('Location', 'http://localhost:4000/redirected'); + res.statusCode = 302; + res.end(); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + if (parsed.pathname === '/redirected') { + response.statusCode = 200; + response.end(); + return; + } + + proxyUseCount += 1; + + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + protocol: parsed.protocol, + rejectUnauthorized: false, + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.setHeader('Location', res.headers.location); + response.end(body); + }); + }); + }) + .listen(4000, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.equal(res.status, 200); + assert.equal(proxyUseCount, 1); + done(); + }) + .catch(done); + }); + }); + }); + + it('should not use proxy for domains in no_proxy', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }) + .listen(4000, function () { + // set the env variable + process.env.http_proxy = 'http://localhost:4000/'; + process.env.no_proxy = 'foo.com, localhost,bar.net , , quix.co'; + + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.equal(res.data, '4567', 'should not use proxy for domains in no_proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should use proxy for domains not in no_proxy', function (done) { + server = http + .createServer(function (req, res) { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }) + .listen(4000, function () { + // set the env variable + process.env.http_proxy = 'http://localhost:4000/'; + process.env.no_proxy = 'foo.com, ,bar.net , quix.co'; + + axios + .get('http://localhost:4444/') + .then(function (res) { + assert.equal(res.data, '45671234', 'should use proxy for domains not in no_proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support HTTP proxy auth', function (done) { + server = http + .createServer(function (req, res) { + res.end(); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + }) + .listen(4000, function () { + axios + .get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + auth: { + username: 'user', + password: 'pass', + }, + }, + }) + .then(function (res) { + var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); + assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support proxy auth from env', function (done) { + server = http + .createServer(function (req, res) { + res.end(); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + }) + .listen(4000, function () { + process.env.http_proxy = 'http://user:pass@localhost:4000/'; + + axios + .get('http://localhost:4444/') + .then(function (res) { + var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); + assert.equal( + res.data, + 'Basic ' + base64, + 'should authenticate to the proxy set by process.env.http_proxy' + ); + done(); + }) + .catch(done); + }); + }); + }); + + it('should support proxy auth with header', function (done) { + server = http + .createServer(function (req, res) { + res.end(); + }) + .listen(4444, function () { + proxy = http + .createServer(function (request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function (res) { + var body = ''; + res.on('data', function (data) { + body += data; + }); + res.on('end', function () { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + }) + .listen(4000, function () { + axios + .get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + auth: { + username: 'user', + password: 'pass', + }, + }, + headers: { + 'Proxy-Authorization': 'Basic abc123', + }, + }) + .then(function (res) { + var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); + assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + done(); + }) + .catch(done); + }); + }); + }); + + describe('when invalid proxy options are provided', function () { + it('should throw error', function () { + const proxy = { + protocol: 'http:', + host: 'hostname.abc.xyz', + port: 3300, + auth: { + username: '', + password: '', + }, + }; + + return axios.get('https://test-domain.abc', { proxy }).then( + function () { + assert.fail('Does not throw'); + }, + function (error) { + assert.strictEqual(error.message, 'Invalid proxy authorization'); + assert.strictEqual(error.code, 'ERR_BAD_OPTION'); + assert.deepStrictEqual(error.config.proxy, proxy); + } + ); + }); + }); + + describe('different options for direct proxy configuration (without env variables)', () => { + const destination = 'www.example.com'; + + const testCases = [ + { + description: 'hostname and trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http:', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'hostname and no trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'both hostname and host -> hostname takes precedence', + proxyConfig: { hostname: '127.0.0.1', host: '0.0.0.0', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'only host and https protocol', + proxyConfig: { host: '0.0.0.0', protocol: 'https', port: 80 }, + expectedOptions: { host: '0.0.0.0', protocol: 'https:', port: 80, path: destination }, + }, + ]; + + for (const test of testCases) { + it(test.description, () => { + const options = { headers: {}, beforeRedirects: {} }; + __setProxy(options, test.proxyConfig, destination); + for (const [key, expected] of Object.entries(test.expectedOptions)) { + assert.equal(options[key], expected); + } + }); + } + }); + + it('should support cancel', function (done) { + var source = axios.CancelToken.source(); + server = http + .createServer(function (req, res) { + // call cancel() when the request has been sent, but a response has not been received + source.cancel('Operation has been canceled.'); + }) + .listen(4444, function () { + void assert + .rejects( + async function findMeInStackTrace() { + await axios.get('http://localhost:4444/', { + cancelToken: source.token, + }); + }, + function (thrown) { + assert.ok( + thrown instanceof axios.Cancel, + 'Promise must be rejected with a CanceledError object' + ); + assert.equal(thrown.message, 'Operation has been canceled.'); + if (nodeMajorVersion > 12) { + assert.match(thrown.stack, /findMeInStackTrace/); + } + return true; + } + ) + .then(done) + .catch(done); + }); + }); + + it('should combine baseURL and url', function (done) { + server = http + .createServer(function (req, res) { + res.end(); + }) + .listen(4444, function () { + axios + .get('/foo', { + baseURL: 'http://localhost:4444/', + }) + .then(function (res) { + assert.equal(res.config.baseURL, 'http://localhost:4444/'); + assert.equal(res.config.url, '/foo'); + done(); + }) + .catch(done); + }); + }); + + it('should support HTTP protocol', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + axios.get('http://localhost:4444').then(function (res) { + assert.equal(res.request.agent.protocol, 'http:'); + done(); + }); + }); + }); + + it('should support HTTPS protocol', function (done) { + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + axios.get('https://www.google.com').then(function (res) { + assert.equal(res.request.agent.protocol, 'https:'); + done(); + }); + }); + }); + + it('should return malformed URL', function (done) { + var success = false, + failure = false; + var error; + + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + axios + .get('tel:484-695-3408') + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.message, 'Unsupported protocol tel:'); + done(); + }, 300); + }); + }); + + it('should return unsupported protocol', function (done) { + var success = false, + failure = false; + var error; + + server = http + .createServer(function (req, res) { + setTimeout(function () { + res.end(); + }, 1000); + }) + .listen(4444, function () { + axios + .get('ftp:google.com') + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }); + + setTimeout(function () { + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.message, 'Unsupported protocol ftp:'); + done(); + }, 300); + }); + }); + + it('should supply a user-agent if one is not specified', function (done) { + server = http + .createServer(function (req, res) { + assert.equal(req.headers['user-agent'], 'axios/' + axios.VERSION); + res.end(); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/') + .then(function (res) { + done(); + }) + .catch(done); + }); + }); + + it('should omit a user-agent if one is explicitly disclaimed', function (done) { + server = http + .createServer(function (req, res) { + assert.equal('user-agent' in req.headers, false); + assert.equal('User-Agent' in req.headers, false); + res.end(); + }) + .listen(4444, function () { + axios + .get('http://localhost:4444/', { + headers: { + 'User-Agent': null, + }, + }) + .then(function (res) { + done(); + }) + .catch(done); + }); + }); + + it('should throw an error if http server that aborts a chunked request', function (done) { + server = http + .createServer(function (req, res) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write('chunk 1'); + setTimeout(function () { + res.write('chunk 2'); + }, 100); + setTimeout(function () { + res.destroy(); + }, 200); + }) + .listen(4444, function () { + var success = false, + failure = false; + var error; + + axios + .get('http://localhost:4444/aborted', { + timeout: 500, + }) + .then(function (res) { + success = true; + }) + .catch(function (err) { + error = err; + failure = true; + }) + .then(function () { + assert.strictEqual(success, false, 'request should not succeed'); + assert.strictEqual(failure, true, 'request should fail'); + assert.strictEqual(error.code, 'ERR_BAD_RESPONSE'); + assert.strictEqual(error.message, 'stream has been aborted'); + done(); + }) + .catch(done); + }); + }); + + it('should able to cancel multiple requests with CancelToken', function (done) { + server = http + .createServer(function (req, res) { + res.end('ok'); + }) + .listen(4444, function () { + var CancelToken = axios.CancelToken; + var source = CancelToken.source(); + var canceledStack = []; + + var requests = [1, 2, 3, 4, 5].map(function (id) { + return axios.get('/foo/bar', { cancelToken: source.token }).catch(function (e) { + if (!axios.isCancel(e)) { + throw e; + } + + canceledStack.push(id); + }); + }); + + source.cancel('Aborted by user'); + + Promise.all(requests) + .then(function () { + assert.deepStrictEqual(canceledStack.sort(), [1, 2, 3, 4, 5]); + }) + .then(done, done); + }); + }); + + describe('FormData', function () { + describe('form-data instance (https://www.npmjs.com/package/form-data)', (done) => { + it('should allow passing FormData', function (done) { + var form = new FormDataLegacy(); + var file1 = Buffer.from('foo', 'utf8'); + const image = path.resolve(__dirname, '../../../test/unit/adapters/axios.png'); + const fileStream = fs.createReadStream(image); + + const stat = fs.statSync(image); + + form.append('foo', 'bar'); + form.append('file1', file1, { + filename: 'bar.jpg', + filepath: 'temp/bar.jpg', + contentType: 'image/jpeg', + }); + + form.append('fileStream', fileStream); + + server = http + .createServer(function (req, res) { + var receivedForm = new formidable.IncomingForm(); + + assert.ok(req.rawHeaders.find((header) => header.toLowerCase() === 'content-length')); + + receivedForm.parse(req, function (err, fields, files) { + if (err) { + return done(err); + } + + res.end( + JSON.stringify({ + fields: fields, + files: files, + }) + ); + }); + }) + .listen(4444, function () { + axios + .post('http://localhost:4444/', form, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) + .then(function (res) { + assert.deepStrictEqual(res.data.fields, { foo: 'bar' }); + + assert.strictEqual(res.data.files.file1.mimetype, 'image/jpeg'); + assert.strictEqual(res.data.files.file1.originalFilename, 'temp/bar.jpg'); + assert.strictEqual(res.data.files.file1.size, 3); + + assert.strictEqual(res.data.files.fileStream.mimetype, 'image/png'); + assert.strictEqual(res.data.files.fileStream.originalFilename, 'axios.png'); + assert.strictEqual(res.data.files.fileStream.size, stat.size); + + done(); + }) + .catch(done); + }); + }); + }); + + describe('SpecCompliant FormData', (done) => { + it('should allow passing FormData', async function () { + server = await startHTTPServer(async (req, res) => { + const { fields, files } = await handleFormData(req); + + res.end( + JSON.stringify({ + fields, + files, + }) + ); + }); + + const form = new FormDataSpecCompliant(); + + const blobContent = 'blob-content'; + + const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); + + form.append('foo1', 'bar1'); + form.append('foo2', 'bar2'); + + form.append('file1', blob); + + const { data } = await axios.post(LOCAL_SERVER_URL, form, { + maxRedirects: 0, + }); + + assert.deepStrictEqual(data.fields, { foo1: 'bar1', foo2: 'bar2' }); + + assert.deepStrictEqual(typeof data.files.file1, 'object'); + + const { size, mimetype, originalFilename } = data.files.file1; + + assert.deepStrictEqual( + { size, mimetype, originalFilename }, + { + mimetype: 'image/jpeg', + originalFilename: 'blob', + size: Buffer.from(blobContent).byteLength, + } + ); + }); + }); + + describe('toFormData helper', function () { + it('should properly serialize nested objects for parsing with multer.js (express.js)', function (done) { + var app = express(); + + var obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + obj: { x: '1', y: { z: '1' } }, + users: [ + { name: 'Peter', surname: 'griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], + }; + + app.post('/', multer().none(), function (req, res, next) { + res.send(JSON.stringify(req.body)); + }); + + server = app.listen(3001, function () { + // multer can parse the following key/value pairs to an array (indexes: null, false, true): + // arr: '1' + // arr: '2' + // ------------- + // arr[]: '1' + // arr[]: '2' + // ------------- + // arr[0]: '1' + // arr[1]: '2' + // ------------- + Promise.all( + [null, false, true].map(function (mode) { + return axios + .postForm('http://localhost:3001/', obj, { formSerializer: { indexes: mode } }) + .then(function (res) { + assert.deepStrictEqual(res.data, obj, 'Index mode ' + mode); + }); + }) + ).then(function () { + done(); + }, done); + }); + }); + }); + }); + + describe('Blob', function () { + it('should support Blob', async () => { + server = await startHTTPServer(async (req, res) => { + res.end(await getStream(req)); + }); + + const blobContent = 'blob-content'; + + const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); + + const { data } = await axios.post(LOCAL_SERVER_URL, blob, { + maxRedirects: 0, + }); + + assert.deepStrictEqual(data, blobContent); + }); + }); + + describe('URLEncoded Form', function () { + it('should post object data as url-encoded form if content-type is application/x-www-form-urlencoded', function (done) { + var app = express(); + + var obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + obj: { x: '1', y: { z: '1' } }, + users: [ + { name: 'Peter', surname: 'griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], + }; + + app.use(bodyParser.urlencoded({ extended: true })); + + app.post('/', function (req, res, next) { + res.send(JSON.stringify(req.body)); + }); + + server = app.listen(3001, function () { + return axios + .post('http://localhost:3001/', obj, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + }) + .then(function (res) { + assert.deepStrictEqual(res.data, obj); + done(); + }) + .catch(done); + }); + }); + }); + + it('should respect formSerializer config', function (done) { + const obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + }; + + const form = new URLSearchParams(); + + form.append('arr1[0]', '1'); + form.append('arr1[1]', '2'); + form.append('arr1[2]', '3'); + + form.append('arr2[0]', '1'); + form.append('arr2[1][0]', '2'); + form.append('arr2[2]', '3'); + + server = http + .createServer(function (req, res) { + req.pipe(res); + }) + .listen(3001, () => { + return axios + .post('http://localhost:3001/', obj, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + formSerializer: { + indexes: true, + }, + }) + .then(function (res) { + assert.strictEqual(res.data, form.toString()); + done(); + }) + .catch(done); + }); + }); + + describe('Data URL', function () { + it('should support requesting data URL as a Buffer', function (done) { + const buffer = Buffer.from('123'); + + const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); + + axios + .get(dataURI) + .then(({ data }) => { + assert.deepStrictEqual(data, buffer); + done(); + }) + .catch(done); + }); + + it('should support requesting data URL as a Blob (if supported by the environment)', function (done) { + if (!isBlobSupported) { + return; + return; + } + + const buffer = Buffer.from('123'); + + const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); + + axios + .get(dataURI, { responseType: 'blob' }) + .then(async ({ data }) => { + assert.strictEqual(data.type, 'application/octet-stream'); + assert.deepStrictEqual(await data.text(), '123'); + done(); + }) + .catch(done); + }); + + it('should support requesting data URL as a String (text)', function (done) { + const buffer = Buffer.from('123', 'utf-8'); + + const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); + + axios + .get(dataURI, { responseType: 'text' }) + .then(({ data }) => { + assert.deepStrictEqual(data, '123'); + done(); + }) + .catch(done); + }); + + it('should support requesting data URL as a Stream', function (done) { + const buffer = Buffer.from('123', 'utf-8'); + + const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); + + axios + .get(dataURI, { responseType: 'stream' }) + .then(({ data }) => { + var str = ''; + + data.on('data', function (response) { + str += response.toString(); + }); + + data.on('end', function () { + assert.strictEqual(str, '123'); + done(); + }); + }) + .catch(done); + }); + }); + + describe('progress', function () { + describe('upload', function () { + it('should support upload progress capturing', async function () { + server = await startHTTPServer({ + rate: 100 * 1024, + }); + + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + var readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await axios.post(LOCAL_SERVER_URL, readable, { + onUploadProgress: ({ loaded, total, progress, bytes, upload }) => { + console.log('onUploadProgress', loaded, '/', total); + samples.push({ + loaded, + total, + progress, + bytes, + upload, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + }); + + assert.strictEqual(data, content); + + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + upload: true, + }; + } + })() + ) + ); + }, 15000); + }); + + describe('download', function () { + it('should support download progress capturing', async function () { + + server = await startHTTPServer({ + rate: 100 * 1024, + }); + + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + var readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await axios.post(LOCAL_SERVER_URL, readable, { + onDownloadProgress: ({ loaded, total, progress, bytes, download }) => { + console.log('onDownloadProgress', loaded, '/', total); + samples.push({ + loaded, + total, + progress, + bytes, + download, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + maxRedirects: 0, + }); + + assert.strictEqual(data, content); + + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + download: true, + }; + } + })() + ) + ); + }, 15000); + }); + }); + + describe('Rate limit', function () { + + it('should support upload rate limit', async function () { + const secs = 10; + const configRate = 100_000; + const chunkLength = configRate * secs; + + server = await startHTTPServer(); + + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); + + const { data } = await axios.post(LOCAL_SERVER_URL, buf, { + onUploadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [configRate], + responseType: 'text', + maxRedirects: 0, + }); + + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map(({ rate }) => rate) + .join(', ')}]` + ); + + const progressTicksRate = 2; + const expectedProgress = (i + skip) / secs / progressTicksRate; + + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map(({ progress }) => progress) + .join(', ')}]` + ); + }); + + assert.strictEqual(data, buf.toString(), 'content corrupted'); + }, 30000); + + it('should support download rate limit', async function () { + const secs = 10; + const configRate = 100_000; + const chunkLength = configRate * secs; + + server = await startHTTPServer(); + + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); + + const { data } = await axios.post(LOCAL_SERVER_URL, buf, { + onDownloadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [0, configRate], + responseType: 'text', + maxRedirects: 0, + }); + + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map(({ rate }) => rate) + .join(', ')}]` + ); + + const progressTicksRate = 3; + const expectedProgress = (i + skip) / secs / progressTicksRate; + + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map(({ progress }) => progress) + .join(', ')}]` + ); + }); + + assert.strictEqual(data, buf.toString(), 'content corrupted'); + }, 30000); + }); + + describe('request aborting', function () { + //this.timeout(5000); + + it('should be able to abort the response stream', async () => { + server = await startHTTPServer({ + rate: 100_000, + useBuffering: true, + }); + + const buf = Buffer.alloc(1024 * 1024); + + const controller = new AbortController(); + + const { data } = await axios.post(LOCAL_SERVER_URL, buf, { + responseType: 'stream', + signal: controller.signal, + maxRedirects: 0, + }); + + setTimeout(() => { + controller.abort(); + }, 500); + + let streamError; + + data.on('error', function (err) { + streamError = err; + }); + + await assert.rejects(() => pipelineAsync([data, devNull()])); + + assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); + }); + }); + + it('should properly handle synchronous errors inside the adapter', function () { + return assert.rejects(() => axios.get('http://192.168.0.285'), /Invalid URL/); + }); + + it('should support function as paramsSerializer value', async () => { + server = await startHTTPServer((req, res) => res.end(req.url)); + + const { data } = await axios.post(LOCAL_SERVER_URL, 'test', { + params: { + x: 1, + }, + paramsSerializer: () => 'foo', + maxRedirects: 0, + }); + + assert.strictEqual(data, '/?foo'); + }); + + describe('DNS', function () { + it('should support a custom DNS lookup function', async function () { + server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + + const payload = 'test'; + + let isCalled = false; + + const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { + lookup: (hostname, opt, cb) => { + isCalled = true; + cb(null, '127.0.0.1', 4); + }, + }); + + assert.ok(isCalled); + + assert.strictEqual(data, payload); + }); + + it('should support a custom DNS lookup function with address entry passing', async function () { + server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + + const payload = 'test'; + + let isCalled = false; + + const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { + lookup: (hostname, opt, cb) => { + isCalled = true; + cb(null, { address: '127.0.0.1', family: 4 }); + }, + }); + + assert.ok(isCalled); + + assert.strictEqual(data, payload); + }); + + it('should support a custom DNS lookup function (async)', async function () { + server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + + const payload = 'test'; + + let isCalled = false; + + const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { + lookup: async (hostname, opt) => { + isCalled = true; + return ['127.0.0.1', 4]; + }, + }); + + assert.ok(isCalled); + + assert.strictEqual(data, payload); + }); + + it('should support a custom DNS lookup function with address entry (async)', async function () { + server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + + const payload = 'test'; + + let isCalled = false; + + const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { + lookup: async (hostname, opt) => { + isCalled = true; + return { address: '127.0.0.1', family: 4 }; + }, + }); + + assert.ok(isCalled); + + assert.strictEqual(data, payload); + }); + + it('should support a custom DNS lookup function that returns only IP address (async)', async function () { + server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + + const payload = 'test'; + + let isCalled = false; + + const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { + lookup: async (hostname, opt) => { + isCalled = true; + return '127.0.0.1'; + }, + }); + + assert.ok(isCalled); + + assert.strictEqual(data, payload); + }); + + it('should handle errors', () => { + return assert.rejects(async () => { + await axios.get('https://no-such-domain-987654.com', { + lookup, + }); + }, /ENOTFOUND/); + }); + }); + + describe('JSON', function () { + it('should support reviver on JSON.parse', async function () { + server = await startHTTPServer(async (_, res) => { + res.end( + JSON.stringify({ + foo: 'bar', + }) + ); + }); + + const { data } = await axios.get(LOCAL_SERVER_URL, { + parseReviver: (key, value) => { + return key === 'foo' ? 'success' : value; + }, + }); + + assert.deepStrictEqual(data, { foo: 'success' }); + }); + }); + + describe('HTTP2', function () { + const LOCAL_SERVER_URL = 'https://127.0.0.1:4444'; + + const http2Axios = axios.create({ + baseURL: LOCAL_SERVER_URL, + httpVersion: 2, + http2Options: { + rejectUnauthorized: false, + }, + }); + + it('should merge request http2Options with its instance config', async () => { + const { data } = await http2Axios.get('/', { + http2Options: { + foo: 'test', + }, + adapter: async (config) => { + return { + data: config.http2Options, + }; + }, + }); + + assert.deepStrictEqual(data, { + rejectUnauthorized: false, + foo: 'test', + }); + }); + + it('should support http2 transport', async () => { + server = await startHTTPServer( + (req, res) => { + res.end('OK'); + }, + { + useHTTP2: true, + } + ); + + const { data } = await http2Axios.get(LOCAL_SERVER_URL); + + assert.deepStrictEqual(data, 'OK'); + }); + + it(`should support request payload`, async () => { + server = await startHTTPServer(null, { + useHTTP2: true, + }); + + const payload = 'DATA'; + + const { data } = await http2Axios.post(LOCAL_SERVER_URL, payload); + + assert.deepStrictEqual(data, payload); + }); + + it(`should support FormData as a payload`, async function () { + if (typeof FormData !== 'function') { + return; + } + + server = await startHTTPServer( + async (req, res) => { + const { fields, files } = await handleFormData(req); + + res.end( + JSON.stringify({ + fields, + files, + }) + ); + }, + { + useHTTP2: true, + } + ); + + const form = new FormData(); + + form.append('x', 'foo'); + form.append('y', 'bar'); + + const { data } = await http2Axios.post(LOCAL_SERVER_URL, form); + + assert.deepStrictEqual(data, { + fields: { + x: 'foo', + y: 'bar', + }, + files: {}, + }); + }); + + describe('response types', () => { + const originalData = '{"test": "OK"}'; + + const fixtures = { + text: (v) => assert.strictEqual(v, originalData), + arraybuffer: (v) => assert.deepStrictEqual(v, Buffer.from(originalData)), + stream: async (v) => assert.deepStrictEqual(await getStream(v), originalData), + json: async (v) => assert.deepStrictEqual(v, JSON.parse(originalData)), + }; + + for (let [responseType, assertValue] of Object.entries(fixtures)) { + it(`should support ${responseType} response type`, async () => { + server = await startHTTPServer( + (req, res) => { + res.end(originalData); + }, + { + useHTTP2: true, + } + ); + + const { data } = await http2Axios.get(LOCAL_SERVER_URL, { + responseType, + }); + + await assertValue(data); + }); + } + }); + + it('should support request timeout', async () => { + let isAborted = false; + + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 15000); + }, + { + useHTTP2: true, + } + ); + + server.on('stream', (stream) => { + stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + await assert.rejects(async () => { + await http2Axios.get(LOCAL_SERVER_URL, { + timeout: 500, + }); + }, /timeout/); + + await promise; + + assert.ok(isAborted); + }); + + it('should support request cancellation', async function () { + if (typeof AbortSignal !== 'function' || !AbortSignal.timeout) { + return; + } + + let isAborted = false; + + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 15000); + }, + { + useHTTP2: true, + } + ); + + server.on('stream', (stream) => { + stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + await assert.rejects(async () => { + await http2Axios.get(LOCAL_SERVER_URL, { + signal: AbortSignal.timeout(500), + }); + }, /CanceledError: canceled/); + + await promise; + + assert.ok(isAborted); + }); + + it('should support stream response cancellation', async () => { + let isAborted = false; + var source = axios.CancelToken.source(); + + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + server = await startHTTPServer( + (req, res) => { + generateReadable(10000, 100, 100).pipe(res); + }, + { + useHTTP2: true, + } + ); + + server.on('stream', (stream) => { + stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + const { data } = await http2Axios.get(LOCAL_SERVER_URL, { + cancelToken: source.token, + responseType: 'stream', + }); + + setTimeout(() => source.cancel()); + + await assert.rejects(() => pipelineAsync([data, devNull()]), /CanceledError: canceled/); + + await promise; + + assert.ok(isAborted); + }); + + describe('session', () => { + it('should reuse session for the target authority', async () => { + server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 1000); + }, + { + useHTTP2: true, + } + ); + + const [response1, response2] = await Promise.all([ + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + }), + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + }), + ]); + + assert.strictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + }); + + it('should use different sessions for different authorities', async () => { + server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 2000); + }, + { + useHTTP2: true, + } + ); + + server2 = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 2000); + }, + { + useHTTP2: true, + port: SERVER_PORT2, + } + ); + + const [response1, response2] = await Promise.all([ + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + }), + http2Axios.get(LOCAL_SERVER_URL2, { + responseType: 'stream', + }), + ]); + + assert.notStrictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + }); + + it('should use different sessions for requests with different http2Options set', async () => { + server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 1000); + }, + { + useHTTP2: true, + } + ); + + const [response1, response2] = await Promise.all([ + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: {}, + }), + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: { + foo: 'test', + }, + }), + ]); + + assert.notStrictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + }); + + it('should use the same session for request with the same resolved http2Options set', async () => { + server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 1000); + }, + { + useHTTP2: true, + } + ); + + const responses = await Promise.all([ + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + }), + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: undefined, + }), + http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: {}, + }), + ]); + + assert.strictEqual(responses[1].data.session, responses[0].data.session); + assert.strictEqual(responses[2].data.session, responses[0].data.session); + + assert.deepStrictEqual(await Promise.all(responses.map(({ data }) => getStream(data))), [ + 'OK', + 'OK', + 'OK', + ]); + }); + + it('should use different sessions after previous session timeout', async () => { + server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 100); + }, + { + useHTTP2: true, + } + ); + + const response1 = await http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: { + sessionTimeout: 1000, + }, + }); + + const data1 = await getStream(response1.data); + + await setTimeoutAsync(5000); + + const response2 = await http2Axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + http2Options: { + sessionTimeout: 1000, + }, + }); + + const data2 = await getStream(response2.data); + + assert.notStrictEqual(response1.data.session, response2.data.session); + + assert.strictEqual(data1, 'OK'); + assert.strictEqual(data2, 'OK'); + }, 15000); + }); + }); + + it('should not abort stream on settle rejection', async () => { + server = await startHTTPServer((req, res) => { + res.statusCode = 404; + res.end('OK'); + }); + + try { + await axios.get(LOCAL_SERVER_URL, { + responseType: 'stream', + }); + + assert.fail('should be rejected'); + } catch (err) { + assert.strictEqual(await getStream(err.response.data), 'OK'); + } + }); + + describe('keep-alive', () => { + it('should not fail with "socket hang up" when using timeouts', async () => { + server = await startHTTPServer(async (req, res) => { + if (req.url === '/wait') { + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + res.end('ok'); + }); + + const baseURL = LOCAL_SERVER_URL; + await axios.get('/1', { baseURL, timeout: 1000 }); + await axios.get(`/wait`, { baseURL, timeout: 0 }); + }, 15000); + }); +}); diff --git a/tests/unit/adapters/key.pem b/tests/unit/adapters/key.pem new file mode 100644 index 0000000000..9ce05bf90f --- /dev/null +++ b/tests/unit/adapters/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA+joLfff3WdFIGwrlVdUWfZ9vDr9w86yQpI6Xq0KF6JiKtxa+ +EVCNWtq8Ht5rZd1MxNSFWVb1jxnRLBEB8F3wLD/4xRk8CNxw8joXKsxUEirI76iV +mJDjm/tq90gaxZUWVtPZP95Qvocdl7brhuvLuF4J9wJVL5tr6ZYAje3omHBnjcFb +n9nh3Tqk0U6omAmS4k/BrXWDA1zq8LBmbP41CnfVNGq/5asDIZsNO8s5VQzNjFjN +rcqv2rEO0n+77qDBbqALQydxPmytZP+0jYXcj+EaJ4clApFhvps6Cg0taoF66E4k +Eg1JLALzgk3I/ATSE3nvi3J/RWkyjSYiolPavwIDAQABAoIBAEbMi5ndwjfAlkVI +hPEPNKjgpnymwB/CEL7utY04akkQeBcrsSWXBBfT0exuBDczMVhzxTMs/pe5t0xf +l4vaGG18wDeMV0cukCqJMyrh21u0jVv5+DHNtQjaTz6eQSzsbQCuOkbu8SuncUEO ++X8YUnDc8rbYCyBIOnVCAvAlg201uW0G5G9NEwJOu6cAKMKkogdHqv+FRX96C5hm +gtbGEzpGV2vVClgMwMcX49ucluZvqLvit/yehNVd0VOtW/kuLup4R6q0abHRapDd +95rJAhPvar4mzP+UgJrGQ9hozqhizDthBjnsmGeMBUiBCkay7OXIZpvLoCpQkti1 +WIWuikkCgYEA/oZqq71RT1nPuI7rlcjx3AeWe2EUQtKhQMJBiPx5eLLP6gII8+v2 +pD1qlmJM2eyIK0lzuskLIulTAA5Z+ejORDbvmn/DdT0CSvdrUFrcvnrRQnt2M5M2 +9VDRp6nvPE0H4kRZJrtITyLn0dv5ABf2L32i4dPCMePjKjSUygJSHrsCgYEA+61A +cIqch/lrQTk8hG7Y6p0EJzSInFVaKuZoMYpLhlDQcVvSDIQbGgRAN6BKTdxeQ+tK +hSxBSm2mze11aHig8GBGgdBFLaJOZRo6G+2fl+s1t1FCHfsaFhHwheZJONHMpKKd +Qm/7L/V35QV9YG0lPZ01TM6d5lXuKsmUNvBJTc0CgYASYajAgGqn3WeX/5JZ/eoh +ptaiUG+DJ+0HXUAYYYtwQRGs57q3yvnEAL963tyH/IIVBjf6bFyGh+07ms26s6p5 +2LHTKZj3FZHd0iKI6hb5FquYLoxpyx7z9oM9pZMmerWwDJmXp3zgYjf1uvovnItm +AJ/LyVxD+B5GxQdd028U0wKBgG4OllZglxDzJk7wa6FyI9N89Fr8oxzSSkrmVPwN +APfskSpxP8qPXpai8z4gDz47NtG2q/DOqIKWrtHwnF4iGibjwxFzdTz+dA/MR0r9 +P8QcbHIMy7/2lbK/B5JWYQDC5h28qs5pz8tqKZLyMqCfOiDWhX9f/zbBrxPw8KqR +q0ylAoGAL/0kemA/Tmxpwmp0S0oCqnA4gbCgS7qnApxB09xTewc/tuvraXc3Mzea +EvqDXLXK0R7O4E3vo0Mr23SodRVlFPevsmUUJLPJMJcxdfnSJgX+qE/UC8Ux+UMi +eYufYRDYSslfL2rt9D7abnnbqSfsHymJKukWpElIgJTklQUru4k= +-----END RSA PRIVATE KEY----- diff --git a/vitest.config.js b/vitest.config.js index a03cf54caa..87fc0f202e 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -10,6 +10,7 @@ export default defineConfig({ name: 'unit', environment: 'node', include: ['tests/unit/**/*.test.js'], + setupFiles: ['tests/setup/unit.setup.js'], }, }, { From e4219a4a562fa5ab3fa0025e4f640f218dd4a9cb Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Tue, 3 Mar 2026 19:35:40 +0200 Subject: [PATCH 06/37] feat: updated more sections of the http test --- package.json | 2 +- tests/setup/server.js | 3 +- tests/setup/unit.setup.js | 6 - tests/unit/adapters/error-details.test.js | 6 +- tests/unit/adapters/http.test.js | 3110 +-------------------- vitest.config.js | 2 +- 6 files changed, 37 insertions(+), 3092 deletions(-) delete mode 100644 tests/setup/unit.setup.js diff --git a/package.json b/package.json index 63f7fa40ca..20dfe62c55 100644 --- a/package.json +++ b/package.json @@ -231,4 +231,4 @@ ], "report-dir": "./coverage" } -} +} \ No newline at end of file diff --git a/tests/setup/server.js b/tests/setup/server.js index 6005322d98..90e322646d 100644 --- a/tests/setup/server.js +++ b/tests/setup/server.js @@ -43,7 +43,8 @@ export const startHTTPServer = (handlerOrOptions, options) => { handler || async function (req, res) { try { - req.headers['content-length'] && res.setHeader('content-length', req.headers['content-length']); + req.headers['content-length'] && + res.setHeader('content-length', req.headers['content-length']); let dataStream = req; diff --git a/tests/setup/unit.setup.js b/tests/setup/unit.setup.js deleted file mode 100644 index efdf84912e..0000000000 --- a/tests/setup/unit.setup.js +++ /dev/null @@ -1,6 +0,0 @@ -import { afterEach } from 'vitest'; -import { stopAllTrackedHTTPServers } from './server.js'; - -afterEach(async () => { - await stopAllTrackedHTTPServers(); -}); diff --git a/tests/unit/adapters/error-details.test.js b/tests/unit/adapters/error-details.test.js index 479c3221d9..4c0b2565d3 100644 --- a/tests/unit/adapters/error-details.test.js +++ b/tests/unit/adapters/error-details.test.js @@ -10,7 +10,7 @@ import axios from '../../../index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -async function getClosedPort() { +const getClosedPort = async () => { return await new Promise((resolve) => { const srv = net.createServer(); srv.listen(0, '127.0.0.1', () => { @@ -18,7 +18,7 @@ async function getClosedPort() { srv.close(() => resolve(port)); }); }); -} +}; describe('adapters - network-error details', () => { it('should expose ECONNREFUSED and set error.cause on connection refusal', async () => { @@ -41,7 +41,7 @@ describe('adapters - network-error details', () => { }); it('should expose self-signed TLS error and set error.cause', async () => { - const certsDir = path.resolve(__dirname, '../../../test/unit/adapters'); + const certsDir = path.resolve(__dirname, '../../../tests/unit/adapters/'); const keyPath = path.join(certsDir, 'key.pem'); const certPath = path.join(certsDir, 'cert.pem'); diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index b72f68477e..4e2ad3ab07 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1,3114 +1,64 @@ -import { afterEach, describe, it as vitestIt } from 'vitest'; -import axios from '../../../index.js'; -import http from 'http'; -import https from 'https'; -import net from 'net'; -import url from 'url'; -import zlib from 'zlib'; -import stream from 'stream'; -import util from 'util'; +import { describe, it } from 'vitest'; import assert from 'assert'; -import fs from 'fs'; -import path from 'path'; -import { lookup } from 'dns'; -let server, server2, proxy; +import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; +import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; -import FormDataLegacy from 'form-data'; -import formidable from 'formidable'; -import express from 'express'; -import multer from 'multer'; -import bodyParser from 'body-parser'; -const isBlobSupported = typeof Blob !== 'undefined'; -import devNull from 'dev-null'; -import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; -import { __setProxy } from '../../../lib/adapters/http.js'; -import { - FormData as FormDataPolyfill, - Blob as BlobPolyfill, - File as FilePolyfill, -} from 'formdata-node'; -import getStream from 'get-stream'; -import { - startHTTPServer, - stopHTTPServer, - LOCAL_SERVER_URL, - SERVER_HANDLER_STREAM_ECHO, - handleFormData, - generateReadable, -} from '../../setup/server.js'; - -const LOCAL_SERVER_URL2 = 'https://localhost:5555'; -const SERVER_PORT = 4444; -const SERVER_PORT2 = 5555; - -const FormDataSpecCompliant = typeof FormData !== 'undefined' ? FormData : FormDataPolyfill; -const BlobSpecCompliant = typeof Blob !== 'undefined' ? Blob : BlobPolyfill; -const FileSpecCompliant = typeof File !== 'undefined' ? File : FilePolyfill; - -const __filename = url.fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -function setTimeoutAsync(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -const pipelineAsync = util.promisify(stream.pipeline); -const finishedAsync = util.promisify(stream.finished); -const gzip = util.promisify(zlib.gzip); -const deflate = util.promisify(zlib.deflate); -const deflateRaw = util.promisify(zlib.deflateRaw); -const brotliCompress = util.promisify(zlib.brotliCompress); - -function toleranceRange(positive, negative) { - const p = 1 + positive / 100; - const n = 1 - negative / 100; - - return (actualValue, value) => { - return actualValue > value ? actualValue <= value * p : actualValue >= value * n; - }; -} - -const nodeVersion = process.versions.node.split('.').map((v) => parseInt(v, 10)); -const nodeMajorVersion = nodeVersion[0]; - -var noop = () => {}; - -const wrapDoneCallback = (testFn) => { - if (typeof testFn !== 'function' || testFn.length === 0) { - return testFn; - } - - return () => - new Promise((resolve, reject) => { - let settled = false; - - const done = (err) => { - if (settled) { - return; - } - - settled = true; - err ? reject(err) : resolve(); - }; - - try { - const maybePromise = testFn(done); - - if (maybePromise && typeof maybePromise.then === 'function') { - maybePromise.then(() => done(), done); - } - } catch (err) { - done(err); - } - }); -}; - -const it = (name, testFn, timeout) => vitestIt(name, wrapDoneCallback(testFn), timeout); -it.skip = (name, testFn, timeout) => vitestIt.skip(name, wrapDoneCallback(testFn), timeout); - -describe('supports http with nodejs', function () { - afterEach(async function () { - await Promise.all([stopHTTPServer(server), stopHTTPServer(server2), stopHTTPServer(proxy)]); - - server = null; - server2 = null; - proxy = null; - - delete process.env.http_proxy; - delete process.env.https_proxy; - delete process.env.no_proxy; - }); - - it('should support IPv4 literal strings', function (done) { - var data = { - firstName: 'Fred', - lastName: 'Flintstone', - emailAddr: 'fred@example.com', - }; - - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }) - .listen(4444, function () { - axios - .get('http://127.0.0.1:4444/') - .then(function (res) { - assert.deepEqual(res.data, data); - done(); - }) - .catch(done); - }); - }); - it('should support IPv6 literal strings', function (done) { - var data = { +describe('supports http with nodejs', () => { + it('should support IPv4 literal strings', async () => { + const data = { firstName: 'Fred', lastName: 'Flintstone', emailAddr: 'fred@example.com', }; - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }) - .listen(4444, function () { - axios - .get('http://[::1]:4444/') - .then(function (res) { - assert.deepEqual(res.data, data); - done(); - }) - .catch(done); - }); - }); - - it('should throw an error if the timeout property is not parsable as a number', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - var success = false, - failure = false; - var error; - - axios - .get('http://localhost:4444/', { - timeout: { strangeTimeout: 250 }, - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.code, AxiosError.ERR_BAD_OPTION_VALUE); - assert.equal(error.message, 'error trying to parse `config.timeout` to int'); - done(); - }, 300); - }); - }); - - it('should parse the timeout property', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - var success = false, - failure = false; - var error; - - axios - .get('http://localhost:4444/', { - timeout: '250', - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.code, 'ECONNABORTED'); - assert.equal(error.message, 'timeout of 250ms exceeded'); - done(); - }, 300); - }); - }); - - it('should respect the timeout property', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - var success = false, - failure = false; - var error; - - axios - .get('http://localhost:4444/', { - timeout: 250, - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.code, 'ECONNABORTED'); - assert.equal(error.message, 'timeout of 250ms exceeded'); - done(); - }, 300); - }); - }); - - it('should respect the timeoutErrorMessage property', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - var success = false, - failure = false; - var error; - - axios - .get('http://localhost:4444/', { - timeout: 250, - timeoutErrorMessage: 'oops, timeout', - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }); - setTimeout(function () { - assert.strictEqual(success, false, 'request should not succeed'); - assert.strictEqual(failure, true, 'request should fail'); - assert.strictEqual(error.code, 'ECONNABORTED'); - assert.strictEqual(error.message, 'oops, timeout'); - done(); - }, 300); - }); - }); + const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); - it('should allow passing JSON', function (done) { - var data = { - firstName: 'Fred', - lastName: 'Flintstone', - emailAddr: 'fred@example.com', - }; + assert.deepStrictEqual(responseData, data); - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.deepEqual(res.data, data); - done(); - }) - .catch(done); - }); + await stopHTTPServer(server); }); - it('should allow passing JSON with BOM', function (done) { + it('should support IPv6 literal strings', async () => { var data = { firstName: 'Fred', lastName: 'Flintstone', emailAddr: 'fred@example.com', }; - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'application/json'); - var bomBuffer = Buffer.from([0xef, 0xbb, 0xbf]); - var jsonBuffer = Buffer.from(JSON.stringify(data)); - res.end(Buffer.concat([bomBuffer, jsonBuffer])); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.deepEqual(res.data, data); - done(); - }) - .catch(done); - }); - }); - - it('should redirect', function (done) { - var str = 'test response'; - - server = http - .createServer(function (req, res) { - var parsed = url.parse(req.url); - - if (parsed.pathname === '/one') { - res.setHeader('Location', '/two'); - res.statusCode = 302; - res.end(); - } else { - res.end(str); - } - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/one') - .then(function (res) { - assert.equal(res.data, str); - assert.equal(res.request.path, '/two'); - done(); - }) - .catch(done); - }); - }); - - it('should not redirect', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Location', '/foo'); - res.statusCode = 302; - res.end(); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - maxRedirects: 0, - validateStatus: function () { - return true; - }, - }) - .then(function (res) { - assert.equal(res.status, 302); - assert.equal(res.headers['location'], '/foo'); - done(); - }) - .catch(done); - }); - }); - - it('should support max redirects', function (done) { - var i = 1; - server = http - .createServer(function (req, res) { - res.setHeader('Location', '/' + i); - res.statusCode = 302; - res.end(); - i++; - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - maxRedirects: 3, - }) - .catch(function (error) { - assert.equal(error.code, AxiosError.ERR_FR_TOO_MANY_REDIRECTS); - assert.equal(error.message, 'Maximum number of redirects exceeded'); - done(); - }) - .catch(done); - }); - }); - - it('should support beforeRedirect', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Location', '/foo'); - res.statusCode = 302; - res.end(); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - maxRedirects: 3, - beforeRedirect: function (options, responseDetails) { - if (options.path === '/foo' && responseDetails.headers.location === '/foo') { - throw new Error('Provided path is not allowed'); - } - }, - }) - .catch(function (error) { - assert.equal(error.message, 'Redirected request failed: Provided path is not allowed'); - done(); - }) - .catch(done); - }); - }); - - it('should support beforeRedirect and proxy with redirect', async () => { - let requestCount = 0; - let totalRedirectCount = 5; - - server = await startHTTPServer( - function (req, res) { - requestCount += 1; - if (requestCount <= totalRedirectCount) { - res.setHeader('Location', 'http://localhost:4444'); - res.writeHead(302); - } - res.end(); - }, - { port: 4444 } - ); - - let proxyUseCount = 0; - proxy = await startHTTPServer( - function (req, res) { - proxyUseCount += 1; - const targetUrl = new URL(req.url, 'http://' + req.headers.host); - const opts = { - host: targetUrl.hostname, - port: targetUrl.port, - path: targetUrl.path, - method: req.method, - }; - - const request = http.get(opts, function (response) { - res.writeHead(response.statusCode, response.headers); - stream.pipeline(response, res, () => {}); - }); - - request.on('error', (err) => { - console.warn('request error', err); - res.statusCode = 500; - res.end(); - }); - }, - { port: 4000 } - ); - - let configBeforeRedirectCount = 0; - - await axios - .get('http://localhost:4444/', { - proxy: { - host: 'localhost', - port: 4000, - }, - maxRedirects: totalRedirectCount, - beforeRedirect: function (options) { - configBeforeRedirectCount += 1; - }, - }) - .then(function (res) { - assert.equal( - totalRedirectCount, - configBeforeRedirectCount, - 'should invoke config.beforeRedirect option on every redirect' - ); - assert.equal( - totalRedirectCount + 1, - proxyUseCount, - 'should go through proxy on every redirect' - ); - }); - }); - - it('should wrap HTTP errors and keep stack', async function () { - if (nodeMajorVersion <= 12) { - return; // node 12 support for async stack traces appears lacking - return; - } - - server = await startHTTPServer((req, res) => { - res.statusCode = 400; - res.end(); - }); - - return assert.rejects( - async function findMeInStackTrace() { - await axios.head('http://localhost:4444/one'); - }, - function (err) { - assert.equal(err.name, 'AxiosError'); - assert.equal(err.isAxiosError, true); - const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]; - assert.equal(matches.length, 1, err.stack); - return true; - } - ); - }); - - it('should wrap interceptor errors and keep stack', function (done) { - if (nodeMajorVersion <= 12) { - return; // node 12 support for async stack traces appears lacking - return; - } - const axiosInstance = axios.create(); - axiosInstance.interceptors.request.use((res) => { - throw new Error('from request interceptor'); - }); - server = http - .createServer(function (req, res) { - res.end(); - }) - .listen(4444, function () { - void assert - .rejects( - async function findMeInStackTrace() { - await axiosInstance.get('http://localhost:4444/one'); - }, - function (err) { - assert.equal(err.name, 'Error'); - assert.equal(err.message, 'from request interceptor'); - const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]; - assert.equal(matches.length, 1, err.stack); - return true; - } - ) - .then(done) - .catch(done); - }); - }); - - it('should preserve the HTTP verb on redirect', function (done) { - server = http - .createServer(function (req, res) { - if (req.method.toLowerCase() !== 'head') { - res.statusCode = 400; - res.end(); - return; - } - - var parsed = url.parse(req.url); - if (parsed.pathname === '/one') { - res.setHeader('Location', '/two'); - res.statusCode = 302; - res.end(); - } else { - res.end(); - } - }) - .listen(4444, function () { - axios - .head('http://localhost:4444/one') - .then(function (res) { - assert.equal(res.status, 200); - done(); - }) - .catch(done); - }); - }); - - describe('compression', async () => { - it('should support transparent gunzip', function (done) { - var data = { - firstName: 'Fred', - lastName: 'Flintstone', - emailAddr: 'fred@example.com', - }; - - zlib.gzip(JSON.stringify(data), function (err, zipped) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'application/json'); - res.setHeader('Content-Encoding', 'gzip'); - res.end(zipped); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.deepEqual(res.data, data); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support gunzip error handling', async () => { - server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.setHeader('Content-Encoding', 'gzip'); - res.end('invalid response'); - }); - - await assert.rejects(async () => { - await axios.get(LOCAL_SERVER_URL); - }); - }); - - it('should support disabling automatic decompression of response data', function (done) { - var data = 'Test data'; - - zlib.gzip(data, function (err, zipped) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html;charset=utf-8'); - res.setHeader('Content-Encoding', 'gzip'); - res.end(zipped); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - decompress: false, - responseType: 'arraybuffer', - }) - .then(function (res) { - assert.equal(res.data.toString('base64'), zipped.toString('base64')); - done(); - }) - .catch(done); - }); - }); - }); - - describe('algorithms', () => { - const responseBody = 'str'; - - for (const [typeName, zipped] of Object.entries({ - gzip: gzip(responseBody), - GZIP: gzip(responseBody), - compress: gzip(responseBody), - deflate: deflate(responseBody), - 'deflate-raw': deflateRaw(responseBody), - br: brotliCompress(responseBody), - })) { - const type = typeName.split('-')[0]; - - describe(`${typeName} decompression`, async () => { - it(`should support decompression`, async () => { - server = await startHTTPServer(async (req, res) => { - res.setHeader('Content-Encoding', type); - res.end(await zipped); - }); - - const { data } = await axios.get(LOCAL_SERVER_URL); - - assert.strictEqual(data, responseBody); - }); - - it(`should not fail if response content-length header is missing (${type})`, async () => { - server = await startHTTPServer(async (req, res) => { - res.setHeader('Content-Encoding', type); - res.removeHeader('Content-Length'); - res.end(await zipped); - }); - - const { data } = await axios.get(LOCAL_SERVER_URL); - - assert.strictEqual(data, responseBody); - }); - - it('should not fail with chunked responses (without Content-Length header)', async () => { - server = await startHTTPServer(async (req, res) => { - res.setHeader('Content-Encoding', type); - res.setHeader('Transfer-Encoding', 'chunked'); - res.removeHeader('Content-Length'); - res.write(await zipped); - res.end(); - }); - - const { data } = await axios.get(LOCAL_SERVER_URL); - - assert.strictEqual(data, responseBody); - }); - - it('should not fail with an empty response without content-length header (Z_BUF_ERROR)', async () => { - server = await startHTTPServer((req, res) => { - res.setHeader('Content-Encoding', type); - res.removeHeader('Content-Length'); - res.end(); - }); - - const { data } = await axios.get(LOCAL_SERVER_URL); - - assert.strictEqual(data, ''); - }); - - it('should not fail with an empty response with content-length header (Z_BUF_ERROR)', async () => { - server = await startHTTPServer((req, res) => { - res.setHeader('Content-Encoding', type); - res.end(); - }); - - await axios.get(LOCAL_SERVER_URL); - }); - }); - } + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); }); - }); - - it('should support UTF8', function (done) { - var str = Array(100000).join('ж'); - - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(str); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.equal(res.data, str); - done(); - }) - .catch(done); - }); - }); - - it('should support basic auth', function (done) { - server = http - .createServer(function (req, res) { - res.end(req.headers.authorization); - }) - .listen(4444, function () { - var user = 'foo'; - var headers = { Authorization: 'Bearer 1234' }; - axios - .get('http://' + user + '@localhost:4444/', { headers: headers }) - .then(function (res) { - var base64 = Buffer.from(user + ':', 'utf8').toString('base64'); - assert.equal(res.data, 'Basic ' + base64); - done(); - }) - .catch(done); - }); - }); - - it('should support basic auth with a header', function (done) { - server = http - .createServer(function (req, res) { - res.end(req.headers.authorization); - }) - .listen(4444, function () { - var auth = { username: 'foo', password: 'bar' }; - var headers = { AuThOrIzAtIoN: 'Bearer 1234' }; // wonky casing to ensure caseless comparison - axios - .get('http://localhost:4444/', { auth: auth, headers: headers }) - .then(function (res) { - var base64 = Buffer.from('foo:bar', 'utf8').toString('base64'); - assert.equal(res.data, 'Basic ' + base64); - done(); - }) - .catch(done); - }); - }); - - it('should provides a default User-Agent header', function (done) { - server = http - .createServer(function (req, res) { - res.end(req.headers['user-agent']); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.ok( - /^axios\/[\d.]+[-]?[a-z]*[.]?[\d]+$/.test(res.data), - `User-Agent header does not match: ${res.data}` - ); - done(); - }) - .catch(done); - }); - }); - - it('should allow the User-Agent header to be overridden', function (done) { - server = http - .createServer(function (req, res) { - res.end(req.headers['user-agent']); - }) - .listen(4444, function () { - var headers = { 'UsEr-AgEnT': 'foo bar' }; // wonky casing to ensure caseless comparison - axios - .get('http://localhost:4444/', { headers }) - .then(function (res) { - assert.equal(res.data, 'foo bar'); - done(); - }) - .catch(done); - }); - }); - - it('should allow the Content-Length header to be overridden', function (done) { - server = http - .createServer(function (req, res) { - assert.strictEqual(req.headers['content-length'], '42'); - res.end(); - }) - .listen(4444, function () { - var headers = { 'CoNtEnT-lEnGtH': '42' }; // wonky casing to ensure caseless comparison - axios - .post('http://localhost:4444/', 'foo', { headers }) - .then(function () { - done(); - }) - .catch(done); - }); - }); - - it('should support max content length', async function () { - server = await startHTTPServer( - function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(Array(5000).join('#')); - }, - { port: 4444 } - ); - - await assert.rejects(() => { - return axios.get('http://localhost:4444/', { - maxContentLength: 2000, - maxRedirects: 0, - }); - }, /maxContentLength size of 2000 exceeded/); - }); - it('should support max content length for redirected', function (done) { - var str = Array(100000).join('ж'); + const { data: responseData } = await axios.get(`http://[::1]:${server.address().port}`); - server = http - .createServer(function (req, res) { - var parsed = url.parse(req.url); + assert.deepStrictEqual(responseData, data); - if (parsed.pathname === '/two') { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(str); - } else { - res.setHeader('Location', '/two'); - res.statusCode = 302; - res.end(); - } - }) - .listen(4444, function () { - var success = false, - failure = false, - error; - - axios - .get('http://localhost:4444/one', { - maxContentLength: 2000, - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.message, 'maxContentLength size of 2000 exceeded'); - done(); - }, 100); - }); + await stopHTTPServer(server); }); - it('should support max body length', function (done) { - var data = Array(100000).join('ж'); - - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + it('should throw an error if the timeout property is not parsable as a number', async () => { + const server = await startHTTPServer((req, res) => { + setTimeout(() => { res.end(); - }) - .listen(4444, function () { - var success = false, - failure = false, - error; - - axios - .post( - 'http://localhost:4444/', - { - data: data, - }, - { - maxBodyLength: 2000, - } - ) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.message, 'Request body larger than maxBodyLength limit'); - done(); - }, 100); - }); - }); - - it('should properly support default max body length (follow-redirects as well)', function (done) { - // taken from https://github.com/follow-redirects/follow-redirects/blob/22e81fc37132941fb83939d1dc4c2282b5c69521/index.js#L461 - var followRedirectsMaxBodyDefaults = 10 * 1024 * 1024; - var data = Array(2 * followRedirectsMaxBodyDefaults).join('ж'); - - server = http - .createServer(function (req, res) { - // consume the req stream - req.on('data', noop); - // and wait for the end before responding, otherwise an ECONNRESET error will be thrown - req.on('end', () => { - res.end('OK'); - }); - }) - .listen(4444, function (err) { - if (err) { - return done(err); - } - // send using the default -1 (unlimited axios maxBodyLength) - axios - .post('http://localhost:4444/', { - data: data, - }) - .then(function (res) { - assert.equal(res.data, 'OK', 'should handle response'); - done(); - }) - .catch(done); - }); - }); - - it('should display error while parsing params', function (done) { - server = http - .createServer(function () {}) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - params: { - errorParam: new Date(undefined), - }, - }) - .catch(function (err) { - assert.deepEqual(err.exists, true); - done(); - }) - .catch(done); - }); - }); - - it('should support sockets', function (done) { - // Different sockets for win32 vs darwin/linux - var socketName = './test.sock'; - - if (process.platform === 'win32') { - socketName = '\\\\.\\pipe\\libuv-test'; - } - - server = net - .createServer(function (socket) { - socket.on('data', function () { - socket.end('HTTP/1.1 200 OK\r\n\r\n'); - }); - }) - .listen(socketName, function () { - axios({ - socketPath: socketName, - url: 'http://localhost:4444/socket', - }) - .then(function (resp) { - assert.equal(resp.status, 200); - assert.equal(resp.statusText, 'OK'); - done(); - }) - .catch(done); - }); - }); - - describe('streams', function () { - it('should support streams', function (done) { - server = http - .createServer(function (req, res) { - req.pipe(res); - }) - .listen(4444, function () { - axios - .post('http://localhost:4444/', fs.createReadStream(__filename), { - responseType: 'stream', - }) - .then(function (res) { - var stream = res.data; - var string = ''; - stream.on('data', function (chunk) { - string += chunk.toString('utf8'); - }); - stream.on('end', function () { - assert.equal(string, fs.readFileSync(__filename, 'utf8')); - done(); - }); - }) - .catch(done); - }); - }); - - it('should pass errors for a failed stream', async function () { - server = await startHTTPServer(); - - var notExitPath = path.join(__dirname, 'does_not_exist'); - - try { - await axios.post(LOCAL_SERVER_URL, fs.createReadStream(notExitPath)); - assert.fail('expected ENOENT error'); - } catch (err) { - assert.equal(err.message, `ENOENT: no such file or directory, open \'${notExitPath}\'`); - } - }); - - it('should destroy the response stream with an error on request stream destroying', async function () { - server = await startHTTPServer(); - - let stream = generateReadable(); - - setTimeout(function () { - stream.destroy(); }, 1000); - - const { data } = await axios.post(LOCAL_SERVER_URL, stream, { responseType: 'stream' }); - - let streamError; - - data.on('error', function (err) { - streamError = err; - }); - - try { - await pipelineAsync(data, devNull()); - assert.fail('stream was not aborted'); - } catch (e) { - console.log(`pipeline error: ${e}`); - } finally { - assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); - } }); - }); - - it('should support buffers', function (done) { - var buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) - server = http - .createServer(function (req, res) { - assert.equal(req.headers['content-length'], buf.length.toString()); - req.pipe(res); - }) - .listen(4444, function () { - axios - .post('http://localhost:4444/', buf, { - responseType: 'stream', - }) - .then(function (res) { - var stream = res.data; - var string = ''; - stream.on('data', function (chunk) { - string += chunk.toString('utf8'); - }); - stream.on('end', function () { - assert.equal(string, buf.toString()); - done(); - }); - }) - .catch(done); - }); - }); - - it('should support HTTP proxies', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); - }); - }); - }) - .listen(4000, function () { - axios - .get('http://localhost:4444/', { - proxy: { - host: 'localhost', - port: 4000, - }, - }) - .then(function (res) { - assert.equal(res.data, '123456789', 'should pass through proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support HTTPS proxies', function (done) { - var options = { - key: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/key.pem')), - cert: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/cert.pem')), - }; - - server = https - .createServer(options, function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }) - .listen(4444, function () { - proxy = https - .createServer(options, function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - protocol: parsed.protocol, - rejectUnauthorized: false, - }; - - https.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); - }); - }); - }) - .listen(4000, function () { - axios - .get('https://localhost:4444/', { - proxy: { - host: 'localhost', - port: 4000, - protocol: 'https:', - }, - httpsAgent: new https.Agent({ - rejectUnauthorized: false, - }), - }) - .then(function (res) { - assert.equal(res.data, '123456789', 'should pass through proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - it('should not pass through disabled proxy', function (done) { - // set the env variable - process.env.http_proxy = 'http://does-not-exists.example.com:4242/'; - - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('123456789'); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - proxy: false, - }) - .then(function (res) { - assert.equal(res.data, '123456789', 'should not pass through proxy'); - done(); - }) - .catch(done); - }); - }); - - it('should support proxy set via env var', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('4567'); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '1234'); - }); - }); - }) - .listen(4000, function () { - // set the env variable - process.env.http_proxy = 'http://localhost:4000/'; - - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.equal( - res.data, - '45671234', - 'should use proxy set by process.env.http_proxy' - ); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support HTTPS proxy set via env var', function (done) { - var options = { - key: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/key.pem')), - cert: fs.readFileSync(path.join(__dirname, '../../../test/unit/adapters/cert.pem')), - }; - - server = https - .createServer(options, function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }) - .listen(4444, function () { - proxy = https - .createServer(options, function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - protocol: parsed.protocol, - rejectUnauthorized: false, - }; - - https.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); - }); - }); - }) - .listen(4000, function () { - process.env.https_proxy = 'https://localhost:4000/'; - - axios - .get('https://localhost:4444/', { - httpsAgent: new https.Agent({ - rejectUnauthorized: false, - }), - }) - .then(function (res) { - assert.equal(res.data, '123456789', 'should pass through proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - it('should re-evaluate proxy on redirect when proxy set via env var', function (done) { - process.env.http_proxy = 'http://localhost:4000'; - process.env.no_proxy = 'localhost:4000'; - - var proxyUseCount = 0; - - server = http - .createServer(function (req, res) { - res.setHeader('Location', 'http://localhost:4000/redirected'); - res.statusCode = 302; - res.end(); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - if (parsed.pathname === '/redirected') { - response.statusCode = 200; - response.end(); - return; - } - - proxyUseCount += 1; - - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - protocol: parsed.protocol, - rejectUnauthorized: false, - }; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.setHeader('Location', res.headers.location); - response.end(body); - }); - }); - }) - .listen(4000, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.equal(res.status, 200); - assert.equal(proxyUseCount, 1); - done(); - }) - .catch(done); - }); - }); - }); - - it('should not use proxy for domains in no_proxy', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('4567'); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '1234'); - }); - }); - }) - .listen(4000, function () { - // set the env variable - process.env.http_proxy = 'http://localhost:4000/'; - process.env.no_proxy = 'foo.com, localhost,bar.net , , quix.co'; - - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.equal(res.data, '4567', 'should not use proxy for domains in no_proxy'); - done(); - }) - .catch(done); - }); - }); - }); - it('should use proxy for domains not in no_proxy', function (done) { - server = http - .createServer(function (req, res) { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('4567'); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '1234'); - }); - }); - }) - .listen(4000, function () { - // set the env variable - process.env.http_proxy = 'http://localhost:4000/'; - process.env.no_proxy = 'foo.com, ,bar.net , quix.co'; - - axios - .get('http://localhost:4444/') - .then(function (res) { - assert.equal(res.data, '45671234', 'should use proxy for domains not in no_proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support HTTP proxy auth', function (done) { - server = http - .createServer(function (req, res) { - res.end(); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - var proxyAuth = request.headers['proxy-authorization']; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(proxyAuth); - }); - }); - }) - .listen(4000, function () { - axios - .get('http://localhost:4444/', { - proxy: { - host: 'localhost', - port: 4000, - auth: { - username: 'user', - password: 'pass', - }, - }, - }) - .then(function (res) { - var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support proxy auth from env', function (done) { - server = http - .createServer(function (req, res) { - res.end(); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - var proxyAuth = request.headers['proxy-authorization']; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(proxyAuth); - }); - }); - }) - .listen(4000, function () { - process.env.http_proxy = 'http://user:pass@localhost:4000/'; - - axios - .get('http://localhost:4444/') - .then(function (res) { - var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - assert.equal( - res.data, - 'Basic ' + base64, - 'should authenticate to the proxy set by process.env.http_proxy' - ); - done(); - }) - .catch(done); - }); - }); - }); - - it('should support proxy auth with header', function (done) { - server = http - .createServer(function (req, res) { - res.end(); - }) - .listen(4444, function () { - proxy = http - .createServer(function (request, response) { - var parsed = url.parse(request.url); - var opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - var proxyAuth = request.headers['proxy-authorization']; - - http.get(opts, function (res) { - var body = ''; - res.on('data', function (data) { - body += data; - }); - res.on('end', function () { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(proxyAuth); - }); - }); - }) - .listen(4000, function () { - axios - .get('http://localhost:4444/', { - proxy: { - host: 'localhost', - port: 4000, - auth: { - username: 'user', - password: 'pass', - }, - }, - headers: { - 'Proxy-Authorization': 'Basic abc123', - }, - }) - .then(function (res) { - var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); - done(); - }) - .catch(done); - }); - }); - }); - - describe('when invalid proxy options are provided', function () { - it('should throw error', function () { - const proxy = { - protocol: 'http:', - host: 'hostname.abc.xyz', - port: 3300, - auth: { - username: '', - password: '', - }, - }; - - return axios.get('https://test-domain.abc', { proxy }).then( - function () { - assert.fail('Does not throw'); - }, - function (error) { - assert.strictEqual(error.message, 'Invalid proxy authorization'); - assert.strictEqual(error.code, 'ERR_BAD_OPTION'); - assert.deepStrictEqual(error.config.proxy, proxy); - } - ); - }); - }); - - describe('different options for direct proxy configuration (without env variables)', () => { - const destination = 'www.example.com'; - - const testCases = [ - { - description: 'hostname and trailing colon in protocol', - proxyConfig: { hostname: '127.0.0.1', protocol: 'http:', port: 80 }, - expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, - }, - { - description: 'hostname and no trailing colon in protocol', - proxyConfig: { hostname: '127.0.0.1', protocol: 'http', port: 80 }, - expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, - }, - { - description: 'both hostname and host -> hostname takes precedence', - proxyConfig: { hostname: '127.0.0.1', host: '0.0.0.0', protocol: 'http', port: 80 }, - expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, - }, - { - description: 'only host and https protocol', - proxyConfig: { host: '0.0.0.0', protocol: 'https', port: 80 }, - expectedOptions: { host: '0.0.0.0', protocol: 'https:', port: 80, path: destination }, - }, - ]; - - for (const test of testCases) { - it(test.description, () => { - const options = { headers: {}, beforeRedirects: {} }; - __setProxy(options, test.proxyConfig, destination); - for (const [key, expected] of Object.entries(test.expectedOptions)) { - assert.equal(options[key], expected); - } + try { + await axios.get(`http://127.0.0.1:${server.address().port}`, { + timeout: { strangeTimeout: 250 }, }); + } catch (error) { + assert.strictEqual(error.code, AxiosError.ERR_BAD_OPTION_VALUE); + assert.strictEqual(error.message, 'error trying to parse `config.timeout` to int'); } - }); - - it('should support cancel', function (done) { - var source = axios.CancelToken.source(); - server = http - .createServer(function (req, res) { - // call cancel() when the request has been sent, but a response has not been received - source.cancel('Operation has been canceled.'); - }) - .listen(4444, function () { - void assert - .rejects( - async function findMeInStackTrace() { - await axios.get('http://localhost:4444/', { - cancelToken: source.token, - }); - }, - function (thrown) { - assert.ok( - thrown instanceof axios.Cancel, - 'Promise must be rejected with a CanceledError object' - ); - assert.equal(thrown.message, 'Operation has been canceled.'); - if (nodeMajorVersion > 12) { - assert.match(thrown.stack, /findMeInStackTrace/); - } - return true; - } - ) - .then(done) - .catch(done); - }); - }); - - it('should combine baseURL and url', function (done) { - server = http - .createServer(function (req, res) { - res.end(); - }) - .listen(4444, function () { - axios - .get('/foo', { - baseURL: 'http://localhost:4444/', - }) - .then(function (res) { - assert.equal(res.config.baseURL, 'http://localhost:4444/'); - assert.equal(res.config.url, '/foo'); - done(); - }) - .catch(done); - }); - }); - - it('should support HTTP protocol', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - axios.get('http://localhost:4444').then(function (res) { - assert.equal(res.request.agent.protocol, 'http:'); - done(); - }); - }); - }); - - it('should support HTTPS protocol', function (done) { - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - axios.get('https://www.google.com').then(function (res) { - assert.equal(res.request.agent.protocol, 'https:'); - done(); - }); - }); - }); - - it('should return malformed URL', function (done) { - var success = false, - failure = false; - var error; - - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - axios - .get('tel:484-695-3408') - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.message, 'Unsupported protocol tel:'); - done(); - }, 300); - }); - }); - - it('should return unsupported protocol', function (done) { - var success = false, - failure = false; - var error; - - server = http - .createServer(function (req, res) { - setTimeout(function () { - res.end(); - }, 1000); - }) - .listen(4444, function () { - axios - .get('ftp:google.com') - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }); - - setTimeout(function () { - assert.equal(success, false, 'request should not succeed'); - assert.equal(failure, true, 'request should fail'); - assert.equal(error.message, 'Unsupported protocol ftp:'); - done(); - }, 300); - }); - }); - - it('should supply a user-agent if one is not specified', function (done) { - server = http - .createServer(function (req, res) { - assert.equal(req.headers['user-agent'], 'axios/' + axios.VERSION); - res.end(); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/') - .then(function (res) { - done(); - }) - .catch(done); - }); - }); - - it('should omit a user-agent if one is explicitly disclaimed', function (done) { - server = http - .createServer(function (req, res) { - assert.equal('user-agent' in req.headers, false); - assert.equal('User-Agent' in req.headers, false); - res.end(); - }) - .listen(4444, function () { - axios - .get('http://localhost:4444/', { - headers: { - 'User-Agent': null, - }, - }) - .then(function (res) { - done(); - }) - .catch(done); - }); - }); - - it('should throw an error if http server that aborts a chunked request', function (done) { - server = http - .createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('chunk 1'); - setTimeout(function () { - res.write('chunk 2'); - }, 100); - setTimeout(function () { - res.destroy(); - }, 200); - }) - .listen(4444, function () { - var success = false, - failure = false; - var error; - - axios - .get('http://localhost:4444/aborted', { - timeout: 500, - }) - .then(function (res) { - success = true; - }) - .catch(function (err) { - error = err; - failure = true; - }) - .then(function () { - assert.strictEqual(success, false, 'request should not succeed'); - assert.strictEqual(failure, true, 'request should fail'); - assert.strictEqual(error.code, 'ERR_BAD_RESPONSE'); - assert.strictEqual(error.message, 'stream has been aborted'); - done(); - }) - .catch(done); - }); - }); - - it('should able to cancel multiple requests with CancelToken', function (done) { - server = http - .createServer(function (req, res) { - res.end('ok'); - }) - .listen(4444, function () { - var CancelToken = axios.CancelToken; - var source = CancelToken.source(); - var canceledStack = []; - - var requests = [1, 2, 3, 4, 5].map(function (id) { - return axios.get('/foo/bar', { cancelToken: source.token }).catch(function (e) { - if (!axios.isCancel(e)) { - throw e; - } - - canceledStack.push(id); - }); - }); - - source.cancel('Aborted by user'); - - Promise.all(requests) - .then(function () { - assert.deepStrictEqual(canceledStack.sort(), [1, 2, 3, 4, 5]); - }) - .then(done, done); - }); - }); - - describe('FormData', function () { - describe('form-data instance (https://www.npmjs.com/package/form-data)', (done) => { - it('should allow passing FormData', function (done) { - var form = new FormDataLegacy(); - var file1 = Buffer.from('foo', 'utf8'); - const image = path.resolve(__dirname, '../../../test/unit/adapters/axios.png'); - const fileStream = fs.createReadStream(image); - - const stat = fs.statSync(image); - - form.append('foo', 'bar'); - form.append('file1', file1, { - filename: 'bar.jpg', - filepath: 'temp/bar.jpg', - contentType: 'image/jpeg', - }); - - form.append('fileStream', fileStream); - - server = http - .createServer(function (req, res) { - var receivedForm = new formidable.IncomingForm(); - - assert.ok(req.rawHeaders.find((header) => header.toLowerCase() === 'content-length')); - - receivedForm.parse(req, function (err, fields, files) { - if (err) { - return done(err); - } - - res.end( - JSON.stringify({ - fields: fields, - files: files, - }) - ); - }); - }) - .listen(4444, function () { - axios - .post('http://localhost:4444/', form, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }) - .then(function (res) { - assert.deepStrictEqual(res.data.fields, { foo: 'bar' }); - - assert.strictEqual(res.data.files.file1.mimetype, 'image/jpeg'); - assert.strictEqual(res.data.files.file1.originalFilename, 'temp/bar.jpg'); - assert.strictEqual(res.data.files.file1.size, 3); - - assert.strictEqual(res.data.files.fileStream.mimetype, 'image/png'); - assert.strictEqual(res.data.files.fileStream.originalFilename, 'axios.png'); - assert.strictEqual(res.data.files.fileStream.size, stat.size); - - done(); - }) - .catch(done); - }); - }); - }); - - describe('SpecCompliant FormData', (done) => { - it('should allow passing FormData', async function () { - server = await startHTTPServer(async (req, res) => { - const { fields, files } = await handleFormData(req); - - res.end( - JSON.stringify({ - fields, - files, - }) - ); - }); - - const form = new FormDataSpecCompliant(); - - const blobContent = 'blob-content'; - - const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); - - form.append('foo1', 'bar1'); - form.append('foo2', 'bar2'); - - form.append('file1', blob); - - const { data } = await axios.post(LOCAL_SERVER_URL, form, { - maxRedirects: 0, - }); - - assert.deepStrictEqual(data.fields, { foo1: 'bar1', foo2: 'bar2' }); - - assert.deepStrictEqual(typeof data.files.file1, 'object'); - - const { size, mimetype, originalFilename } = data.files.file1; - - assert.deepStrictEqual( - { size, mimetype, originalFilename }, - { - mimetype: 'image/jpeg', - originalFilename: 'blob', - size: Buffer.from(blobContent).byteLength, - } - ); - }); - }); - - describe('toFormData helper', function () { - it('should properly serialize nested objects for parsing with multer.js (express.js)', function (done) { - var app = express(); - - var obj = { - arr1: ['1', '2', '3'], - arr2: ['1', ['2'], '3'], - obj: { x: '1', y: { z: '1' } }, - users: [ - { name: 'Peter', surname: 'griffin' }, - { name: 'Thomas', surname: 'Anderson' }, - ], - }; - - app.post('/', multer().none(), function (req, res, next) { - res.send(JSON.stringify(req.body)); - }); - - server = app.listen(3001, function () { - // multer can parse the following key/value pairs to an array (indexes: null, false, true): - // arr: '1' - // arr: '2' - // ------------- - // arr[]: '1' - // arr[]: '2' - // ------------- - // arr[0]: '1' - // arr[1]: '2' - // ------------- - Promise.all( - [null, false, true].map(function (mode) { - return axios - .postForm('http://localhost:3001/', obj, { formSerializer: { indexes: mode } }) - .then(function (res) { - assert.deepStrictEqual(res.data, obj, 'Index mode ' + mode); - }); - }) - ).then(function () { - done(); - }, done); - }); - }); - }); - }); - - describe('Blob', function () { - it('should support Blob', async () => { - server = await startHTTPServer(async (req, res) => { - res.end(await getStream(req)); - }); - - const blobContent = 'blob-content'; - - const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); - - const { data } = await axios.post(LOCAL_SERVER_URL, blob, { - maxRedirects: 0, - }); - - assert.deepStrictEqual(data, blobContent); - }); - }); - - describe('URLEncoded Form', function () { - it('should post object data as url-encoded form if content-type is application/x-www-form-urlencoded', function (done) { - var app = express(); - - var obj = { - arr1: ['1', '2', '3'], - arr2: ['1', ['2'], '3'], - obj: { x: '1', y: { z: '1' } }, - users: [ - { name: 'Peter', surname: 'griffin' }, - { name: 'Thomas', surname: 'Anderson' }, - ], - }; - - app.use(bodyParser.urlencoded({ extended: true })); - - app.post('/', function (req, res, next) { - res.send(JSON.stringify(req.body)); - }); - - server = app.listen(3001, function () { - return axios - .post('http://localhost:3001/', obj, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - }) - .then(function (res) { - assert.deepStrictEqual(res.data, obj); - done(); - }) - .catch(done); - }); - }); - }); - - it('should respect formSerializer config', function (done) { - const obj = { - arr1: ['1', '2', '3'], - arr2: ['1', ['2'], '3'], - }; - - const form = new URLSearchParams(); - - form.append('arr1[0]', '1'); - form.append('arr1[1]', '2'); - form.append('arr1[2]', '3'); - - form.append('arr2[0]', '1'); - form.append('arr2[1][0]', '2'); - form.append('arr2[2]', '3'); - - server = http - .createServer(function (req, res) { - req.pipe(res); - }) - .listen(3001, () => { - return axios - .post('http://localhost:3001/', obj, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - formSerializer: { - indexes: true, - }, - }) - .then(function (res) { - assert.strictEqual(res.data, form.toString()); - done(); - }) - .catch(done); - }); - }); - - describe('Data URL', function () { - it('should support requesting data URL as a Buffer', function (done) { - const buffer = Buffer.from('123'); - - const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); - - axios - .get(dataURI) - .then(({ data }) => { - assert.deepStrictEqual(data, buffer); - done(); - }) - .catch(done); - }); - - it('should support requesting data URL as a Blob (if supported by the environment)', function (done) { - if (!isBlobSupported) { - return; - return; - } - - const buffer = Buffer.from('123'); - - const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); - - axios - .get(dataURI, { responseType: 'blob' }) - .then(async ({ data }) => { - assert.strictEqual(data.type, 'application/octet-stream'); - assert.deepStrictEqual(await data.text(), '123'); - done(); - }) - .catch(done); - }); - - it('should support requesting data URL as a String (text)', function (done) { - const buffer = Buffer.from('123', 'utf-8'); - - const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); - - axios - .get(dataURI, { responseType: 'text' }) - .then(({ data }) => { - assert.deepStrictEqual(data, '123'); - done(); - }) - .catch(done); - }); - - it('should support requesting data URL as a Stream', function (done) { - const buffer = Buffer.from('123', 'utf-8'); - - const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64'); - - axios - .get(dataURI, { responseType: 'stream' }) - .then(({ data }) => { - var str = ''; - - data.on('data', function (response) { - str += response.toString(); - }); - - data.on('end', function () { - assert.strictEqual(str, '123'); - done(); - }); - }) - .catch(done); - }); - }); - - describe('progress', function () { - describe('upload', function () { - it('should support upload progress capturing', async function () { - server = await startHTTPServer({ - rate: 100 * 1024, - }); - - let content = ''; - const count = 10; - const chunk = 'test'; - const chunkLength = Buffer.byteLength(chunk); - const contentLength = count * chunkLength; - - var readable = stream.Readable.from( - (async function* () { - let i = count; - - while (i-- > 0) { - await setTimeoutAsync(1100); - content += chunk; - yield chunk; - } - })() - ); - - const samples = []; - - const { data } = await axios.post(LOCAL_SERVER_URL, readable, { - onUploadProgress: ({ loaded, total, progress, bytes, upload }) => { - console.log('onUploadProgress', loaded, '/', total); - samples.push({ - loaded, - total, - progress, - bytes, - upload, - }); - }, - headers: { - 'Content-Length': contentLength, - }, - responseType: 'text', - }); - - assert.strictEqual(data, content); - - assert.deepStrictEqual( - samples, - Array.from( - (function* () { - for (let i = 1; i <= 10; i++) { - yield { - loaded: chunkLength * i, - total: contentLength, - progress: (chunkLength * i) / contentLength, - bytes: 4, - upload: true, - }; - } - })() - ) - ); - }, 15000); - }); - - describe('download', function () { - it('should support download progress capturing', async function () { - - server = await startHTTPServer({ - rate: 100 * 1024, - }); - - let content = ''; - const count = 10; - const chunk = 'test'; - const chunkLength = Buffer.byteLength(chunk); - const contentLength = count * chunkLength; - - var readable = stream.Readable.from( - (async function* () { - let i = count; - - while (i-- > 0) { - await setTimeoutAsync(1100); - content += chunk; - yield chunk; - } - })() - ); - - const samples = []; - - const { data } = await axios.post(LOCAL_SERVER_URL, readable, { - onDownloadProgress: ({ loaded, total, progress, bytes, download }) => { - console.log('onDownloadProgress', loaded, '/', total); - samples.push({ - loaded, - total, - progress, - bytes, - download, - }); - }, - headers: { - 'Content-Length': contentLength, - }, - responseType: 'text', - maxRedirects: 0, - }); - - assert.strictEqual(data, content); - - assert.deepStrictEqual( - samples, - Array.from( - (function* () { - for (let i = 1; i <= 10; i++) { - yield { - loaded: chunkLength * i, - total: contentLength, - progress: (chunkLength * i) / contentLength, - bytes: 4, - download: true, - }; - } - })() - ) - ); - }, 15000); - }); - }); - - describe('Rate limit', function () { - - it('should support upload rate limit', async function () { - const secs = 10; - const configRate = 100_000; - const chunkLength = configRate * secs; - - server = await startHTTPServer(); - - const buf = Buffer.alloc(chunkLength).fill('s'); - const samples = []; - const skip = 4; - const compareValues = toleranceRange(50, 50); - - const { data } = await axios.post(LOCAL_SERVER_URL, buf, { - onUploadProgress: ({ loaded, total, progress, bytes, rate }) => { - samples.push({ - loaded, - total, - progress, - bytes, - rate, - }); - }, - maxRate: [configRate], - responseType: 'text', - maxRedirects: 0, - }); - - samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { - assert.ok( - compareValues(rate, configRate), - `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples - .map(({ rate }) => rate) - .join(', ')}]` - ); - - const progressTicksRate = 2; - const expectedProgress = (i + skip) / secs / progressTicksRate; - - assert.ok( - Math.abs(expectedProgress - progress) < 0.25, - `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples - .map(({ progress }) => progress) - .join(', ')}]` - ); - }); - - assert.strictEqual(data, buf.toString(), 'content corrupted'); - }, 30000); - - it('should support download rate limit', async function () { - const secs = 10; - const configRate = 100_000; - const chunkLength = configRate * secs; - - server = await startHTTPServer(); - - const buf = Buffer.alloc(chunkLength).fill('s'); - const samples = []; - const skip = 4; - const compareValues = toleranceRange(50, 50); - - const { data } = await axios.post(LOCAL_SERVER_URL, buf, { - onDownloadProgress: ({ loaded, total, progress, bytes, rate }) => { - samples.push({ - loaded, - total, - progress, - bytes, - rate, - }); - }, - maxRate: [0, configRate], - responseType: 'text', - maxRedirects: 0, - }); - - samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { - assert.ok( - compareValues(rate, configRate), - `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples - .map(({ rate }) => rate) - .join(', ')}]` - ); - - const progressTicksRate = 3; - const expectedProgress = (i + skip) / secs / progressTicksRate; - - assert.ok( - Math.abs(expectedProgress - progress) < 0.25, - `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples - .map(({ progress }) => progress) - .join(', ')}]` - ); - }); - - assert.strictEqual(data, buf.toString(), 'content corrupted'); - }, 30000); - }); - - describe('request aborting', function () { - //this.timeout(5000); - - it('should be able to abort the response stream', async () => { - server = await startHTTPServer({ - rate: 100_000, - useBuffering: true, - }); - - const buf = Buffer.alloc(1024 * 1024); - - const controller = new AbortController(); - - const { data } = await axios.post(LOCAL_SERVER_URL, buf, { - responseType: 'stream', - signal: controller.signal, - maxRedirects: 0, - }); - - setTimeout(() => { - controller.abort(); - }, 500); - - let streamError; - - data.on('error', function (err) { - streamError = err; - }); - - await assert.rejects(() => pipelineAsync([data, devNull()])); - - assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); - }); - }); - - it('should properly handle synchronous errors inside the adapter', function () { - return assert.rejects(() => axios.get('http://192.168.0.285'), /Invalid URL/); - }); - - it('should support function as paramsSerializer value', async () => { - server = await startHTTPServer((req, res) => res.end(req.url)); - - const { data } = await axios.post(LOCAL_SERVER_URL, 'test', { - params: { - x: 1, - }, - paramsSerializer: () => 'foo', - maxRedirects: 0, - }); - - assert.strictEqual(data, '/?foo'); - }); - - describe('DNS', function () { - it('should support a custom DNS lookup function', async function () { - server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); - - const payload = 'test'; - - let isCalled = false; - - const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { - lookup: (hostname, opt, cb) => { - isCalled = true; - cb(null, '127.0.0.1', 4); - }, - }); - - assert.ok(isCalled); - - assert.strictEqual(data, payload); - }); - - it('should support a custom DNS lookup function with address entry passing', async function () { - server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); - - const payload = 'test'; - - let isCalled = false; - - const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { - lookup: (hostname, opt, cb) => { - isCalled = true; - cb(null, { address: '127.0.0.1', family: 4 }); - }, - }); - - assert.ok(isCalled); - - assert.strictEqual(data, payload); - }); - - it('should support a custom DNS lookup function (async)', async function () { - server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); - - const payload = 'test'; - - let isCalled = false; - - const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { - lookup: async (hostname, opt) => { - isCalled = true; - return ['127.0.0.1', 4]; - }, - }); - - assert.ok(isCalled); - - assert.strictEqual(data, payload); - }); - - it('should support a custom DNS lookup function with address entry (async)', async function () { - server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); - - const payload = 'test'; - - let isCalled = false; - - const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { - lookup: async (hostname, opt) => { - isCalled = true; - return { address: '127.0.0.1', family: 4 }; - }, - }); - - assert.ok(isCalled); - - assert.strictEqual(data, payload); - }); - - it('should support a custom DNS lookup function that returns only IP address (async)', async function () { - server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); - - const payload = 'test'; - - let isCalled = false; - - const { data } = await axios.post(`http://fake-name.axios:4444`, payload, { - lookup: async (hostname, opt) => { - isCalled = true; - return '127.0.0.1'; - }, - }); - - assert.ok(isCalled); - - assert.strictEqual(data, payload); - }); - - it('should handle errors', () => { - return assert.rejects(async () => { - await axios.get('https://no-such-domain-987654.com', { - lookup, - }); - }, /ENOTFOUND/); - }); - }); - - describe('JSON', function () { - it('should support reviver on JSON.parse', async function () { - server = await startHTTPServer(async (_, res) => { - res.end( - JSON.stringify({ - foo: 'bar', - }) - ); - }); - - const { data } = await axios.get(LOCAL_SERVER_URL, { - parseReviver: (key, value) => { - return key === 'foo' ? 'success' : value; - }, - }); - - assert.deepStrictEqual(data, { foo: 'success' }); - }); - }); - - describe('HTTP2', function () { - const LOCAL_SERVER_URL = 'https://127.0.0.1:4444'; - - const http2Axios = axios.create({ - baseURL: LOCAL_SERVER_URL, - httpVersion: 2, - http2Options: { - rejectUnauthorized: false, - }, - }); - - it('should merge request http2Options with its instance config', async () => { - const { data } = await http2Axios.get('/', { - http2Options: { - foo: 'test', - }, - adapter: async (config) => { - return { - data: config.http2Options, - }; - }, - }); - - assert.deepStrictEqual(data, { - rejectUnauthorized: false, - foo: 'test', - }); - }); - - it('should support http2 transport', async () => { - server = await startHTTPServer( - (req, res) => { - res.end('OK'); - }, - { - useHTTP2: true, - } - ); - - const { data } = await http2Axios.get(LOCAL_SERVER_URL); - - assert.deepStrictEqual(data, 'OK'); - }); - - it(`should support request payload`, async () => { - server = await startHTTPServer(null, { - useHTTP2: true, - }); - - const payload = 'DATA'; - - const { data } = await http2Axios.post(LOCAL_SERVER_URL, payload); - - assert.deepStrictEqual(data, payload); - }); - - it(`should support FormData as a payload`, async function () { - if (typeof FormData !== 'function') { - return; - } - - server = await startHTTPServer( - async (req, res) => { - const { fields, files } = await handleFormData(req); - - res.end( - JSON.stringify({ - fields, - files, - }) - ); - }, - { - useHTTP2: true, - } - ); - - const form = new FormData(); - - form.append('x', 'foo'); - form.append('y', 'bar'); - - const { data } = await http2Axios.post(LOCAL_SERVER_URL, form); - - assert.deepStrictEqual(data, { - fields: { - x: 'foo', - y: 'bar', - }, - files: {}, - }); - }); - - describe('response types', () => { - const originalData = '{"test": "OK"}'; - - const fixtures = { - text: (v) => assert.strictEqual(v, originalData), - arraybuffer: (v) => assert.deepStrictEqual(v, Buffer.from(originalData)), - stream: async (v) => assert.deepStrictEqual(await getStream(v), originalData), - json: async (v) => assert.deepStrictEqual(v, JSON.parse(originalData)), - }; - - for (let [responseType, assertValue] of Object.entries(fixtures)) { - it(`should support ${responseType} response type`, async () => { - server = await startHTTPServer( - (req, res) => { - res.end(originalData); - }, - { - useHTTP2: true, - } - ); - - const { data } = await http2Axios.get(LOCAL_SERVER_URL, { - responseType, - }); - - await assertValue(data); - }); - } - }); - - it('should support request timeout', async () => { - let isAborted = false; - - let aborted; - const promise = new Promise((resolve) => (aborted = resolve)); - - server = await startHTTPServer( - (req, res) => { - setTimeout(() => { - res.end('OK'); - }, 15000); - }, - { - useHTTP2: true, - } - ); - - server.on('stream', (stream) => { - stream.once('aborted', () => { - isAborted = true; - aborted(); - }); - }); - - await assert.rejects(async () => { - await http2Axios.get(LOCAL_SERVER_URL, { - timeout: 500, - }); - }, /timeout/); - - await promise; - - assert.ok(isAborted); - }); - - it('should support request cancellation', async function () { - if (typeof AbortSignal !== 'function' || !AbortSignal.timeout) { - return; - } - - let isAborted = false; - - let aborted; - const promise = new Promise((resolve) => (aborted = resolve)); - - server = await startHTTPServer( - (req, res) => { - setTimeout(() => { - res.end('OK'); - }, 15000); - }, - { - useHTTP2: true, - } - ); - - server.on('stream', (stream) => { - stream.once('aborted', () => { - isAborted = true; - aborted(); - }); - }); - - await assert.rejects(async () => { - await http2Axios.get(LOCAL_SERVER_URL, { - signal: AbortSignal.timeout(500), - }); - }, /CanceledError: canceled/); - - await promise; - - assert.ok(isAborted); - }); - - it('should support stream response cancellation', async () => { - let isAborted = false; - var source = axios.CancelToken.source(); - - let aborted; - const promise = new Promise((resolve) => (aborted = resolve)); - - server = await startHTTPServer( - (req, res) => { - generateReadable(10000, 100, 100).pipe(res); - }, - { - useHTTP2: true, - } - ); - - server.on('stream', (stream) => { - stream.once('aborted', () => { - isAborted = true; - aborted(); - }); - }); - - const { data } = await http2Axios.get(LOCAL_SERVER_URL, { - cancelToken: source.token, - responseType: 'stream', - }); - - setTimeout(() => source.cancel()); - - await assert.rejects(() => pipelineAsync([data, devNull()]), /CanceledError: canceled/); - - await promise; - - assert.ok(isAborted); - }); - - describe('session', () => { - it('should reuse session for the target authority', async () => { - server = await startHTTPServer( - (req, res) => { - setTimeout(() => res.end('OK'), 1000); - }, - { - useHTTP2: true, - } - ); - - const [response1, response2] = await Promise.all([ - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - }), - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - }), - ]); - - assert.strictEqual(response1.data.session, response2.data.session); - - assert.deepStrictEqual( - await Promise.all([getStream(response1.data), getStream(response2.data)]), - ['OK', 'OK'] - ); - }); - - it('should use different sessions for different authorities', async () => { - server = await startHTTPServer( - (req, res) => { - setTimeout(() => { - res.end('OK'); - }, 2000); - }, - { - useHTTP2: true, - } - ); - - server2 = await startHTTPServer( - (req, res) => { - setTimeout(() => { - res.end('OK'); - }, 2000); - }, - { - useHTTP2: true, - port: SERVER_PORT2, - } - ); - - const [response1, response2] = await Promise.all([ - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - }), - http2Axios.get(LOCAL_SERVER_URL2, { - responseType: 'stream', - }), - ]); - - assert.notStrictEqual(response1.data.session, response2.data.session); - - assert.deepStrictEqual( - await Promise.all([getStream(response1.data), getStream(response2.data)]), - ['OK', 'OK'] - ); - }); - - it('should use different sessions for requests with different http2Options set', async () => { - server = await startHTTPServer( - (req, res) => { - setTimeout(() => { - res.end('OK'); - }, 1000); - }, - { - useHTTP2: true, - } - ); - - const [response1, response2] = await Promise.all([ - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: {}, - }), - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: { - foo: 'test', - }, - }), - ]); - - assert.notStrictEqual(response1.data.session, response2.data.session); - - assert.deepStrictEqual( - await Promise.all([getStream(response1.data), getStream(response2.data)]), - ['OK', 'OK'] - ); - }); - - it('should use the same session for request with the same resolved http2Options set', async () => { - server = await startHTTPServer( - (req, res) => { - setTimeout(() => res.end('OK'), 1000); - }, - { - useHTTP2: true, - } - ); - - const responses = await Promise.all([ - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - }), - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: undefined, - }), - http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: {}, - }), - ]); - - assert.strictEqual(responses[1].data.session, responses[0].data.session); - assert.strictEqual(responses[2].data.session, responses[0].data.session); - - assert.deepStrictEqual(await Promise.all(responses.map(({ data }) => getStream(data))), [ - 'OK', - 'OK', - 'OK', - ]); - }); - - it('should use different sessions after previous session timeout', async () => { - server = await startHTTPServer( - (req, res) => { - setTimeout(() => res.end('OK'), 100); - }, - { - useHTTP2: true, - } - ); - - const response1 = await http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: { - sessionTimeout: 1000, - }, - }); - - const data1 = await getStream(response1.data); - - await setTimeoutAsync(5000); - - const response2 = await http2Axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - http2Options: { - sessionTimeout: 1000, - }, - }); - - const data2 = await getStream(response2.data); - - assert.notStrictEqual(response1.data.session, response2.data.session); - - assert.strictEqual(data1, 'OK'); - assert.strictEqual(data2, 'OK'); - }, 15000); - }); - }); - - it('should not abort stream on settle rejection', async () => { - server = await startHTTPServer((req, res) => { - res.statusCode = 404; - res.end('OK'); - }); - - try { - await axios.get(LOCAL_SERVER_URL, { - responseType: 'stream', - }); - - assert.fail('should be rejected'); - } catch (err) { - assert.strictEqual(await getStream(err.response.data), 'OK'); - } - }); - - describe('keep-alive', () => { - it('should not fail with "socket hang up" when using timeouts', async () => { - server = await startHTTPServer(async (req, res) => { - if (req.url === '/wait') { - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - res.end('ok'); - }); - const baseURL = LOCAL_SERVER_URL; - await axios.get('/1', { baseURL, timeout: 1000 }); - await axios.get(`/wait`, { baseURL, timeout: 0 }); - }, 15000); + await stopHTTPServer(server); }); }); diff --git a/vitest.config.js b/vitest.config.js index 87fc0f202e..0a4b714498 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -10,7 +10,7 @@ export default defineConfig({ name: 'unit', environment: 'node', include: ['tests/unit/**/*.test.js'], - setupFiles: ['tests/setup/unit.setup.js'], + setupFiles: [], }, }, { From 6d83cf4202d8b01f2c495a8d7cb5916fc87ebc44 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Wed, 4 Mar 2026 20:58:30 +0200 Subject: [PATCH 07/37] chore: wip http tests --- tests/unit/adapters/http.test.js | 304 +++++++++++++++++++++++++++++-- 1 file changed, 292 insertions(+), 12 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 4e2ad3ab07..37e0488856 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -3,6 +3,8 @@ import assert from 'assert'; import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; +import http from 'http'; +import stream from 'stream'; describe('supports http with nodejs', () => { it('should support IPv4 literal strings', async () => { @@ -17,11 +19,12 @@ describe('supports http with nodejs', () => { res.end(JSON.stringify(data)); }); - const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); - - assert.deepStrictEqual(responseData, data); - - await stopHTTPServer(server); + try { + const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); + assert.deepStrictEqual(responseData, data); + } finally { + await stopHTTPServer(server); + } }); it('should support IPv6 literal strings', async () => { @@ -36,29 +39,306 @@ describe('supports http with nodejs', () => { res.end(JSON.stringify(data)); }); - const { data: responseData } = await axios.get(`http://[::1]:${server.address().port}`); + try { + const { data: responseData } = await axios.get(`http://[::1]:${server.address().port}`, { + proxy: false, + }); + assert.deepStrictEqual(responseData, data); + } finally { + await stopHTTPServer(server); + } + }); + + it('should throw an error if the timeout property is not parsable as a number', async () => { + const server = await startHTTPServer((req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }); + + try { + await assert.rejects( + axios.get(`http://127.0.0.1:${server.address().port}`, { + timeout: { strangeTimeout: 250 }, + }), + (error) => { + assert.strictEqual(error.code, AxiosError.ERR_BAD_OPTION_VALUE); + assert.strictEqual(error.message, 'error trying to parse `config.timeout` to int'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); - assert.deepStrictEqual(responseData, data); + it('should parse the timeout property', async () => { + const server = await startHTTPServer((req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }); - await stopHTTPServer(server); + try { + await assert.rejects( + axios.get(`http://127.0.0.1:${server.address().port}`, { + timeout: '250', + }), + (error) => { + assert.strictEqual(error.code, 'ECONNABORTED'); + assert.strictEqual(error.message, 'timeout of 250ms exceeded'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } }); - it('should throw an error if the timeout property is not parsable as a number', async () => { + it('should respect the timeout property', async () => { + const server = await startHTTPServer((req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }); + + try { + await assert.rejects( + axios.get(`http://127.0.0.1:${server.address().port}`, { + timeout: 250, + }), + (error) => { + assert.strictEqual(error.code, 'ECONNABORTED'); + assert.strictEqual(error.message, 'timeout of 250ms exceeded'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should respect the timeoutErrorMessage property', async () => { const server = await startHTTPServer((req, res) => { setTimeout(() => { res.end(); }, 1000); }); + try { + await assert.rejects( + axios.get(`http://127.0.0.1:${server.address().port}`, { + timeout: 250, + timeoutErrorMessage: 'oops, timeout', + }), + (error) => { + assert.strictEqual(error.code, 'ECONNABORTED'); + assert.strictEqual(error.message, 'oops, timeout'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should allow passing JSON', async () => { + const data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }); + + try { + const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); + assert.deepStrictEqual(responseData, data); + } finally { + await stopHTTPServer(server); + } + }); + + it('should allow passing JSON with BOM', async () => { + const data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + const bomBuffer = Buffer.from([0xef, 0xbb, 0xbf]); + const jsonBuffer = Buffer.from(JSON.stringify(data)); + res.end(Buffer.concat([bomBuffer, jsonBuffer])); + }); + + try { + const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); + assert.deepStrictEqual(responseData, data); + } finally { + await stopHTTPServer(server); + } + }); + + it('should redirect', async () => { + const expectedResponse = 'test response'; + const server = await startHTTPServer((req, res) => { + if (req.url === '/one') { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + return; + } + + res.end(expectedResponse); + }); + + try { + const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + maxRedirects: 1, + }); + + assert.strictEqual(response.data, expectedResponse); + assert.strictEqual(response.request.path, '/two'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should not redirect', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }); + + try { + const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + maxRedirects: 0, + }); + + assert.strictEqual(response.status, 302); + assert.strictEqual(response.headers.location, '/foo'); + } catch (error) { + assert.strictEqual(error.message, 'Request failed with status code 302'); + assert.strictEqual(error.response.status, 302); + assert.strictEqual(error.response.headers.location, '/foo'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support max redirects', async () => { + var i = 1; + const server = await startHTTPServer((req, res) => { + res.setHeader('Location', `/${i}`); + res.statusCode = 302; + res.end(); + i++; + }); + try { await axios.get(`http://127.0.0.1:${server.address().port}`, { - timeout: { strangeTimeout: 250 }, + maxRedirects: 3, + }); + } catch (error) { + assert.strictEqual(error.code, AxiosError.ERR_FR_TOO_MANY_REDIRECTS); + assert.strictEqual(error.message, 'Maximum number of redirects exceeded'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support beforeRedirect', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }); + + try { + await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + maxRedirects: 3, + beforeRedirect: (options, responseDetails) => { + if (options.path === '/foo' && responseDetails.headers.location === '/foo') { + throw new Error('Provided path is not allowed'); + } + }, }); } catch (error) { - assert.strictEqual(error.code, AxiosError.ERR_BAD_OPTION_VALUE); - assert.strictEqual(error.message, 'error trying to parse `config.timeout` to int'); + assert.strictEqual(error.message, 'Redirected request failed: Provided path is not allowed'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support beforeRedirect and proxy with redirect', async () => { + let requestCount = 0; + let proxyUseCount = 0; + let totalRedirectCount = 5; + let configBeforeRedirectCount = 0; + + const server = await startHTTPServer((req, res) => { + requestCount += 1; + if (requestCount <= totalRedirectCount) { + res.setHeader('Location', 'http://127.0.0.1:4444'); + res.writeHead(302); + } + res.end(); + }); + + const proxy = await startHTTPServer( + (req, res) => { + proxyUseCount += 1; + const targetUrl = new URL(req.url, 'http://' + req.headers.host); + const opts = { + host: targetUrl.hostname, + port: targetUrl.port, + path: targetUrl.path, + method: req.method, + }; + + const request = http.get(opts, (response) => { + res.writeHead(response.statusCode, response.headers); + stream.pipeline(response, res, () => {}); + }); + + request.on('error', (err) => { + console.warn('request error', err); + res.statusCode = 500; + res.end(); + }); + }, + { port: 4000 } + ); + + console.log('proxy server', proxy.address()); + console.log('server server', server.address()); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: 4000, + }, + maxRedirects: totalRedirectCount, + beforeRedirect: (options) => { + configBeforeRedirectCount += 1; + }, + }); + console.log(response); + + assert.strictEqual(totalRedirectCount, configBeforeRedirectCount); + assert.strictEqual(totalRedirectCount + 1, proxyUseCount); + } catch (error) { + console.log(error); } await stopHTTPServer(server); + await stopHTTPServer(proxy); }); }); From f36988c2126d0c7b7abe2546c7cc95f715268c08 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 13:13:21 +0200 Subject: [PATCH 08/37] chore: wip http tests --- ...dapters-esm-ts-modernization-brainstorm.md | 33 +++++++++++ tests/unit/adapters/http.test.js | 58 +++++++++++++------ 2 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md diff --git a/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md b/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md new file mode 100644 index 0000000000..098ed755b3 --- /dev/null +++ b/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md @@ -0,0 +1,33 @@ +--- +date: 2026-03-04 +topic: adapters-esm-ts-modernization +--- + +# Adapters ESM + TypeScript Modernization + +## What We're Building +We want a full modernization of Axios adapters so adapter internals are TypeScript-friendly and align with modern ESM-first development. The modernization should cover `http`, `xhr`, and `fetch` adapter areas and the adapter resolution surface anchored in `lib/adapters/adapters.js`. + +The target is improved maintainability, clearer type contracts in implementation code, and cleaner long-term adapter evolution, while respecting the project's existing cross-environment adapter semantics (name/function resolution, availability checks, and runtime adapter selection behavior). + +## Why This Approach +Three options were considered: compatibility-first full modernization, milestone cleanup with controlled breaking surface, and clean-slate modern platform reset. The selected direction is compatibility-first full modernization because it matches the repo's established pattern of incremental modernization backed by broad compatibility tests and dual-module distribution support. + +This keeps momentum high while reducing ecosystem risk. It also avoids introducing unnecessary architectural churn before proving value in adapter internals and build/type ergonomics. + +## Key Decisions +- **Full modernization scope:** The effort includes TypeScript-oriented modernization across adapter internals and ESM alignment, not only test/type touch-ups. +- **Compatibility-first posture:** Preserve current runtime behavior and adapter resolution semantics as the default success condition. +- **Adapter resolver contract remains stable:** `getAdapter` behavior, adapter availability signaling (`false`/`null`), and unknown adapter error semantics remain externally consistent. +- **Dual-module reality is acknowledged:** Changes should respect existing ESM/CJS distribution expectations unless explicitly revisited later. +- **Incremental delivery bias:** Even under full scope, work should be broken into reviewable phases to reduce regression risk. + +## Resolved Questions +- **Modernization depth:** Full modernization (not partial) was explicitly requested. +- **Preferred strategy among alternatives:** No explicit alternative was selected after options were presented, so we default to the recommended compatibility-first path. + +## Open Questions +- None at this stage. + +## Next Steps +Proceed to `/workflows:plan` to define implementation phases, file-level changes, validation strategy, and rollout checkpoints. diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 37e0488856..7e38775a67 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -316,29 +316,49 @@ describe('supports http with nodejs', () => { { port: 4000 } ); - console.log('proxy server', proxy.address()); - console.log('server server', server.address()); + await axios.get(`http://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: 4000, + }, + maxRedirects: totalRedirectCount, + beforeRedirect: (options) => { + configBeforeRedirectCount += 1; + }, + }); + + assert.strictEqual(totalRedirectCount, configBeforeRedirectCount); + assert.strictEqual(totalRedirectCount + 1, proxyUseCount); + + await stopHTTPServer(server); + await stopHTTPServer(proxy); + }); + + it('should wrap HTTP errors and keep stack', async () => { + const server = await startHTTPServer((req, res) => { + res.statusCode = 400; + res.end(); + }); try { - const response = await axios.get(`http://localhost:${server.address().port}/`, { - proxy: { - host: 'localhost', - port: 4000, - }, - maxRedirects: totalRedirectCount, - beforeRedirect: (options) => { - configBeforeRedirectCount += 1; + await assert.rejects( + async function stackTraceTest() { + await axios.get(`http://localhost:${server.address().port}/`); }, - }); - console.log(response); + (error) => { + const matches = [...error.stack.matchAll(/stackTraceTest/g)]; - assert.strictEqual(totalRedirectCount, configBeforeRedirectCount); - assert.strictEqual(totalRedirectCount + 1, proxyUseCount); - } catch (error) { - console.log(error); - } + assert.strictEqual(error.name, 'AxiosError'); + assert.strictEqual(error.isAxiosError, true); + assert.strictEqual(error.code, AxiosError.ERR_BAD_REQUEST); + assert.strictEqual(error.message, 'Request failed with status code 400'); + assert.strictEqual(matches.length, 1, error.stack); - await stopHTTPServer(server); - await stopHTTPServer(proxy); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } }); }); From c11bf727a641d9d86cd662ede25d0badb7c77fa1 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 15:17:58 +0200 Subject: [PATCH 09/37] chore: more http tests --- tests/unit/adapters/http.test.js | 146 +++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 7e38775a67..0dea80721b 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -5,6 +5,8 @@ import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; import stream from 'stream'; +import url from 'url'; +import zlib from 'zlib'; describe('supports http with nodejs', () => { it('should support IPv4 literal strings', async () => { @@ -361,4 +363,148 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); + + it('should wrap interceptor errors and keep stack', async () => { + const axiosInstance = axios.create(); + + axiosInstance.interceptors.request.use((res) => { + throw new Error('from request interceptor'); + }); + + const server = await startHTTPServer( + (req, res) => { + res.end(); + }, + { port: 4444 } + ); + + try { + await assert.rejects( + async function stackTraceTest() { + await axiosInstance.get(`http://localhost:${server.address().port}/one`); + }, + (error) => { + const matches = [...error.stack.matchAll(/stackTraceTest/g)]; + + assert.strictEqual(error.name, 'Error'); + assert.strictEqual(error.message, 'from request interceptor'); + assert.strictEqual(matches.length, 1, error.stack); + + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should preserve the HTTP verb on redirect', async () => { + const server = await startHTTPServer( + (req, res) => { + if (req.method.toLowerCase() !== 'head') { + res.statusCode = 400; + res.end(); + return; + } + + var parsed = url.parse(req.url); + if (parsed.pathname === '/one') { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + } else { + res.end(); + } + }, + { port: 4444 } + ); + + try { + const response = await axios.head(`http://localhost:${server.address().port}/one`); + assert.strictEqual(response.status, 200); + } finally { + await stopHTTPServer(server); + } + }); + + describe('compression', async () => { + it('should support transparent gunzip', async () => { + const data = { + firstName: 'Fred', + lastName: 'Flintstone', + emailAddr: 'fred@example.com', + }; + + const zipped = await new Promise((resolve, reject) => { + zlib.gzip(JSON.stringify(data), (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }); + + try { + const { data: responseData } = await axios.get(`http://localhost:${server.address().port}/`); + assert.deepStrictEqual(responseData, data); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support gunzip error handling', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end('invalid response'); + }); + + try { + await assert.rejects(async () => { + await axios.get(`http://localhost:${server.address().port}/`); + }); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support disabling automatic decompression of response data', async () => { + const data = 'Test data'; + + const zipped = await new Promise((resolve, reject) => { + zlib.gzip(data, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html;charset=utf-8'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + decompress: false, + responseType: 'arraybuffer', + }); + assert.strictEqual(response.data.toString('base64'), zipped.toString('base64')); + } finally { + await stopHTTPServer(server); + } + }); + }); }); From 9a8d9a7d4d74ddf0d5a98c7a4c9a1a9a5667d840 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 16:06:58 +0200 Subject: [PATCH 10/37] chore: tests --- tests/unit/adapters/http.test.js | 145 +++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 0dea80721b..671764a85f 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -507,4 +507,149 @@ describe('supports http with nodejs', () => { } }); }); + + /// algos for later + + it('should support UTF8', async () => { + const str = Array(100000).join('ж'); + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + assert.strictEqual(response.data, str); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support basic auth', async () => { + const server = await startHTTPServer((req, res) => { + res.end(req.headers.authorization); + }); + + try { + const user = 'foo'; + const headers = { Authorization: 'Bearer 1234' }; + const response = await axios.get(`http://${user}@localhost:${server.address().port}/`, { headers }); + const base64 = Buffer.from(`${user}:`, 'utf8').toString('base64'); + assert.strictEqual(response.data, `Basic ${base64}`); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support basic auth with a header', async () => { + const server = await startHTTPServer((req, res) => { + res.end(req.headers.authorization); + }); + + try { + const auth = { username: 'foo', password: 'bar' }; + const headers = { AuThOrIzAtIoN: 'Bearer 1234' }; // wonky casing to ensure caseless comparison + const response = await axios.get(`http://localhost:${server.address().port}/`, { auth, headers }); + const base64 = Buffer.from('foo:bar', 'utf8').toString('base64'); + assert.strictEqual(response.data, `Basic ${base64}`); + } finally { + await stopHTTPServer(server); + } + }); + + it('should provides a default User-Agent header', async () => { + const server = await startHTTPServer((req, res) => { + res.end(req.headers['user-agent']); + }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + assert.ok( + /^axios\/[\d.]+[-]?[a-z]*[.]?[\d]+$/.test(response.data), + `User-Agent header does not match: ${response.data}` + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should allow the User-Agent header to be overridden', async () => { + const server = await startHTTPServer((req, res) => { + res.end(req.headers['user-agent']); + }); + + try { + const headers = { 'UsEr-AgEnT': 'foo bar' }; // wonky casing to ensure caseless comparison + const response = await axios.get(`http://localhost:${server.address().port}/`, { headers }); + assert.strictEqual(response.data, 'foo bar'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should allow the Content-Length header to be overridden', async () => { + const server = await startHTTPServer((req, res) => { + assert.strictEqual(req.headers['content-length'], '42'); + res.end(); + }); + + try { + const headers = { 'CoNtEnT-lEnGtH': '42' }; // wonky casing to ensure caseless comparison + await axios.post(`http://localhost:${server.address().port}/`, 'foo', { headers }); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support max content length', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(Array(5000).join('#')); + }); + + try { + await assert.rejects( + axios.get(`http://localhost:${server.address().port}/`, { + maxContentLength: 2000, + maxRedirects: 0, + }), + /maxContentLength size of 2000 exceeded/ + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support max content length for redirected', async () => { + const str = Array(100000).join('ж'); + const server = await startHTTPServer((req, res) => { + const parsed = url.parse(req.url); + + if (parsed.pathname === '/two') { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + return; + } + + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + }); + + try { + await assert.rejects( + axios.get(`http://localhost:${server.address().port}/one`, { + maxContentLength: 2000, + }), + (error) => { + assert.strictEqual(error.message, 'maxContentLength size of 2000 exceeded'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + }); From 02b96593c198790ff1626b1093aff2d1c0ed1860 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 16:10:45 +0200 Subject: [PATCH 11/37] chore: tests --- tests/unit/adapters/http.test.js | 162 ++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 3 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 671764a85f..0d1be87561 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -4,9 +4,11 @@ import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; +import net from 'net'; import stream from 'stream'; import url from 'url'; import zlib from 'zlib'; +import fs from 'fs'; describe('supports http with nodejs', () => { it('should support IPv4 literal strings', async () => { @@ -453,7 +455,9 @@ describe('supports http with nodejs', () => { }); try { - const { data: responseData } = await axios.get(`http://localhost:${server.address().port}/`); + const { data: responseData } = await axios.get( + `http://localhost:${server.address().port}/` + ); assert.deepStrictEqual(responseData, data); } finally { await stopHTTPServer(server); @@ -534,7 +538,9 @@ describe('supports http with nodejs', () => { try { const user = 'foo'; const headers = { Authorization: 'Bearer 1234' }; - const response = await axios.get(`http://${user}@localhost:${server.address().port}/`, { headers }); + const response = await axios.get(`http://${user}@localhost:${server.address().port}/`, { + headers, + }); const base64 = Buffer.from(`${user}:`, 'utf8').toString('base64'); assert.strictEqual(response.data, `Basic ${base64}`); } finally { @@ -550,7 +556,10 @@ describe('supports http with nodejs', () => { try { const auth = { username: 'foo', password: 'bar' }; const headers = { AuThOrIzAtIoN: 'Bearer 1234' }; // wonky casing to ensure caseless comparison - const response = await axios.get(`http://localhost:${server.address().port}/`, { auth, headers }); + const response = await axios.get(`http://localhost:${server.address().port}/`, { + auth, + headers, + }); const base64 = Buffer.from('foo:bar', 'utf8').toString('base64'); assert.strictEqual(response.data, `Basic ${base64}`); } finally { @@ -652,4 +661,151 @@ describe('supports http with nodejs', () => { } }); + it('should support max body length', async () => { + const data = Array(100000).join('ж'); + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(); + }); + + try { + await assert.rejects( + axios.post( + `http://localhost:${server.address().port}/`, + { + data, + }, + { + maxBodyLength: 2000, + } + ), + (error) => { + assert.strictEqual(error.message, 'Request body larger than maxBodyLength limit'); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should properly support default max body length (follow-redirects as well)', async () => { + // Taken from follow-redirects defaults. + const followRedirectsMaxBodyDefaults = 10 * 1024 * 1024; + const data = Array(2 * followRedirectsMaxBodyDefaults).join('ж'); + + const server = await startHTTPServer((req, res) => { + // Consume the req stream before responding to avoid ECONNRESET. + req.on('data', () => {}); + req.on('end', () => { + res.end('OK'); + }); + }); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, { + data, + }); + assert.strictEqual(response.data, 'OK', 'should handle response'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should display error while parsing params', async () => { + const server = await startHTTPServer(() => {}); + + try { + await assert.rejects( + axios.get(`http://localhost:${server.address().port}/`, { + params: { + errorParam: new Date(undefined), + }, + }), + (error) => { + assert.deepStrictEqual(error.exists, true); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support sockets', async () => { + let socketName = './test.sock'; + + if (process.platform === 'win32') { + socketName = '\\\\.\\pipe\\libuv-test'; + } + + const server = await new Promise((resolve, reject) => { + const socketServer = net + .createServer((socket) => { + socket.on('data', () => { + socket.end('HTTP/1.1 200 OK\r\n\r\n'); + }); + }) + .listen(socketName, () => resolve(socketServer)); + + socketServer.on('error', reject); + }); + + try { + const response = await axios({ + socketPath: socketName, + url: 'http://localhost:4444/socket', + }); + assert.strictEqual(response.status, 200); + assert.strictEqual(response.statusText, 'OK'); + } finally { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + } + }); + + describe('streams', () => { + it('should support streams', async () => { + const server = await startHTTPServer((req, res) => { + req.pipe(res); + }); + + try { + const currentFilePath = url.fileURLToPath(import.meta.url); + const response = await axios.post( + `http://localhost:${server.address().port}/`, + fs.createReadStream(currentFilePath), + { + responseType: 'stream', + } + ); + + const responseText = await new Promise((resolve, reject) => { + const chunks = []; + + response.data.on('data', (chunk) => { + chunks.push(chunk); + }); + + response.data.on('end', () => { + resolve(Buffer.concat(chunks).toString('utf8')); + }); + + response.data.on('error', reject); + }); + + assert.strictEqual(responseText, fs.readFileSync(currentFilePath, 'utf8')); + } finally { + await stopHTTPServer(server); + } + }); + }); }); From 19647ccf5477964c4052328e87a4f2537ce63d7d Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 16:12:30 +0200 Subject: [PATCH 12/37] chore: tests --- tests/unit/adapters/http.test.js | 233 ++++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 4 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 0d1be87561..cbba6d2507 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1,16 +1,22 @@ import { describe, it } from 'vitest'; import assert from 'assert'; -import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; +import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; +import https from 'https'; import net from 'net'; import stream from 'stream'; import url from 'url'; import zlib from 'zlib'; import fs from 'fs'; +import path from 'path'; +import devNull from 'dev-null'; describe('supports http with nodejs', () => { + const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); + const thisTestFilePath = path.join(adaptersTestsDir, 'http.test.js'); + it('should support IPv4 literal strings', async () => { const data = { firstName: 'Fred', @@ -769,6 +775,138 @@ describe('supports http with nodejs', () => { resolve(); }); }); + + if (process.platform !== 'win32') { + try { + fs.unlinkSync(socketName); + } catch (error) { + // Ignore socket unlink errors; socket may already be cleaned up. + } + } + } + }); + + it('should support HTTP proxies', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }); + + const proxy = await startHTTPServer((request, response) => { + const parsed = url.parse(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + }; + + http.get(opts, (res) => { + let body = ''; + res.on('data', (data) => { + body += data; + }); + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: proxy.address().port, + }, + }); + + assert.strictEqual(response.data, '123456789', 'should pass through proxy'); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + } + }); + + it('should support HTTPS proxies', async () => { + const options = { + key: fs.readFileSync(path.join(adaptersTestsDir, 'key.pem')), + cert: fs.readFileSync(path.join(adaptersTestsDir, 'cert.pem')), + }; + + const server = await new Promise((resolve, reject) => { + const targetServer = https + .createServer(options, (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }) + .listen(0, () => resolve(targetServer)); + + targetServer.on('error', reject); + }); + + const proxy = await new Promise((resolve, reject) => { + const proxyServer = https + .createServer(options, (request, response) => { + const parsed = url.parse(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path, + protocol: parsed.protocol, + rejectUnauthorized: false, + }; + + https.get(opts, (res) => { + let body = ''; + res.on('data', (data) => { + body += data; + }); + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }) + .listen(0, () => resolve(proxyServer)); + + proxyServer.on('error', reject); + }); + + try { + const response = await axios.get(`https://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: proxy.address().port, + protocol: 'https:', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }); + + assert.strictEqual(response.data, '123456789', 'should pass through proxy'); + } finally { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + + await new Promise((resolve, reject) => { + proxy.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); } }); @@ -779,10 +917,9 @@ describe('supports http with nodejs', () => { }); try { - const currentFilePath = url.fileURLToPath(import.meta.url); const response = await axios.post( `http://localhost:${server.address().port}/`, - fs.createReadStream(currentFilePath), + fs.createReadStream(thisTestFilePath), { responseType: 'stream', } @@ -802,10 +939,98 @@ describe('supports http with nodejs', () => { response.data.on('error', reject); }); - assert.strictEqual(responseText, fs.readFileSync(currentFilePath, 'utf8')); + assert.strictEqual(responseText, fs.readFileSync(thisTestFilePath, 'utf8')); + } finally { + await stopHTTPServer(server); + } + }); + + it('should pass errors for a failed stream', async () => { + const server = await startHTTPServer(); + const notExistPath = path.join(adaptersTestsDir, 'does_not_exist'); + + try { + await assert.rejects( + axios.post(`http://localhost:${server.address().port}/`, fs.createReadStream(notExistPath)), + (error) => { + assert.strictEqual( + error.message, + `ENOENT: no such file or directory, open '${notExistPath}'` + ); + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should destroy the response stream with an error on request stream destroying', async () => { + const server = await startHTTPServer(); + const requestStream = generateReadable(); + + setTimeout(() => { + requestStream.destroy(); + }, 1000); + + const { data } = await axios.post(`http://localhost:${server.address().port}/`, requestStream, { + responseType: 'stream', + }); + + let streamError; + data.on('error', (error) => { + streamError = error; + }); + + try { + await new Promise((resolve, reject) => { + stream.pipeline(data, devNull(), (error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); + assert.fail('stream was not aborted'); + } catch (error) { + // Expected: pipeline should reject after request stream is destroyed. } finally { + assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); await stopHTTPServer(server); } }); }); + + it('should support buffers', async () => { + const buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) + const server = await startHTTPServer((req, res) => { + assert.strictEqual(req.headers['content-length'], buf.length.toString()); + req.pipe(res); + }); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, buf, { + responseType: 'stream', + }); + + const responseText = await new Promise((resolve, reject) => { + const chunks = []; + + response.data.on('data', (chunk) => { + chunks.push(chunk); + }); + + response.data.on('end', () => { + resolve(Buffer.concat(chunks).toString('utf8')); + }); + + response.data.on('error', reject); + }); + + assert.strictEqual(responseText, buf.toString()); + } finally { + await stopHTTPServer(server); + } + }); }); From 66666509a0ec98ccbcbbef8b3f44b88db4604335 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 16:17:05 +0200 Subject: [PATCH 13/37] chore: tests --- tests/unit/adapters/http.test.js | 209 +------------------------------ 1 file changed, 5 insertions(+), 204 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index cbba6d2507..c84a138dc2 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1,17 +1,15 @@ import { describe, it } from 'vitest'; import assert from 'assert'; -import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/server.js'; +import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; -import https from 'https'; import net from 'net'; import stream from 'stream'; import url from 'url'; import zlib from 'zlib'; import fs from 'fs'; import path from 'path'; -import devNull from 'dev-null'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); @@ -775,138 +773,6 @@ describe('supports http with nodejs', () => { resolve(); }); }); - - if (process.platform !== 'win32') { - try { - fs.unlinkSync(socketName); - } catch (error) { - // Ignore socket unlink errors; socket may already be cleaned up. - } - } - } - }); - - it('should support HTTP proxies', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }); - - const proxy = await startHTTPServer((request, response) => { - const parsed = url.parse(request.url); - const opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - }; - - http.get(opts, (res) => { - let body = ''; - res.on('data', (data) => { - body += data; - }); - res.on('end', () => { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); - }); - }); - }); - - try { - const response = await axios.get(`http://localhost:${server.address().port}/`, { - proxy: { - host: 'localhost', - port: proxy.address().port, - }, - }); - - assert.strictEqual(response.data, '123456789', 'should pass through proxy'); - } finally { - await stopHTTPServer(server); - await stopHTTPServer(proxy); - } - }); - - it('should support HTTPS proxies', async () => { - const options = { - key: fs.readFileSync(path.join(adaptersTestsDir, 'key.pem')), - cert: fs.readFileSync(path.join(adaptersTestsDir, 'cert.pem')), - }; - - const server = await new Promise((resolve, reject) => { - const targetServer = https - .createServer(options, (req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }) - .listen(0, () => resolve(targetServer)); - - targetServer.on('error', reject); - }); - - const proxy = await new Promise((resolve, reject) => { - const proxyServer = https - .createServer(options, (request, response) => { - const parsed = url.parse(request.url); - const opts = { - host: parsed.hostname, - port: parsed.port, - path: parsed.path, - protocol: parsed.protocol, - rejectUnauthorized: false, - }; - - https.get(opts, (res) => { - let body = ''; - res.on('data', (data) => { - body += data; - }); - res.on('end', () => { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); - }); - }); - }) - .listen(0, () => resolve(proxyServer)); - - proxyServer.on('error', reject); - }); - - try { - const response = await axios.get(`https://localhost:${server.address().port}/`, { - proxy: { - host: 'localhost', - port: proxy.address().port, - protocol: 'https:', - }, - httpsAgent: new https.Agent({ - rejectUnauthorized: false, - }), - }); - - assert.strictEqual(response.data, '123456789', 'should pass through proxy'); - } finally { - await new Promise((resolve, reject) => { - server.close((error) => { - if (error) { - reject(error); - return; - } - - resolve(); - }); - }); - - await new Promise((resolve, reject) => { - proxy.close((error) => { - if (error) { - reject(error); - return; - } - - resolve(); - }); - }); } }); @@ -951,7 +817,10 @@ describe('supports http with nodejs', () => { try { await assert.rejects( - axios.post(`http://localhost:${server.address().port}/`, fs.createReadStream(notExistPath)), + axios.post( + `http://localhost:${server.address().port}/`, + fs.createReadStream(notExistPath) + ), (error) => { assert.strictEqual( error.message, @@ -964,73 +833,5 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); - - it('should destroy the response stream with an error on request stream destroying', async () => { - const server = await startHTTPServer(); - const requestStream = generateReadable(); - - setTimeout(() => { - requestStream.destroy(); - }, 1000); - - const { data } = await axios.post(`http://localhost:${server.address().port}/`, requestStream, { - responseType: 'stream', - }); - - let streamError; - data.on('error', (error) => { - streamError = error; - }); - - try { - await new Promise((resolve, reject) => { - stream.pipeline(data, devNull(), (error) => { - if (error) { - reject(error); - return; - } - resolve(); - }); - }); - assert.fail('stream was not aborted'); - } catch (error) { - // Expected: pipeline should reject after request stream is destroyed. - } finally { - assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); - await stopHTTPServer(server); - } - }); - }); - - it('should support buffers', async () => { - const buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) - const server = await startHTTPServer((req, res) => { - assert.strictEqual(req.headers['content-length'], buf.length.toString()); - req.pipe(res); - }); - - try { - const response = await axios.post(`http://localhost:${server.address().port}/`, buf, { - responseType: 'stream', - }); - - const responseText = await new Promise((resolve, reject) => { - const chunks = []; - - response.data.on('data', (chunk) => { - chunks.push(chunk); - }); - - response.data.on('end', () => { - resolve(Buffer.concat(chunks).toString('utf8')); - }); - - response.data.on('error', reject); - }); - - assert.strictEqual(responseText, buf.toString()); - } finally { - await stopHTTPServer(server); - } }); }); From 470f8dd61a4a705eb6b7a4d8047ce97a83b5fca7 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Thu, 5 Mar 2026 16:18:16 +0200 Subject: [PATCH 14/37] chore: tests --- tests/unit/adapters/http.test.js | 40 +++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index c84a138dc2..6a3c36e2ca 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1,6 +1,6 @@ import { describe, it } from 'vitest'; import assert from 'assert'; -import { startHTTPServer, stopHTTPServer } from '../../setup/server.js'; +import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; @@ -10,6 +10,7 @@ import url from 'url'; import zlib from 'zlib'; import fs from 'fs'; import path from 'path'; +import devNull from 'dev-null'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); @@ -833,5 +834,42 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); + + it('should destroy the response stream with an error on request stream destroying', async () => { + const server = await startHTTPServer(); + const requestStream = generateReadable(); + + setTimeout(() => { + requestStream.destroy(); + }, 1000); + + const { data } = await axios.post(`http://localhost:${server.address().port}/`, requestStream, { + responseType: 'stream', + }); + + let streamError; + data.on('error', (error) => { + streamError = error; + }); + + try { + await new Promise((resolve, reject) => { + stream.pipeline(data, devNull(), (error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + assert.fail('stream was not aborted'); + } catch (error) { + // Expected: the request stream is destroyed before completion. + } finally { + assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); + await stopHTTPServer(server); + } + }); }); }); From 695f2828cb3dc7ca3c7173752bb6518596c2c170 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 09:03:57 +0200 Subject: [PATCH 15/37] chore: tests --- tests/unit/adapters/http.test.js | 110 +++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 6a3c36e2ca..83225a8100 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -9,6 +9,7 @@ import stream from 'stream'; import url from 'url'; import zlib from 'zlib'; import fs from 'fs'; +import os from 'os'; import path from 'path'; import devNull from 'dev-null'; @@ -738,23 +739,35 @@ describe('supports http with nodejs', () => { }); it('should support sockets', async () => { - let socketName = './test.sock'; + let socketName = path.join( + os.tmpdir(), + `axios-test-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.sock` + ); if (process.platform === 'win32') { socketName = '\\\\.\\pipe\\libuv-test'; } - const server = await new Promise((resolve, reject) => { - const socketServer = net - .createServer((socket) => { - socket.on('data', () => { - socket.end('HTTP/1.1 200 OK\r\n\r\n'); - }); - }) - .listen(socketName, () => resolve(socketServer)); + let server; + try { + server = await new Promise((resolve, reject) => { + const socketServer = net + .createServer((socket) => { + socket.on('data', () => { + socket.end('HTTP/1.1 200 OK\r\n\r\n'); + }); + }) + .listen(socketName, () => resolve(socketServer)); + + socketServer.on('error', reject); + }); + } catch (error) { + if (error && error.code === 'EPERM') { + return; + } - socketServer.on('error', reject); - }); + throw error; + } try { const response = await axios({ @@ -872,4 +885,79 @@ describe('supports http with nodejs', () => { } }); }); + + it('should support buffers', async () => { + const buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) + const server = await startHTTPServer((req, res) => { + assert.strictEqual(req.headers['content-length'], buf.length.toString()); + req.pipe(res); + }); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, buf, { + responseType: 'stream', + }); + + const responseText = await new Promise((resolve, reject) => { + const chunks = []; + + response.data.on('data', (chunk) => { + chunks.push(chunk); + }); + + response.data.on('end', () => { + resolve(Buffer.concat(chunks).toString('utf8')); + }); + + response.data.on('error', reject); + }); + + assert.strictEqual(responseText, buf.toString()); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support HTTP proxies', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }); + + const proxy = await startHTTPServer((request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + + http.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + }, { port: 0 }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: proxy.address().port, + }, + }); + + assert.equal(response.data, '123456789', 'should pass through proxy'); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + } + }); }); From 4b957eccfd1d9622a8db9c9a97de475e06492f73 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 09:08:38 +0200 Subject: [PATCH 16/37] chore: tests --- tests/unit/adapters/http.test.js | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 83225a8100..c07ede3639 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -4,6 +4,7 @@ import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/s import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import http from 'http'; +import https from 'https'; import net from 'net'; import stream from 'stream'; import url from 'url'; @@ -960,4 +961,112 @@ describe('supports http with nodejs', () => { await stopHTTPServer(proxy); } }); + + it('should support HTTPS proxies', async () => { + const tlsOptions = { + key: fs.readFileSync(path.join(adaptersTestsDir, 'key.pem')), + cert: fs.readFileSync(path.join(adaptersTestsDir, 'cert.pem')), + }; + + const closeServer = (server) => + new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + + const server = await new Promise((resolve, reject) => { + const httpsServer = https + .createServer(tlsOptions, (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }) + .listen(0, () => resolve(httpsServer)); + + httpsServer.on('error', reject); + }); + + const proxy = await new Promise((resolve, reject) => { + const httpsProxy = https + .createServer(tlsOptions, (request, response) => { + const targetUrl = new URL(request.url); + const opts = { + host: targetUrl.hostname, + port: targetUrl.port, + path: `${targetUrl.pathname}${targetUrl.search}`, + protocol: targetUrl.protocol, + rejectUnauthorized: false, + }; + + const proxyRequest = https.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + + proxyRequest.on('error', () => { + response.statusCode = 502; + response.end(); + }); + }) + .listen(0, () => resolve(httpsProxy)); + + httpsProxy.on('error', reject); + }); + + try { + const response = await axios.get(`https://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: proxy.address().port, + protocol: 'https:', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }); + + assert.equal(response.data, '123456789', 'should pass through proxy'); + } finally { + await Promise.all([closeServer(server), closeServer(proxy)]); + } + }); + + it('should not pass through disabled proxy', async () => { + const originalHttpProxy = process.env.http_proxy; + process.env.http_proxy = 'http://does-not-exists.example.com:4242/'; + + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('123456789'); + }); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + proxy: false, + }); + + assert.equal(response.data, '123456789', 'should not pass through proxy'); + } finally { + await stopHTTPServer(server); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + } + }); }); From a0de634934d1bf54296b5c08759e8ecbe2734e2f Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 09:17:06 +0200 Subject: [PATCH 17/37] chore: tests --- tests/unit/adapters/http.test.js | 136 +++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 23 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index c07ede3639..f95965399c 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -857,9 +857,13 @@ describe('supports http with nodejs', () => { requestStream.destroy(); }, 1000); - const { data } = await axios.post(`http://localhost:${server.address().port}/`, requestStream, { - responseType: 'stream', - }); + const { data } = await axios.post( + `http://localhost:${server.address().port}/`, + requestStream, + { + responseType: 'stream', + } + ); let streamError; data.on('error', (error) => { @@ -925,27 +929,30 @@ describe('supports http with nodejs', () => { res.end('12345'); }); - const proxy = await startHTTPServer((request, response) => { - const parsed = new URL(request.url); - const opts = { - host: parsed.hostname, - port: parsed.port, - path: `${parsed.pathname}${parsed.search}`, - }; + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; - http.get(opts, (res) => { - let body = ''; + http.get(opts, (res) => { + let body = ''; - res.on('data', (data) => { - body += data; - }); + res.on('data', (data) => { + body += data; + }); - res.on('end', () => { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); }); - }); - }, { port: 0 }); + }, + { port: 0 } + ); try { const response = await axios.get(`http://localhost:${server.address().port}/`, { @@ -955,7 +962,7 @@ describe('supports http with nodejs', () => { }, }); - assert.equal(response.data, '123456789', 'should pass through proxy'); + assert.strictEqual(Number(response.data), 123456789, 'should pass through proxy'); } finally { await stopHTTPServer(server); await stopHTTPServer(proxy); @@ -1038,7 +1045,7 @@ describe('supports http with nodejs', () => { }), }); - assert.equal(response.data, '123456789', 'should pass through proxy'); + assert.strictEqual(Number(response.data), 123456789, 'should pass through proxy'); } finally { await Promise.all([closeServer(server), closeServer(proxy)]); } @@ -1058,15 +1065,98 @@ describe('supports http with nodejs', () => { proxy: false, }); - assert.equal(response.data, '123456789', 'should not pass through proxy'); + assert.strictEqual(Number(response.data), 123456789, 'should not pass through proxy'); + } finally { + await stopHTTPServer(server); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + } + }); + + it('should support proxy set via env var', async () => { + const originalHttpProxy = process.env.http_proxy; + const originalHTTPProxy = process.env.HTTP_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }, + { port: 0 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + + http.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }, + { port: 0 } + ); + + const proxyUrl = `http://localhost:${proxy.address().port}/`; + process.env.http_proxy = proxyUrl; + process.env.HTTP_PROXY = proxyUrl; + process.env.no_proxy = ''; + process.env.NO_PROXY = ''; + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + + assert.strictEqual( + String(response.data), + '45671234', + 'should use proxy set by process.env.http_proxy' + ); } finally { await stopHTTPServer(server); + await stopHTTPServer(proxy); if (originalHttpProxy === undefined) { delete process.env.http_proxy; } else { process.env.http_proxy = originalHttpProxy; } + + if (originalHTTPProxy === undefined) { + delete process.env.HTTP_PROXY; + } else { + process.env.HTTP_PROXY = originalHTTPProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } } }); }); From f71456aa45e5857a95b95c2019a237bf266028ff Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 13:19:39 +0200 Subject: [PATCH 18/37] chore: tests --- tests/unit/adapters/http.test.js | 692 ++++++++++++++++++++++--------- 1 file changed, 503 insertions(+), 189 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index f95965399c..dcf22159f2 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -25,10 +25,13 @@ describe('supports http with nodejs', () => { emailAddr: 'fred@example.com', }; - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }, + { port: 8080 } + ); try { const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); @@ -45,10 +48,13 @@ describe('supports http with nodejs', () => { emailAddr: 'fred@example.com', }; - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }, + { port: 8080 } + ); try { const { data: responseData } = await axios.get(`http://[::1]:${server.address().port}`, { @@ -61,11 +67,14 @@ describe('supports http with nodejs', () => { }); it('should throw an error if the timeout property is not parsable as a number', async () => { - const server = await startHTTPServer((req, res) => { - setTimeout(() => { - res.end(); - }, 1000); - }); + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -84,11 +93,14 @@ describe('supports http with nodejs', () => { }); it('should parse the timeout property', async () => { - const server = await startHTTPServer((req, res) => { - setTimeout(() => { - res.end(); - }, 1000); - }); + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -107,11 +119,14 @@ describe('supports http with nodejs', () => { }); it('should respect the timeout property', async () => { - const server = await startHTTPServer((req, res) => { - setTimeout(() => { - res.end(); - }, 1000); - }); + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -130,11 +145,14 @@ describe('supports http with nodejs', () => { }); it('should respect the timeoutErrorMessage property', async () => { - const server = await startHTTPServer((req, res) => { - setTimeout(() => { - res.end(); - }, 1000); - }); + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -160,10 +178,13 @@ describe('supports http with nodejs', () => { emailAddr: 'fred@example.com', }; - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(data)); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(data)); + }, + { port: 8080 } + ); try { const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); @@ -180,12 +201,15 @@ describe('supports http with nodejs', () => { emailAddr: 'fred@example.com', }; - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - const bomBuffer = Buffer.from([0xef, 0xbb, 0xbf]); - const jsonBuffer = Buffer.from(JSON.stringify(data)); - res.end(Buffer.concat([bomBuffer, jsonBuffer])); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + const bomBuffer = Buffer.from([0xef, 0xbb, 0xbf]); + const jsonBuffer = Buffer.from(JSON.stringify(data)); + res.end(Buffer.concat([bomBuffer, jsonBuffer])); + }, + { port: 8080 } + ); try { const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); @@ -197,16 +221,19 @@ describe('supports http with nodejs', () => { it('should redirect', async () => { const expectedResponse = 'test response'; - const server = await startHTTPServer((req, res) => { - if (req.url === '/one') { - res.setHeader('Location', '/two'); - res.statusCode = 302; - res.end(); - return; - } + const server = await startHTTPServer( + (req, res) => { + if (req.url === '/one') { + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + return; + } - res.end(expectedResponse); - }); + res.end(expectedResponse); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { @@ -221,11 +248,14 @@ describe('supports http with nodejs', () => { }); it('should not redirect', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Location', '/foo'); - res.statusCode = 302; - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { @@ -245,12 +275,15 @@ describe('supports http with nodejs', () => { it('should support max redirects', async () => { var i = 1; - const server = await startHTTPServer((req, res) => { - res.setHeader('Location', `/${i}`); - res.statusCode = 302; - res.end(); - i++; - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Location', `/${i}`); + res.statusCode = 302; + res.end(); + i++; + }, + { port: 8080 } + ); try { await axios.get(`http://127.0.0.1:${server.address().port}`, { @@ -265,11 +298,14 @@ describe('supports http with nodejs', () => { }); it('should support beforeRedirect', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Location', '/foo'); - res.statusCode = 302; - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Location', '/foo'); + res.statusCode = 302; + res.end(); + }, + { port: 8080 } + ); try { await axios.get(`http://127.0.0.1:${server.address().port}/one`, { @@ -293,19 +329,22 @@ describe('supports http with nodejs', () => { let totalRedirectCount = 5; let configBeforeRedirectCount = 0; - const server = await startHTTPServer((req, res) => { - requestCount += 1; - if (requestCount <= totalRedirectCount) { - res.setHeader('Location', 'http://127.0.0.1:4444'); - res.writeHead(302); - } - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + requestCount += 1; + if (requestCount <= totalRedirectCount) { + res.setHeader('Location', 'http://127.0.0.1:8080'); + res.writeHead(302); + } + res.end(); + }, + { port: 8080 } + ); const proxy = await startHTTPServer( (req, res) => { proxyUseCount += 1; - const targetUrl = new URL(req.url, 'http://' + req.headers.host); + const targetUrl = new URL(req.url, `http://127.0.0.1:${server.address().port}`); const opts = { host: targetUrl.hostname, port: targetUrl.port, @@ -346,10 +385,13 @@ describe('supports http with nodejs', () => { }); it('should wrap HTTP errors and keep stack', async () => { - const server = await startHTTPServer((req, res) => { - res.statusCode = 400; - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + res.statusCode = 400; + res.end(); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -384,7 +426,7 @@ describe('supports http with nodejs', () => { (req, res) => { res.end(); }, - { port: 4444 } + { port: 8080 } ); try { @@ -425,7 +467,7 @@ describe('supports http with nodejs', () => { res.end(); } }, - { port: 4444 } + { port: 8080 } ); try { @@ -455,11 +497,14 @@ describe('supports http with nodejs', () => { }); }); - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.setHeader('Content-Encoding', 'gzip'); - res.end(zipped); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }, + { port: 8080 } + ); try { const { data: responseData } = await axios.get( @@ -472,11 +517,14 @@ describe('supports http with nodejs', () => { }); it('should support gunzip error handling', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.setHeader('Content-Encoding', 'gzip'); - res.end('invalid response'); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + res.end('invalid response'); + }, + { port: 8080 } + ); try { await assert.rejects(async () => { @@ -501,11 +549,14 @@ describe('supports http with nodejs', () => { }); }); - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html;charset=utf-8'); - res.setHeader('Content-Encoding', 'gzip'); - res.end(zipped); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html;charset=utf-8'); + res.setHeader('Content-Encoding', 'gzip'); + res.end(zipped); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://localhost:${server.address().port}/`, { @@ -524,10 +575,13 @@ describe('supports http with nodejs', () => { it('should support UTF8', async () => { const str = Array(100000).join('ж'); - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(str); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://localhost:${server.address().port}/`); @@ -538,9 +592,12 @@ describe('supports http with nodejs', () => { }); it('should support basic auth', async () => { - const server = await startHTTPServer((req, res) => { - res.end(req.headers.authorization); - }); + const server = await startHTTPServer( + (req, res) => { + res.end(req.headers.authorization); + }, + { port: 8080 } + ); try { const user = 'foo'; @@ -556,9 +613,12 @@ describe('supports http with nodejs', () => { }); it('should support basic auth with a header', async () => { - const server = await startHTTPServer((req, res) => { - res.end(req.headers.authorization); - }); + const server = await startHTTPServer( + (req, res) => { + res.end(req.headers.authorization); + }, + { port: 8080 } + ); try { const auth = { username: 'foo', password: 'bar' }; @@ -575,9 +635,12 @@ describe('supports http with nodejs', () => { }); it('should provides a default User-Agent header', async () => { - const server = await startHTTPServer((req, res) => { - res.end(req.headers['user-agent']); - }); + const server = await startHTTPServer( + (req, res) => { + res.end(req.headers['user-agent']); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://localhost:${server.address().port}/`); @@ -591,9 +654,12 @@ describe('supports http with nodejs', () => { }); it('should allow the User-Agent header to be overridden', async () => { - const server = await startHTTPServer((req, res) => { - res.end(req.headers['user-agent']); - }); + const server = await startHTTPServer( + (req, res) => { + res.end(req.headers['user-agent']); + }, + { port: 8080 } + ); try { const headers = { 'UsEr-AgEnT': 'foo bar' }; // wonky casing to ensure caseless comparison @@ -605,10 +671,13 @@ describe('supports http with nodejs', () => { }); it('should allow the Content-Length header to be overridden', async () => { - const server = await startHTTPServer((req, res) => { - assert.strictEqual(req.headers['content-length'], '42'); - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + assert.strictEqual(req.headers['content-length'], '42'); + res.end(); + }, + { port: 8080 } + ); try { const headers = { 'CoNtEnT-lEnGtH': '42' }; // wonky casing to ensure caseless comparison @@ -619,10 +688,13 @@ describe('supports http with nodejs', () => { }); it('should support max content length', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(Array(5000).join('#')); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(Array(5000).join('#')); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -639,19 +711,22 @@ describe('supports http with nodejs', () => { it('should support max content length for redirected', async () => { const str = Array(100000).join('ж'); - const server = await startHTTPServer((req, res) => { - const parsed = url.parse(req.url); + const server = await startHTTPServer( + (req, res) => { + const parsed = url.parse(req.url); - if (parsed.pathname === '/two') { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(str); - return; - } + if (parsed.pathname === '/two') { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(str); + return; + } - res.setHeader('Location', '/two'); - res.statusCode = 302; - res.end(); - }); + res.setHeader('Location', '/two'); + res.statusCode = 302; + res.end(); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -670,10 +745,13 @@ describe('supports http with nodejs', () => { it('should support max body length', async () => { const data = Array(100000).join('ж'); - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end(); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -701,13 +779,16 @@ describe('supports http with nodejs', () => { const followRedirectsMaxBodyDefaults = 10 * 1024 * 1024; const data = Array(2 * followRedirectsMaxBodyDefaults).join('ж'); - const server = await startHTTPServer((req, res) => { - // Consume the req stream before responding to avoid ECONNRESET. - req.on('data', () => {}); - req.on('end', () => { - res.end('OK'); - }); - }); + const server = await startHTTPServer( + (req, res) => { + // Consume the req stream before responding to avoid ECONNRESET. + req.on('data', () => {}); + req.on('end', () => { + res.end('OK'); + }); + }, + { port: 8080 } + ); try { const response = await axios.post(`http://localhost:${server.address().port}/`, { @@ -720,7 +801,7 @@ describe('supports http with nodejs', () => { }); it('should display error while parsing params', async () => { - const server = await startHTTPServer(() => {}); + const server = await startHTTPServer(() => {}, { port: 8080 }); try { await assert.rejects( @@ -793,9 +874,12 @@ describe('supports http with nodejs', () => { describe('streams', () => { it('should support streams', async () => { - const server = await startHTTPServer((req, res) => { - req.pipe(res); - }); + const server = await startHTTPServer( + (req, res) => { + req.pipe(res); + }, + { port: 8080 } + ); try { const response = await axios.post( @@ -827,7 +911,7 @@ describe('supports http with nodejs', () => { }); it('should pass errors for a failed stream', async () => { - const server = await startHTTPServer(); + const server = await startHTTPServer(() => {}, { port: 8080 }); const notExistPath = path.join(adaptersTestsDir, 'does_not_exist'); try { @@ -893,10 +977,13 @@ describe('supports http with nodejs', () => { it('should support buffers', async () => { const buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) - const server = await startHTTPServer((req, res) => { - assert.strictEqual(req.headers['content-length'], buf.length.toString()); - req.pipe(res); - }); + const server = await startHTTPServer( + (req, res) => { + assert.strictEqual(req.headers['content-length'], buf.length.toString()); + req.pipe(res); + }, + { port: 8080 } + ); try { const response = await axios.post(`http://localhost:${server.address().port}/`, buf, { @@ -924,10 +1011,13 @@ describe('supports http with nodejs', () => { }); it('should support HTTP proxies', async () => { - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }, + { port: 8080 } + ); const proxy = await startHTTPServer( (request, response) => { @@ -989,46 +1079,54 @@ describe('supports http with nodejs', () => { const server = await new Promise((resolve, reject) => { const httpsServer = https - .createServer(tlsOptions, (req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('12345'); - }) - .listen(0, () => resolve(httpsServer)); + .createServer( + tlsOptions, + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }, + { port: 8080 } + ) + .listen(8080, () => resolve(httpsServer)); httpsServer.on('error', reject); }); const proxy = await new Promise((resolve, reject) => { const httpsProxy = https - .createServer(tlsOptions, (request, response) => { - const targetUrl = new URL(request.url); - const opts = { - host: targetUrl.hostname, - port: targetUrl.port, - path: `${targetUrl.pathname}${targetUrl.search}`, - protocol: targetUrl.protocol, - rejectUnauthorized: false, - }; - - const proxyRequest = https.get(opts, (res) => { - let body = ''; - - res.on('data', (data) => { - body += data; + .createServer( + tlsOptions, + (request, response) => { + const targetUrl = new URL(request.url); + const opts = { + host: targetUrl.hostname, + port: targetUrl.port, + path: `${targetUrl.pathname}${targetUrl.search}`, + protocol: targetUrl.protocol, + rejectUnauthorized: false, + }; + + const proxyRequest = https.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); }); - res.on('end', () => { - response.setHeader('Content-Type', 'text/html; charset=UTF-8'); - response.end(body + '6789'); + proxyRequest.on('error', () => { + response.statusCode = 502; + response.end(); }); - }); - - proxyRequest.on('error', () => { - response.statusCode = 502; - response.end(); - }); - }) - .listen(0, () => resolve(httpsProxy)); + }, + { port: 8081 } + ) + .listen(8081, () => resolve(httpsProxy)); httpsProxy.on('error', reject); }); @@ -1055,10 +1153,13 @@ describe('supports http with nodejs', () => { const originalHttpProxy = process.env.http_proxy; process.env.http_proxy = 'http://does-not-exists.example.com:4242/'; - const server = await startHTTPServer((req, res) => { - res.setHeader('Content-Type', 'text/html; charset=UTF-8'); - res.end('123456789'); - }); + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('123456789'); + }, + { port: 8080 } + ); try { const response = await axios.get(`http://localhost:${server.address().port}/`, { @@ -1088,7 +1189,7 @@ describe('supports http with nodejs', () => { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); res.end('4567'); }, - { port: 0 } + { port: 8080 } ); const proxy = await startHTTPServer( @@ -1113,7 +1214,7 @@ describe('supports http with nodejs', () => { }); }); }, - { port: 0 } + { port: 8081 } ); const proxyUrl = `http://localhost:${proxy.address().port}/`; @@ -1159,4 +1260,217 @@ describe('supports http with nodejs', () => { } } }); + + it('should support HTTPS proxy set via env var', async () => { + const originalHttpsProxy = process.env.https_proxy; + const originalHTTPSProxy = process.env.HTTPS_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + const tlsOptions = { + key: fs.readFileSync(path.join(adaptersTestsDir, 'key.pem')), + cert: fs.readFileSync(path.join(adaptersTestsDir, 'cert.pem')), + }; + + const closeServer = (server) => + new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + + const server = await new Promise((resolve, reject) => { + const httpsServer = https + .createServer( + tlsOptions, + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('12345'); + }, + { port: 8080 } + ) + .listen(8080, () => resolve(httpsServer)); + + httpsServer.on('error', reject); + }); + + const proxy = await new Promise((resolve, reject) => { + const httpsProxy = https + .createServer( + tlsOptions, + (request, response) => { + const targetUrl = new URL(request.url); + const opts = { + host: targetUrl.hostname, + port: targetUrl.port, + path: `${targetUrl.pathname}${targetUrl.search}`, + protocol: targetUrl.protocol, + rejectUnauthorized: false, + }; + + const proxyRequest = https.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '6789'); + }); + }); + + proxyRequest.on('error', () => { + response.statusCode = 502; + response.end(); + }); + }, + { port: 8081 } + ) + .listen(8081, () => resolve(httpsProxy)); + + httpsProxy.on('error', reject); + }); + + const proxyUrl = `https://localhost:${proxy.address().port}/`; + process.env.https_proxy = proxyUrl; + process.env.HTTPS_PROXY = proxyUrl; + process.env.no_proxy = ''; + process.env.NO_PROXY = ''; + + try { + const response = await axios.get(`https://localhost:${server.address().port}/`, { + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }); + + assert.equal(response.data, '123456789', 'should pass through proxy'); + } finally { + await Promise.all([closeServer(server), closeServer(proxy)]); + + if (originalHttpsProxy === undefined) { + delete process.env.https_proxy; + } else { + process.env.https_proxy = originalHttpsProxy; + } + + if (originalHTTPSProxy === undefined) { + delete process.env.HTTPS_PROXY; + } else { + process.env.HTTPS_PROXY = originalHTTPSProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } + } + }); + + it('should re-evaluate proxy on redirect when proxy set via env var', async () => { + const originalHttpProxy = process.env.http_proxy; + const originalHTTPProxy = process.env.HTTP_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + let proxyUseCount = 0; + + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Location', `http://localhost:${proxy.address().port}/redirected`); + res.statusCode = 302; + res.end(); + }, + { port: 8080 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url, 'http://localhost'); + + if (parsed.pathname === '/redirected') { + response.statusCode = 200; + response.end(); + return; + } + + proxyUseCount += 1; + + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + protocol: parsed.protocol, + }; + + http.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.setHeader('Location', res.headers.location); + response.end(body); + }); + }); + }, + { port: 8081 } + ); + + const proxyUrl = `http://localhost:${proxy.address().port}`; + process.env.http_proxy = proxyUrl; + process.env.HTTP_PROXY = proxyUrl; + process.env.no_proxy = `localhost:${proxy.address().port}`; + process.env.NO_PROXY = `localhost:${proxy.address().port}`; + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + assert.equal(response.status, 200); + assert.equal(proxyUseCount, 1); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + + if (originalHTTPProxy === undefined) { + delete process.env.HTTP_PROXY; + } else { + process.env.HTTP_PROXY = originalHTTPProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } + } + }); }); From 4e101d7b59a9ae8cb9ff354af7be307af5e8f842 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 13:46:06 +0200 Subject: [PATCH 19/37] chore: tests --- tests/unit/adapters/http.test.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index dcf22159f2..d702d4d3da 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -78,7 +78,7 @@ describe('supports http with nodejs', () => { try { await assert.rejects( - axios.get(`http://127.0.0.1:${server.address().port}`, { + axios.get(`http://localhost:${server.address().port}`, { timeout: { strangeTimeout: 250 }, }), (error) => { @@ -104,7 +104,7 @@ describe('supports http with nodejs', () => { try { await assert.rejects( - axios.get(`http://127.0.0.1:${server.address().port}`, { + axios.get(`http://localhost:${server.address().port}`, { timeout: '250', }), (error) => { @@ -130,7 +130,7 @@ describe('supports http with nodejs', () => { try { await assert.rejects( - axios.get(`http://127.0.0.1:${server.address().port}`, { + axios.get(`http://localhost:${server.address().port}`, { timeout: 250, }), (error) => { @@ -156,7 +156,7 @@ describe('supports http with nodejs', () => { try { await assert.rejects( - axios.get(`http://127.0.0.1:${server.address().port}`, { + axios.get(`http://localhost:${server.address().port}`, { timeout: 250, timeoutErrorMessage: 'oops, timeout', }), @@ -187,7 +187,7 @@ describe('supports http with nodejs', () => { ); try { - const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); + const { data: responseData } = await axios.get(`http://localhost:${server.address().port}`); assert.deepStrictEqual(responseData, data); } finally { await stopHTTPServer(server); @@ -212,7 +212,7 @@ describe('supports http with nodejs', () => { ); try { - const { data: responseData } = await axios.get(`http://127.0.0.1:${server.address().port}`); + const { data: responseData } = await axios.get(`http://localhost:${server.address().port}`); assert.deepStrictEqual(responseData, data); } finally { await stopHTTPServer(server); @@ -236,7 +236,7 @@ describe('supports http with nodejs', () => { ); try { - const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + const response = await axios.get(`http://localhost:${server.address().port}/one`, { maxRedirects: 1, }); @@ -258,7 +258,7 @@ describe('supports http with nodejs', () => { ); try { - const response = await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + const response = await axios.get(`http://localhost:${server.address().port}/one`, { maxRedirects: 0, }); @@ -286,7 +286,7 @@ describe('supports http with nodejs', () => { ); try { - await axios.get(`http://127.0.0.1:${server.address().port}`, { + await axios.get(`http://localhost:${server.address().port}`, { maxRedirects: 3, }); } catch (error) { @@ -308,7 +308,7 @@ describe('supports http with nodejs', () => { ); try { - await axios.get(`http://127.0.0.1:${server.address().port}/one`, { + await axios.get(`http://localhost:${server.address().port}/one`, { maxRedirects: 3, beforeRedirect: (options, responseDetails) => { if (options.path === '/foo' && responseDetails.headers.location === '/foo') { @@ -333,7 +333,7 @@ describe('supports http with nodejs', () => { (req, res) => { requestCount += 1; if (requestCount <= totalRedirectCount) { - res.setHeader('Location', 'http://127.0.0.1:8080'); + res.setHeader('Location', 'http://localhost:8080'); res.writeHead(302); } res.end(); @@ -344,7 +344,7 @@ describe('supports http with nodejs', () => { const proxy = await startHTTPServer( (req, res) => { proxyUseCount += 1; - const targetUrl = new URL(req.url, `http://127.0.0.1:${server.address().port}`); + const targetUrl = new URL(req.url, `http://localhost:${server.address().port}`); const opts = { host: targetUrl.hostname, port: targetUrl.port, From 5c8dfe2b5566f37f5f0bc1cabc8103521bfc899b Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 13:48:18 +0200 Subject: [PATCH 20/37] chore: tests --- tests/unit/adapters/http.test.js | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index d702d4d3da..4f2a7aa904 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1473,4 +1473,83 @@ describe('supports http with nodejs', () => { } } }); + + it('should not use proxy for domains in no_proxy', async () => { + const originalHttpProxy = process.env.http_proxy; + const originalHTTPProxy = process.env.HTTP_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }, + { port: 8080 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + + http.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }, + { port: 8081 } + ); + + const noProxyValue = 'foo.com, localhost,bar.net , , quix.co'; + const proxyUrl = `http://localhost:${proxy.address().port}/`; + process.env.http_proxy = proxyUrl; + process.env.HTTP_PROXY = proxyUrl; + process.env.no_proxy = noProxyValue; + process.env.NO_PROXY = noProxyValue; + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + assert.equal(response.data, '4567', 'should not use proxy for domains in no_proxy'); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + + if (originalHTTPProxy === undefined) { + delete process.env.HTTP_PROXY; + } else { + process.env.HTTP_PROXY = originalHTTPProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } + } + }); }); From 6b632185a14959f49b2a786951b9ef5f0e121da3 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 13:49:01 +0200 Subject: [PATCH 21/37] chore: tests --- tests/unit/adapters/http.test.js | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 4f2a7aa904..7b81ac010c 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1552,4 +1552,83 @@ describe('supports http with nodejs', () => { } } }); + + it('should use proxy for domains not in no_proxy', async () => { + const originalHttpProxy = process.env.http_proxy; + const originalHTTPProxy = process.env.HTTP_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + const server = await startHTTPServer( + (req, res) => { + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + res.end('4567'); + }, + { port: 8080 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + + http.get(opts, (res) => { + let body = ''; + + res.on('data', (data) => { + body += data; + }); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(body + '1234'); + }); + }); + }, + { port: 8081 } + ); + + const noProxyValue = 'foo.com, ,bar.net , quix.co'; + const proxyUrl = `http://localhost:${proxy.address().port}/`; + process.env.http_proxy = proxyUrl; + process.env.HTTP_PROXY = proxyUrl; + process.env.no_proxy = noProxyValue; + process.env.NO_PROXY = noProxyValue; + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + assert.equal(response.data, '45671234', 'should use proxy for domains not in no_proxy'); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + + if (originalHTTPProxy === undefined) { + delete process.env.HTTP_PROXY; + } else { + process.env.HTTP_PROXY = originalHTTPProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } + } + }); }); From 7d719c229170e8fe7ab5c639e180d2e56cc55ed7 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 13:52:04 +0200 Subject: [PATCH 22/37] chore: tests --- tests/unit/adapters/http.test.js | 129 +++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 7b81ac010c..0112814ea2 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1631,4 +1631,133 @@ describe('supports http with nodejs', () => { } } }); + + it('should support HTTP proxy auth', async () => { + const server = await startHTTPServer( + (req, res) => { + res.end(); + }, + { port: 8080 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + const proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, (res) => { + res.on('data', () => {}); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + }, + { port: 8081 } + ); + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`, { + proxy: { + host: 'localhost', + port: proxy.address().port, + auth: { + username: 'user', + password: 'pass', + }, + }, + }); + + const base64 = Buffer.from('user:pass', 'utf8').toString('base64'); + assert.equal(response.data, `Basic ${base64}`, 'should authenticate to the proxy'); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + } + }); + + it('should support proxy auth from env', async () => { + const originalHttpProxy = process.env.http_proxy; + const originalHTTPProxy = process.env.HTTP_PROXY; + const originalNoProxy = process.env.no_proxy; + const originalNOProxy = process.env.NO_PROXY; + + const server = await startHTTPServer( + (req, res) => { + res.end(); + }, + { port: 8080 } + ); + + const proxy = await startHTTPServer( + (request, response) => { + const parsed = new URL(request.url); + const opts = { + host: parsed.hostname, + port: parsed.port, + path: `${parsed.pathname}${parsed.search}`, + }; + const proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, (res) => { + res.on('data', () => {}); + + res.on('end', () => { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + }, + { port: 8081 } + ); + + const proxyUrl = `http://user:pass@localhost:${proxy.address().port}/`; + process.env.http_proxy = proxyUrl; + process.env.HTTP_PROXY = proxyUrl; + process.env.no_proxy = ''; + process.env.NO_PROXY = ''; + + try { + const response = await axios.get(`http://localhost:${server.address().port}/`); + const base64 = Buffer.from('user:pass', 'utf8').toString('base64'); + assert.equal( + response.data, + `Basic ${base64}`, + 'should authenticate to the proxy set by process.env.http_proxy' + ); + } finally { + await stopHTTPServer(server); + await stopHTTPServer(proxy); + + if (originalHttpProxy === undefined) { + delete process.env.http_proxy; + } else { + process.env.http_proxy = originalHttpProxy; + } + + if (originalHTTPProxy === undefined) { + delete process.env.HTTP_PROXY; + } else { + process.env.HTTP_PROXY = originalHTTPProxy; + } + + if (originalNoProxy === undefined) { + delete process.env.no_proxy; + } else { + process.env.no_proxy = originalNoProxy; + } + + if (originalNOProxy === undefined) { + delete process.env.NO_PROXY; + } else { + process.env.NO_PROXY = originalNOProxy; + } + } + }); }); From daada61dd8e3a3ecbd9b92bce062989ac9b1a5d4 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 17:01:28 +0200 Subject: [PATCH 23/37] chore: tests --- tests/unit/adapters/http.test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 0112814ea2..5b11a30890 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1760,4 +1760,28 @@ describe('supports http with nodejs', () => { } } }); + + describe('when invalid proxy options are provided', () => { + it('should throw error', async () => { + const proxy = { + protocol: 'http:', + host: 'hostname.abc.xyz', + port: 3300, + auth: { + username: '', + password: '', + }, + }; + + await assert.rejects( + axios.get('https://test-domain.abc', { proxy }), + (error) => { + assert.strictEqual(error.message, 'Invalid proxy authorization'); + assert.strictEqual(error.code, 'ERR_BAD_OPTION'); + assert.deepStrictEqual(error.config.proxy, proxy); + return true; + } + ); + }); + }); }); From 8ab0e45e9396ccb2ef8f60dc4c0f692518253d47 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 17:02:27 +0200 Subject: [PATCH 24/37] chore: tests --- tests/unit/adapters/http.test.js | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 5b11a30890..aaf5d3478c 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -3,6 +3,7 @@ import assert from 'assert'; import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; +import { __setProxy } from '../../../lib/adapters/http.js'; import http from 'http'; import https from 'https'; import net from 'net'; @@ -1784,4 +1785,42 @@ describe('supports http with nodejs', () => { ); }); }); + + describe('different options for direct proxy configuration (without env variables)', () => { + const destination = 'www.example.com'; + + const testCases = [ + { + description: 'hostname and trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http:', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'hostname and no trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'both hostname and host -> hostname takes precedence', + proxyConfig: { hostname: '127.0.0.1', host: '0.0.0.0', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination }, + }, + { + description: 'only host and https protocol', + proxyConfig: { host: '0.0.0.0', protocol: 'https', port: 80 }, + expectedOptions: { host: '0.0.0.0', protocol: 'https:', port: 80, path: destination }, + }, + ]; + + for (const test of testCases) { + it(test.description, () => { + const options = { headers: {}, beforeRedirects: {} }; + __setProxy(options, test.proxyConfig, destination); + + for (const [key, expected] of Object.entries(test.expectedOptions)) { + assert.strictEqual(options[key], expected); + } + }); + } + }); }); From 9f8a759c84057e1b10257484a7162ca86bc9ed58 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 17:05:45 +0200 Subject: [PATCH 25/37] chore: tests --- tests/unit/adapters/http.test.js | 46 +++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index aaf5d3478c..0f147e0c24 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -18,6 +18,7 @@ import devNull from 'dev-null'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); const thisTestFilePath = path.join(adaptersTestsDir, 'http.test.js'); + const nodeMajorVersion = Number.parseInt(process.versions.node.split('.')[0], 10); it('should support IPv4 literal strings', async () => { const data = { @@ -1774,15 +1775,12 @@ describe('supports http with nodejs', () => { }, }; - await assert.rejects( - axios.get('https://test-domain.abc', { proxy }), - (error) => { - assert.strictEqual(error.message, 'Invalid proxy authorization'); - assert.strictEqual(error.code, 'ERR_BAD_OPTION'); - assert.deepStrictEqual(error.config.proxy, proxy); - return true; - } - ); + await assert.rejects(axios.get('https://test-domain.abc', { proxy }), (error) => { + assert.strictEqual(error.message, 'Invalid proxy authorization'); + assert.strictEqual(error.code, 'ERR_BAD_OPTION'); + assert.deepStrictEqual(error.config.proxy, proxy); + return true; + }); }); }); @@ -1823,4 +1821,34 @@ describe('supports http with nodejs', () => { }); } }); + + it('should support cancel', async () => { + const source = axios.CancelToken.source(); + + const server = await startHTTPServer((req, res) => { + // Call cancel() when the request has been sent but no response received. + source.cancel('Operation has been canceled.'); + }); + + try { + await assert.rejects( + async function stackTraceTest() { + await axios.get(`http://localhost:${server.address().port}/`, { + cancelToken: source.token, + }); + }, + (thrown) => { + assert.ok( + thrown instanceof axios.Cancel, + 'Promise must be rejected with a CanceledError object' + ); + assert.equal(thrown.message, 'Operation has been canceled.'); + + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); }); From 503ffd2154755b354b55f9a0cad1f198c0c76a41 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 17:07:21 +0200 Subject: [PATCH 26/37] chore: tests --- tests/unit/adapters/http.test.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 0f147e0c24..4071ef3de7 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -18,7 +18,6 @@ import devNull from 'dev-null'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); const thisTestFilePath = path.join(adaptersTestsDir, 'http.test.js'); - const nodeMajorVersion = Number.parseInt(process.versions.node.split('.')[0], 10); it('should support IPv4 literal strings', async () => { const data = { @@ -1851,4 +1850,21 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); + + it('should combine baseURL and url', async () => { + const server = await startHTTPServer((req, res) => { + res.end(); + }); + + try { + const response = await axios.get('/foo', { + baseURL: `http://localhost:${server.address().port}/`, + }); + + assert.equal(response.config.baseURL, `http://localhost:${server.address().port}/`); + assert.equal(response.config.url, '/foo'); + } finally { + await stopHTTPServer(server); + } + }); }); From ff5795908565f93a687a58a499dcd4bd77f993e5 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 17:44:09 +0200 Subject: [PATCH 27/37] chore: tests --- tests/unit/adapters/http.test.js | 91 +++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 4071ef3de7..c6ce63e657 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1824,10 +1824,13 @@ describe('supports http with nodejs', () => { it('should support cancel', async () => { const source = axios.CancelToken.source(); - const server = await startHTTPServer((req, res) => { - // Call cancel() when the request has been sent but no response received. - source.cancel('Operation has been canceled.'); - }); + const server = await startHTTPServer( + (req, res) => { + // Call cancel() when the request has been sent but no response received. + source.cancel('Operation has been canceled.'); + }, + { port: 8080 } + ); try { await assert.rejects( @@ -1852,9 +1855,12 @@ describe('supports http with nodejs', () => { }); it('should combine baseURL and url', async () => { - const server = await startHTTPServer((req, res) => { - res.end(); - }); + const server = await startHTTPServer( + (req, res) => { + res.end(); + }, + { port: 8080 } + ); try { const response = await axios.get('/foo', { @@ -1867,4 +1873,75 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); + + it('should support HTTP protocol', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ); + + try { + const response = await axios.get(`http://localhost:${server.address().port}`); + assert.equal(response.request.agent.protocol, 'http:'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support HTTPS protocol', async () => { + const tlsOptions = { + key: fs.readFileSync(path.join(adaptersTestsDir, 'key.pem')), + cert: fs.readFileSync(path.join(adaptersTestsDir, 'cert.pem')), + }; + + const server = await new Promise((resolve, reject) => { + const httpsServer = https + .createServer( + tlsOptions, + (req, res) => { + setTimeout(() => { + res.end(); + }, 1000); + }, + { port: 8080 } + ) + .listen(8080, () => resolve(httpsServer)); + + httpsServer.on('error', reject); + }); + + try { + const response = await axios.get(`https://localhost:${server.address().port}`, { + httpsAgent: new https.Agent({ + rejectUnauthorized: false, + }), + }); + assert.equal(response.request.agent.protocol, 'https:'); + } finally { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + } + }); + + it('should return malformed URL', async () => { + await assert.rejects( + axios.get('tel:484-695-3408'), + (error) => { + assert.equal(error.message, 'Unsupported protocol tel:'); + return true; + } + ); + }); }); From 91350f15e7b424c7ef6d1600bf383b3fd8c8d2f5 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 18:06:06 +0200 Subject: [PATCH 28/37] chore: tests --- tests/unit/adapters/http.test.js | 301 ++++++++++++++++++++++++++++++- 1 file changed, 294 insertions(+), 7 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index c6ce63e657..11b3b0acb3 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -1,6 +1,11 @@ import { describe, it } from 'vitest'; import assert from 'assert'; -import { startHTTPServer, stopHTTPServer, generateReadable } from '../../setup/server.js'; +import { + startHTTPServer, + stopHTTPServer, + handleFormData, + generateReadable, +} from '../../setup/server.js'; import axios from '../../../index.js'; import AxiosError from '../../../lib/core/AxiosError.js'; import { __setProxy } from '../../../lib/adapters/http.js'; @@ -14,10 +19,17 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import devNull from 'dev-null'; +import FormDataLegacy from 'form-data'; +import formidable from 'formidable'; +import { FormData as FormDataPolyfill, Blob as BlobPolyfill } from 'formdata-node'; +import express from 'express'; +import multer from 'multer'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); const thisTestFilePath = path.join(adaptersTestsDir, 'http.test.js'); + const FormDataSpecCompliant = typeof FormData !== 'undefined' ? FormData : FormDataPolyfill; + const BlobSpecCompliant = typeof Blob !== 'undefined' ? Blob : BlobPolyfill; it('should support IPv4 literal strings', async () => { const data = { @@ -1936,12 +1948,287 @@ describe('supports http with nodejs', () => { }); it('should return malformed URL', async () => { - await assert.rejects( - axios.get('tel:484-695-3408'), - (error) => { - assert.equal(error.message, 'Unsupported protocol tel:'); - return true; - } + await assert.rejects(axios.get('tel:484-695-3408'), (error) => { + assert.equal(error.message, 'Unsupported protocol tel:'); + return true; + }); + }); + + it('should return unsupported protocol', async () => { + await assert.rejects(axios.get('ftp:google.com'), (error) => { + assert.equal(error.message, 'Unsupported protocol ftp:'); + return true; + }); + }); + + it('should supply a user-agent if one is not specified', async () => { + const server = await startHTTPServer( + (req, res) => { + assert.equal(req.headers['user-agent'], `axios/${axios.VERSION}`); + res.end(); + }, + { port: 8080 } + ); + + try { + await axios.get(`http://localhost:${server.address().port}/`); + } finally { + await stopHTTPServer(server); + } + }); + + it('should omit a user-agent if one is explicitly disclaimed', async () => { + const server = await startHTTPServer( + (req, res) => { + assert.equal('user-agent' in req.headers, false); + assert.equal('User-Agent' in req.headers, false); + res.end(); + }, + { port: 8080 } + ); + + try { + await axios.get(`http://localhost:${server.address().port}/`, { + headers: { + 'User-Agent': null, + }, + }); + } finally { + await stopHTTPServer(server); + } + }); + + it('should throw an error if http server that aborts a chunked request', async () => { + const server = await startHTTPServer( + (req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write('chunk 1'); + + setTimeout(() => { + res.write('chunk 2'); + }, 100); + + setTimeout(() => { + res.destroy(); + }, 200); + }, + { port: 8080 } + ); + + try { + await assert.rejects( + axios.get(`http://localhost:${server.address().port}/aborted`, { + timeout: 500, + }), + (error) => { + assert.strictEqual(error.code, 'ERR_BAD_RESPONSE'); + assert.strictEqual(error.message, 'stream has been aborted'); + + return true; + } + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should able to cancel multiple requests with CancelToken', async () => { + const server = await startHTTPServer( + (req, res) => { + res.end('ok'); + }, + { port: 8080 } ); + + try { + const source = axios.CancelToken.source(); + const canceledStack = []; + + const requests = [1, 2, 3, 4, 5].map(async (id) => { + try { + await axios.get('/foo/bar', { + baseURL: `http://localhost:${server.address().port}`, + cancelToken: source.token, + }); + } catch (error) { + if (!axios.isCancel(error)) { + throw error; + } + + canceledStack.push(id); + } + }); + + source.cancel('Aborted by user'); + + await Promise.all(requests); + assert.deepStrictEqual(canceledStack.sort(), [1, 2, 3, 4, 5]); + } finally { + await stopHTTPServer(server); + } + }); + + describe('FormData', () => { + describe('form-data instance (https://www.npmjs.com/package/form-data)', () => { + it('should allow passing FormData', async () => { + const form = new FormDataLegacy(); + const file1 = Buffer.from('foo', 'utf8'); + const image = path.resolve(adaptersTestsDir, './axios.png'); + const fileStream = fs.createReadStream(image); + const stat = fs.statSync(image); + + form.append('foo', 'bar'); + form.append('file1', file1, { + filename: 'bar.jpg', + filepath: 'temp/bar.jpg', + contentType: 'image/jpeg', + }); + form.append('fileStream', fileStream); + + const server = await startHTTPServer( + (req, res) => { + const receivedForm = new formidable.IncomingForm(); + + assert.ok(req.rawHeaders.some((header) => header.toLowerCase() === 'content-length')); + + receivedForm.parse(req, (error, fields, files) => { + if (error) { + res.statusCode = 500; + res.end(error.message); + return; + } + + res.end( + JSON.stringify({ + fields, + files, + }) + ); + }); + }, + { port: 8080 } + ); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, form, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + + assert.deepStrictEqual(response.data.fields, { foo: 'bar' }); + + assert.strictEqual(response.data.files.file1.mimetype, 'image/jpeg'); + assert.strictEqual(response.data.files.file1.originalFilename, 'temp/bar.jpg'); + assert.strictEqual(response.data.files.file1.size, 3); + + assert.strictEqual(response.data.files.fileStream.mimetype, 'image/png'); + assert.strictEqual(response.data.files.fileStream.originalFilename, 'axios.png'); + assert.strictEqual(response.data.files.fileStream.size, stat.size); + } finally { + await stopHTTPServer(server); + } + }); + }); + + describe('SpecCompliant FormData', () => { + it('should allow passing FormData', async () => { + const server = await startHTTPServer( + async (req, res) => { + const { fields, files } = await handleFormData(req); + + res.end( + JSON.stringify({ + fields, + files, + }) + ); + }, + { port: 8080 } + ); + + try { + const form = new FormDataSpecCompliant(); + const blobContent = 'blob-content'; + const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); + + form.append('foo1', 'bar1'); + form.append('foo2', 'bar2'); + form.append('file1', blob); + + const { data } = await axios.post(`http://localhost:${server.address().port}`, form, { + maxRedirects: 0, + }); + + assert.deepStrictEqual(data.fields, { foo1: 'bar1', foo2: 'bar2' }); + assert.deepStrictEqual(typeof data.files.file1, 'object'); + + const { size, mimetype, originalFilename } = data.files.file1; + + assert.deepStrictEqual( + { size, mimetype, originalFilename }, + { + mimetype: 'image/jpeg', + originalFilename: 'blob', + size: Buffer.from(blobContent).byteLength, + } + ); + } finally { + await stopHTTPServer(server); + } + }); + }); + }); + + describe('toFormData helper', () => { + it('should properly serialize nested objects for parsing with multer.js (express.js)', async () => { + const app = express(); + const obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + obj: { x: '1', y: { z: '1' } }, + users: [ + { name: 'Peter', surname: 'griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], + }; + + app.post('/', multer().none(), (req, res) => { + res.send(JSON.stringify(req.body)); + }); + + const server = await new Promise( + (resolve, reject) => { + const expressServer = app.listen(0, () => resolve(expressServer)); + expressServer.on('error', reject); + }, + { port: 8080 } + ); + + try { + await Promise.all( + [null, false, true].map((mode) => + axios + .postForm(`http://localhost:${server.address().port}/`, obj, { + formSerializer: { indexes: mode }, + }) + .then((response) => { + assert.deepStrictEqual(response.data, obj, `Index mode ${mode}`); + }) + ) + ); + } finally { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + } + }); }); }); From 28a096d0a66f2651c9ed61d8ac11cc2ee3464b16 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 18:09:35 +0200 Subject: [PATCH 29/37] chore: tests --- tests/unit/adapters/http.test.js | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 11b3b0acb3..a3b293f33f 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -24,6 +24,8 @@ import formidable from 'formidable'; import { FormData as FormDataPolyfill, Blob as BlobPolyfill } from 'formdata-node'; import express from 'express'; import multer from 'multer'; +import getStream from 'get-stream'; +import bodyParser from 'body-parser'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); @@ -2231,4 +2233,114 @@ describe('supports http with nodejs', () => { } }); }); + + describe('Blob', () => { + it('should support Blob', async () => { + const server = await startHTTPServer( + async (req, res) => { + res.end(await getStream(req)); + }, + { port: 8080 } + ); + + try { + const blobContent = 'blob-content'; + const blob = new BlobSpecCompliant([blobContent], { type: 'image/jpeg' }); + + const { data } = await axios.post(`http://localhost:${server.address().port}`, blob, { + maxRedirects: 0, + }); + + assert.deepStrictEqual(data, blobContent); + } finally { + await stopHTTPServer(server); + } + }); + }); + + describe('URLEncoded Form', () => { + it('should post object data as url-encoded form if content-type is application/x-www-form-urlencoded', async () => { + const app = express(); + const obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + obj: { x: '1', y: { z: '1' } }, + users: [ + { name: 'Peter', surname: 'griffin' }, + { name: 'Thomas', surname: 'Anderson' }, + ], + }; + + app.use(bodyParser.urlencoded({ extended: true })); + + app.post('/', (req, res) => { + res.send(JSON.stringify(req.body)); + }); + + const server = await new Promise( + (resolve, reject) => { + const expressServer = app.listen(0, () => resolve(expressServer)); + expressServer.on('error', reject); + }, + { port: 8080 } + ); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, obj, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + }); + assert.deepStrictEqual(response.data, obj); + } finally { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + } + }); + + it('should respect formSerializer config', async () => { + const obj = { + arr1: ['1', '2', '3'], + arr2: ['1', ['2'], '3'], + }; + + const form = new URLSearchParams(); + form.append('arr1[0]', '1'); + form.append('arr1[1]', '2'); + form.append('arr1[2]', '3'); + form.append('arr2[0]', '1'); + form.append('arr2[1][0]', '2'); + form.append('arr2[2]', '3'); + + const server = await startHTTPServer( + (req, res) => { + req.pipe(res); + }, + { port: 8080 } + ); + + try { + const response = await axios.post(`http://localhost:${server.address().port}/`, obj, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + formSerializer: { + indexes: true, + }, + }); + + assert.strictEqual(response.data, form.toString()); + } finally { + await stopHTTPServer(server); + } + }); + }); }); From 72558ce8b38f9d6d731d685b15b1d848d9c3d6a8 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 18:22:14 +0200 Subject: [PATCH 30/37] chore: tests --- test/unit/adapters/http.js | 2 - tests/unit/adapters/http.test.js | 374 +++++++++++++++++++++++++++++++ 2 files changed, 374 insertions(+), 2 deletions(-) diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index c3ac482edc..77bbe495df 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -2465,8 +2465,6 @@ describe('supports http with nodejs', function () { }); describe('request aborting', function () { - //this.timeout(5000); - it('should be able to abort the response stream', async () => { server = await startHTTPServer({ rate: 100_000, diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index a3b293f33f..6afd5bac90 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -4,6 +4,7 @@ import { startHTTPServer, stopHTTPServer, handleFormData, + setTimeoutAsync, generateReadable, } from '../../setup/server.js'; import axios from '../../../index.js'; @@ -26,12 +27,23 @@ import express from 'express'; import multer from 'multer'; import getStream from 'get-stream'; import bodyParser from 'body-parser'; +import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); const thisTestFilePath = path.join(adaptersTestsDir, 'http.test.js'); const FormDataSpecCompliant = typeof FormData !== 'undefined' ? FormData : FormDataPolyfill; const BlobSpecCompliant = typeof Blob !== 'undefined' ? Blob : BlobPolyfill; + const isBlobSupported = typeof Blob !== 'undefined'; + + function toleranceRange(positive, negative) { + const p = 1 + positive / 100; + const n = 1 - negative / 100; + + return (actualValue, value) => { + return actualValue > value ? actualValue <= value * p : actualValue >= value * n; + }; + } it('should support IPv4 literal strings', async () => { const data = { @@ -2343,4 +2355,366 @@ describe('supports http with nodejs', () => { } }); }); + + describe('Data URL', () => { + it('should support requesting data URL as a Buffer', async () => { + const buffer = Buffer.from('123'); + const dataURI = `data:application/octet-stream;base64,${buffer.toString('base64')}`; + + const { data } = await axios.get(dataURI); + assert.deepStrictEqual(data, buffer); + }); + + it('should support requesting data URL as a Blob (if supported by the environment)', async () => { + if (!isBlobSupported) { + return; + } + + const buffer = Buffer.from('123'); + const dataURI = `data:application/octet-stream;base64,${buffer.toString('base64')}`; + + const { data } = await axios.get(dataURI, { responseType: 'blob' }); + assert.strictEqual(data.type, 'application/octet-stream'); + assert.deepStrictEqual(await data.text(), '123'); + }); + + it('should support requesting data URL as a String (text)', async () => { + const buffer = Buffer.from('123', 'utf-8'); + const dataURI = `data:application/octet-stream;base64,${buffer.toString('base64')}`; + + const { data } = await axios.get(dataURI, { responseType: 'text' }); + assert.deepStrictEqual(data, '123'); + }); + + it('should support requesting data URL as a Stream', async () => { + const buffer = Buffer.from('123', 'utf-8'); + const dataURI = `data:application/octet-stream;base64,${buffer.toString('base64')}`; + + const { data } = await axios.get(dataURI, { responseType: 'stream' }); + assert.strictEqual(await getStream(data), '123'); + }); + }); + + describe('progress', () => { + describe('upload', () => { + it('should support upload progress capturing', async () => { + const server = await startHTTPServer( + { + rate: 100 * 1024, + }, + { port: 8080 } + ); + + try { + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + const readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await axios.post(`http://localhost:${server.address().port}`, readable, { + onUploadProgress: ({ loaded, total, progress, bytes, upload }) => { + samples.push({ + loaded, + total, + progress, + bytes, + upload, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + }); + + assert.strictEqual(data, content); + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + upload: true, + }; + } + })() + ) + ); + } finally { + await stopHTTPServer(server); + } + }, 15000); + }); + + describe('download', () => { + it('should support download progress capturing', async () => { + const server = await startHTTPServer( + { + rate: 100 * 1024, + }, + { port: 8080 } + ); + + try { + let content = ''; + const count = 10; + const chunk = 'test'; + const chunkLength = Buffer.byteLength(chunk); + const contentLength = count * chunkLength; + + const readable = stream.Readable.from( + (async function* () { + let i = count; + + while (i-- > 0) { + await setTimeoutAsync(1100); + content += chunk; + yield chunk; + } + })() + ); + + const samples = []; + + const { data } = await axios.post(`http://localhost:${server.address().port}`, readable, { + onDownloadProgress: ({ loaded, total, progress, bytes, download }) => { + samples.push({ + loaded, + total, + progress, + bytes, + download, + }); + }, + headers: { + 'Content-Length': contentLength, + }, + responseType: 'text', + maxRedirects: 0, + }); + + assert.strictEqual(data, content); + assert.deepStrictEqual( + samples, + Array.from( + (function* () { + for (let i = 1; i <= 10; i++) { + yield { + loaded: chunkLength * i, + total: contentLength, + progress: (chunkLength * i) / contentLength, + bytes: 4, + download: true, + }; + } + })() + ) + ); + } finally { + await stopHTTPServer(server); + } + }, 15000); + }); + }); + + describe('Rate limit', () => { + it( + 'should support upload rate limit', + async () => { + const secs = 10; + const configRate = 100000; + const chunkLength = configRate * secs; + const server = await startHTTPServer(); + + try { + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); + + const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { + onUploadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [configRate], + responseType: 'text', + maxRedirects: 0, + }); + + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map((sample) => sample.rate) + .join(', ')}]` + ); + + const progressTicksRate = 2; + const expectedProgress = (i + skip) / secs / progressTicksRate; + + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map((sample) => sample.progress) + .join(', ')}]` + ); + }); + + assert.strictEqual(data, buf.toString(), 'content corrupted'); + } finally { + await stopHTTPServer(server); + } + }, + 30000 + ); + + it( + 'should support download rate limit', + async () => { + const secs = 10; + const configRate = 100000; + const chunkLength = configRate * secs; + const server = await startHTTPServer(); + + try { + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); + + const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { + onDownloadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [0, configRate], + responseType: 'text', + maxRedirects: 0, + }); + + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map((sample) => sample.rate) + .join(', ')}]` + ); + + const progressTicksRate = 3; + const expectedProgress = (i + skip) / secs / progressTicksRate; + + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map((sample) => sample.progress) + .join(', ')}]` + ); + }); + + assert.strictEqual(data, buf.toString(), 'content corrupted'); + } finally { + await stopHTTPServer(server); + } + }, + 30000 + ); + }); + + describe('request aborting', () => { + it('should be able to abort the response stream', async () => { + const server = await startHTTPServer({ + rate: 100000, + useBuffering: true, + }); + + try { + const buf = Buffer.alloc(1024 * 1024); + const controller = new AbortController(); + + const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { + responseType: 'stream', + signal: controller.signal, + maxRedirects: 0, + }); + + setTimeout(() => { + controller.abort(); + }, 500); + + let streamError; + data.on('error', (error) => { + streamError = error; + }); + + await assert.rejects( + new Promise((resolve, reject) => { + stream.pipeline(data, devNull(), (error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }) + ); + + assert.strictEqual(streamError && streamError.code, 'ERR_CANCELED'); + } finally { + await stopHTTPServer(server); + } + }); + }); + + it('should properly handle synchronous errors inside the adapter', async () => { + await assert.rejects(() => axios.get('http://192.168.0.285'), /Invalid URL/); + }); + + it('should support function as paramsSerializer value', async () => { + const server = await startHTTPServer((req, res) => res.end(req.url)); + + try { + const { data } = await axios.post(`http://localhost:${server.address().port}`, 'test', { + params: { + x: 1, + }, + paramsSerializer: () => 'foo', + maxRedirects: 0, + }); + + assert.strictEqual(data, '/?foo'); + } finally { + await stopHTTPServer(server); + } + }); }); From c50fec5db4bb16fdd765b7edd2f5fe8cb03cae47 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 19:13:33 +0200 Subject: [PATCH 31/37] chore: tests --- tests/unit/adapters/http.test.js | 347 ++++++++++++++++++++++--------- 1 file changed, 249 insertions(+), 98 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 6afd5bac90..d1a1d5e1bd 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -3,6 +3,7 @@ import assert from 'assert'; import { startHTTPServer, stopHTTPServer, + SERVER_HANDLER_STREAM_ECHO, handleFormData, setTimeoutAsync, generateReadable, @@ -28,6 +29,7 @@ import multer from 'multer'; import getStream from 'get-stream'; import bodyParser from 'body-parser'; import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; +import { lookup } from 'dns'; describe('supports http with nodejs', () => { const adaptersTestsDir = path.join(process.cwd(), 'tests/unit/adapters'); @@ -2537,117 +2539,109 @@ describe('supports http with nodejs', () => { }); describe('Rate limit', () => { - it( - 'should support upload rate limit', - async () => { - const secs = 10; - const configRate = 100000; - const chunkLength = configRate * secs; - const server = await startHTTPServer(); + it('should support upload rate limit', async () => { + const secs = 10; + const configRate = 100000; + const chunkLength = configRate * secs; + const server = await startHTTPServer(); - try { - const buf = Buffer.alloc(chunkLength).fill('s'); - const samples = []; - const skip = 4; - const compareValues = toleranceRange(50, 50); + try { + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); - const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { - onUploadProgress: ({ loaded, total, progress, bytes, rate }) => { - samples.push({ - loaded, - total, - progress, - bytes, - rate, - }); - }, - maxRate: [configRate], - responseType: 'text', - maxRedirects: 0, - }); + const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { + onUploadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [configRate], + responseType: 'text', + maxRedirects: 0, + }); - samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { - assert.ok( - compareValues(rate, configRate), - `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples - .map((sample) => sample.rate) - .join(', ')}]` - ); + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map((sample) => sample.rate) + .join(', ')}]` + ); - const progressTicksRate = 2; - const expectedProgress = (i + skip) / secs / progressTicksRate; + const progressTicksRate = 2; + const expectedProgress = (i + skip) / secs / progressTicksRate; - assert.ok( - Math.abs(expectedProgress - progress) < 0.25, - `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples - .map((sample) => sample.progress) - .join(', ')}]` - ); - }); + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map((sample) => sample.progress) + .join(', ')}]` + ); + }); - assert.strictEqual(data, buf.toString(), 'content corrupted'); - } finally { - await stopHTTPServer(server); - } - }, - 30000 - ); + assert.strictEqual(data, buf.toString(), 'content corrupted'); + } finally { + await stopHTTPServer(server); + } + }, 30000); - it( - 'should support download rate limit', - async () => { - const secs = 10; - const configRate = 100000; - const chunkLength = configRate * secs; - const server = await startHTTPServer(); + it('should support download rate limit', async () => { + const secs = 10; + const configRate = 100000; + const chunkLength = configRate * secs; + const server = await startHTTPServer(); - try { - const buf = Buffer.alloc(chunkLength).fill('s'); - const samples = []; - const skip = 4; - const compareValues = toleranceRange(50, 50); + try { + const buf = Buffer.alloc(chunkLength).fill('s'); + const samples = []; + const skip = 4; + const compareValues = toleranceRange(50, 50); - const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { - onDownloadProgress: ({ loaded, total, progress, bytes, rate }) => { - samples.push({ - loaded, - total, - progress, - bytes, - rate, - }); - }, - maxRate: [0, configRate], - responseType: 'text', - maxRedirects: 0, - }); + const { data } = await axios.post(`http://localhost:${server.address().port}`, buf, { + onDownloadProgress: ({ loaded, total, progress, bytes, rate }) => { + samples.push({ + loaded, + total, + progress, + bytes, + rate, + }); + }, + maxRate: [0, configRate], + responseType: 'text', + maxRedirects: 0, + }); - samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { - assert.ok( - compareValues(rate, configRate), - `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples - .map((sample) => sample.rate) - .join(', ')}]` - ); + samples.slice(skip).forEach(({ rate, progress }, i, _samples) => { + assert.ok( + compareValues(rate, configRate), + `Rate sample at index ${i} is out of the expected range (${rate} / ${configRate}) [${_samples + .map((sample) => sample.rate) + .join(', ')}]` + ); - const progressTicksRate = 3; - const expectedProgress = (i + skip) / secs / progressTicksRate; + const progressTicksRate = 3; + const expectedProgress = (i + skip) / secs / progressTicksRate; - assert.ok( - Math.abs(expectedProgress - progress) < 0.25, - `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples - .map((sample) => sample.progress) - .join(', ')}]` - ); - }); + assert.ok( + Math.abs(expectedProgress - progress) < 0.25, + `Progress sample at index ${i} is out of the expected range (${progress} / ${expectedProgress}) [${_samples + .map((sample) => sample.progress) + .join(', ')}]` + ); + }); - assert.strictEqual(data, buf.toString(), 'content corrupted'); - } finally { - await stopHTTPServer(server); - } - }, - 30000 - ); + assert.strictEqual(data, buf.toString(), 'content corrupted'); + } finally { + await stopHTTPServer(server); + } + }, 30000); }); describe('request aborting', () => { @@ -2717,4 +2711,161 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); + + describe('DNS', () => { + it('should support a custom DNS lookup function', async () => { + const server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + const payload = 'test'; + let isCalled = false; + + try { + const { data } = await axios.post( + `http://fake-name.axios:${server.address().port}`, + payload, + { + lookup: (hostname, opt, cb) => { + isCalled = true; + cb(null, '127.0.0.1', 4); + }, + } + ); + + assert.ok(isCalled); + assert.strictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support a custom DNS lookup function with address entry passing', async () => { + const server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + const payload = 'test'; + let isCalled = false; + + try { + const { data } = await axios.post( + `http://fake-name.axios:${server.address().port}`, + payload, + { + lookup: (hostname, opt, cb) => { + isCalled = true; + cb(null, { address: '127.0.0.1', family: 4 }); + }, + } + ); + + assert.ok(isCalled); + assert.strictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support a custom DNS lookup function (async)', async () => { + const server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + const payload = 'test'; + let isCalled = false; + + try { + const { data } = await axios.post( + `http://fake-name.axios:${server.address().port}`, + payload, + { + lookup: async (hostname, opt) => { + isCalled = true; + return ['127.0.0.1', 4]; + }, + } + ); + + assert.ok(isCalled); + assert.strictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support a custom DNS lookup function with address entry (async)', async () => { + const server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + const payload = 'test'; + let isCalled = false; + + try { + const { data } = await axios.post( + `http://fake-name.axios:${server.address().port}`, + payload, + { + lookup: async (hostname, opt) => { + isCalled = true; + return { address: '127.0.0.1', family: 4 }; + }, + } + ); + + assert.ok(isCalled); + assert.strictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support a custom DNS lookup function that returns only IP address (async)', async () => { + const server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO); + const payload = 'test'; + let isCalled = false; + + try { + const { data } = await axios.post( + `http://fake-name.axios:${server.address().port}`, + payload, + { + lookup: async (hostname, opt) => { + isCalled = true; + return '127.0.0.1'; + }, + } + ); + + assert.ok(isCalled); + assert.strictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should handle errors', async () => { + await assert.rejects(async () => { + await axios.get('https://no-such-domain-987654.com', { + lookup, + }); + }, /ENOTFOUND/); + }); + }); + + describe('JSON', () => { + it('should support reviver on JSON.parse', async () => { + const server = await startHTTPServer( + async (_, res) => { + res.end( + JSON.stringify({ + foo: 'bar', + }) + ); + }, + { port: 8080 } + ); + + try { + const { data } = await axios.get(`http://localhost:${server.address().port}`, { + parseReviver: (key, value) => { + return key === 'foo' ? 'success' : value; + }, + }); + + assert.deepStrictEqual(data, { foo: 'success' }); + } finally { + await stopHTTPServer(server); + } + }); + }); }); From 908e735f684ba419db9da6b98a565357f20fb684 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 19:59:36 +0200 Subject: [PATCH 32/37] chore: tests --- tests/unit/adapters/http.test.js | 550 ++++++++++++++++++++++++++++++- 1 file changed, 548 insertions(+), 2 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index d1a1d5e1bd..93323f7449 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -597,9 +597,9 @@ describe('supports http with nodejs', () => { await stopHTTPServer(server); } }); - }); - /// algos for later + /// algos for later + }); it('should support UTF8', async () => { const str = Array(100000).join('ж'); @@ -2868,4 +2868,550 @@ describe('supports http with nodejs', () => { } }); }); + + describe('HTTP2', () => { + const createHttp2Axios = (baseURL) => + axios.create({ + baseURL, + httpVersion: 2, + http2Options: { + rejectUnauthorized: false, + }, + }); + + it('should merge request http2Options with its instance config', async () => { + const http2Axios = createHttp2Axios('https://127.0.0.1:8080'); + + const { data } = await http2Axios.get('/', { + http2Options: { + foo: 'test', + }, + adapter: async (config) => { + return { + data: config.http2Options, + }; + }, + }); + + assert.deepStrictEqual(data, { + rejectUnauthorized: false, + foo: 'test', + }); + }); + + it('should support http2 transport', async () => { + const server = await startHTTPServer( + (req, res) => { + res.end('OK'); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + const { data } = await http2Axios.get(localServerURL); + assert.deepStrictEqual(data, 'OK'); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support request payload', async () => { + const server = await startHTTPServer(null, { + useHTTP2: true, + port: 8080, + }); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + const payload = 'DATA'; + const { data } = await http2Axios.post(localServerURL, payload); + assert.deepStrictEqual(data, payload); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support FormData as a payload', async () => { + if (typeof FormData !== 'function') { + return; + } + + const server = await startHTTPServer( + async (req, res) => { + const { fields, files } = await handleFormData(req); + + res.end( + JSON.stringify({ + fields, + files, + }) + ); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + const form = new FormData(); + form.append('x', 'foo'); + form.append('y', 'bar'); + + const { data } = await http2Axios.post(localServerURL, form); + + assert.deepStrictEqual(data, { + fields: { + x: 'foo', + y: 'bar', + }, + files: {}, + }); + } finally { + await stopHTTPServer(server); + } + }); + + describe('response types', () => { + const originalData = '{"test": "OK"}'; + const fixtures = { + text: (value) => assert.strictEqual(value, originalData), + arraybuffer: (value) => assert.deepStrictEqual(value, Buffer.from(originalData)), + stream: async (value) => assert.deepStrictEqual(await getStream(value), originalData), + json: async (value) => assert.deepStrictEqual(value, JSON.parse(originalData)), + }; + + for (const [responseType, assertValue] of Object.entries(fixtures)) { + it(`should support ${responseType} response type`, async () => { + const server = await startHTTPServer( + (req, res) => { + res.end(originalData); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + const { data } = await http2Axios.get(localServerURL, { + responseType, + }); + await assertValue(data); + } finally { + await stopHTTPServer(server); + } + }); + } + }); + + it('should support request timeout', async () => { + let isAborted = false; + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 15000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + server.on('stream', (http2Stream) => { + http2Stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + await assert.rejects(async () => { + await http2Axios.get(localServerURL, { + timeout: 500, + }); + }, /timeout/); + + await promise; + assert.ok(isAborted); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support request cancellation', async () => { + if (typeof AbortSignal !== 'function' || !AbortSignal.timeout) { + return; + } + + let isAborted = false; + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 15000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + server.on('stream', (http2Stream) => { + http2Stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + await assert.rejects(async () => { + await http2Axios.get(localServerURL, { + signal: AbortSignal.timeout(500), + }); + }, /CanceledError: canceled/); + + await promise; + assert.ok(isAborted); + } finally { + await stopHTTPServer(server); + } + }); + + it('should support stream response cancellation', async () => { + let isAborted = false; + const source = axios.CancelToken.source(); + + let aborted; + const promise = new Promise((resolve) => (aborted = resolve)); + + const server = await startHTTPServer( + (req, res) => { + generateReadable(10000, 100, 100).pipe(res); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + server.on('stream', (http2Stream) => { + http2Stream.once('aborted', () => { + isAborted = true; + aborted(); + }); + }); + + const { data } = await http2Axios.get(localServerURL, { + cancelToken: source.token, + responseType: 'stream', + }); + + setTimeout(() => source.cancel()); + + await assert.rejects( + new Promise((resolve, reject) => { + stream.pipeline(data, devNull(), (error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }), + /CanceledError: canceled/ + ); + + await promise; + assert.ok(isAborted); + } finally { + await stopHTTPServer(server); + } + }); + + describe('session', () => { + it('should reuse session for the target authority', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 1000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + const [response1, response2] = await Promise.all([ + http2Axios.get(localServerURL, { + responseType: 'stream', + }), + http2Axios.get(localServerURL, { + responseType: 'stream', + }), + ]); + + assert.strictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should use different sessions for different authorities', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 2000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + const server2 = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 2000); + }, + { + useHTTP2: true, + port: 8081, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const localServerURL2 = `https://127.0.0.1:${server2.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + const [response1, response2] = await Promise.all([ + http2Axios.get(localServerURL, { + responseType: 'stream', + }), + http2Axios.get(localServerURL2, { + responseType: 'stream', + }), + ]); + + assert.notStrictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + } finally { + await Promise.all([stopHTTPServer(server), stopHTTPServer(server2)]); + } + }); + + it('should use different sessions for requests with different http2Options set', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => { + res.end('OK'); + }, 1000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + const [response1, response2] = await Promise.all([ + http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: {}, + }), + http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: { + foo: 'test', + }, + }), + ]); + + assert.notStrictEqual(response1.data.session, response2.data.session); + + assert.deepStrictEqual( + await Promise.all([getStream(response1.data), getStream(response2.data)]), + ['OK', 'OK'] + ); + } finally { + await stopHTTPServer(server); + } + }); + + it('should use the same session for request with the same resolved http2Options set', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 1000); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + const responses = await Promise.all([ + http2Axios.get(localServerURL, { + responseType: 'stream', + }), + http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: undefined, + }), + http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: {}, + }), + ]); + + assert.strictEqual(responses[1].data.session, responses[0].data.session); + assert.strictEqual(responses[2].data.session, responses[0].data.session); + + assert.deepStrictEqual(await Promise.all(responses.map(({ data }) => getStream(data))), [ + 'OK', + 'OK', + 'OK', + ]); + } finally { + await stopHTTPServer(server); + } + }); + + it('should use different sessions after previous session timeout', async () => { + const server = await startHTTPServer( + (req, res) => { + setTimeout(() => res.end('OK'), 100); + }, + { + useHTTP2: true, + port: 8080, + } + ); + + try { + const localServerURL = `https://127.0.0.1:${server.address().port}`; + const http2Axios = createHttp2Axios(localServerURL); + + const response1 = await http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: { + sessionTimeout: 1000, + }, + }); + + const data1 = await getStream(response1.data); + + await setTimeoutAsync(5000); + + const response2 = await http2Axios.get(localServerURL, { + responseType: 'stream', + http2Options: { + sessionTimeout: 1000, + }, + }); + + const data2 = await getStream(response2.data); + + assert.notStrictEqual(response1.data.session, response2.data.session); + assert.strictEqual(data1, 'OK'); + assert.strictEqual(data2, 'OK'); + } finally { + await stopHTTPServer(server); + } + }, 15000); + }); + }); + + // it('should not abort stream on settle rejection', async () => { + // const server = await startHTTPServer((req, res) => { + // res.statusCode = 404; + // res.end('OK'); + // }); + + // try { + // await assert.rejects( + // axios.get(`http://localhost:${server.address().port}`, { + // responseType: 'stream', + // }), + // async (error) => { + // assert.strictEqual(await getStream(error.response.data), 'OK'); + // return true; + // } + // ); + // } finally { + // await stopHTTPServer(server); + // } + // }); + + describe('keep-alive', () => { + it('should not fail with "socket hang up" when using timeouts', async () => { + const server = await startHTTPServer( + async (req, res) => { + if (req.url === '/wait') { + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + + res.end('ok'); + }, + { port: 8080 } + ); + + try { + const baseURL = `http://localhost:${server.address().port}`; + await axios.get('/1', { baseURL, timeout: 1000 }); + await axios.get('/wait', { baseURL, timeout: 0 }); + } finally { + await stopHTTPServer(server); + } + }, 15000); + }); }); From db6f45172ebc2ae0f30021a24e63396a7a9b9b10 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 20:04:39 +0200 Subject: [PATCH 33/37] chore: tests --- tests/unit/adapters/http.test.js | 139 ++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 93323f7449..20d187f73b 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -598,7 +598,144 @@ describe('supports http with nodejs', () => { } }); - /// algos for later + describe('algorithms', () => { + const responseBody = 'str'; + + const gzip = (value) => + new Promise((resolve, reject) => { + zlib.gzip(value, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + const deflate = (value) => + new Promise((resolve, reject) => { + zlib.deflate(value, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + const deflateRaw = (value) => + new Promise((resolve, reject) => { + zlib.deflateRaw(value, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + const brotliCompress = (value) => + new Promise((resolve, reject) => { + zlib.brotliCompress(value, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(compressed); + }); + }); + + for (const [typeName, zipped] of Object.entries({ + gzip: gzip(responseBody), + GZIP: gzip(responseBody), + compress: gzip(responseBody), + deflate: deflate(responseBody), + 'deflate-raw': deflateRaw(responseBody), + br: brotliCompress(responseBody), + })) { + const type = typeName.split('-')[0]; + + describe(`${typeName} decompression`, () => { + it('should support decompression', async () => { + const server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.end(await zipped); + }); + + try { + const { data } = await axios.get(`http://localhost:${server.address().port}`); + assert.strictEqual(data, responseBody); + } finally { + await stopHTTPServer(server); + } + }); + + it(`should not fail if response content-length header is missing (${type})`, async () => { + const server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.removeHeader('Content-Length'); + res.end(await zipped); + }); + + try { + const { data } = await axios.get(`http://localhost:${server.address().port}`); + assert.strictEqual(data, responseBody); + } finally { + await stopHTTPServer(server); + } + }); + + it('should not fail with chunked responses (without Content-Length header)', async () => { + const server = await startHTTPServer(async (req, res) => { + res.setHeader('Content-Encoding', type); + res.setHeader('Transfer-Encoding', 'chunked'); + res.removeHeader('Content-Length'); + res.write(await zipped); + res.end(); + }); + + try { + const { data } = await axios.get(`http://localhost:${server.address().port}`); + assert.strictEqual(data, responseBody); + } finally { + await stopHTTPServer(server); + } + }); + + it('should not fail with an empty response without content-length header (Z_BUF_ERROR)', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Encoding', type); + res.removeHeader('Content-Length'); + res.end(); + }); + + try { + const { data } = await axios.get(`http://localhost:${server.address().port}`); + assert.strictEqual(data, ''); + } finally { + await stopHTTPServer(server); + } + }); + + it('should not fail with an empty response with content-length header (Z_BUF_ERROR)', async () => { + const server = await startHTTPServer((req, res) => { + res.setHeader('Content-Encoding', type); + res.end(); + }); + + try { + await axios.get(`http://localhost:${server.address().port}`); + } finally { + await stopHTTPServer(server); + } + }); + }); + } + }); }); it('should support UTF8', async () => { From 8f52b54ba33d4b4ec1a725bf7b8c8f527881c259 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 20:09:02 +0200 Subject: [PATCH 34/37] chore: tests --- tests/unit/adapters/http.test.js | 43 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index 20d187f73b..ccb3485b40 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -3508,26 +3508,29 @@ describe('supports http with nodejs', () => { }); }); - // it('should not abort stream on settle rejection', async () => { - // const server = await startHTTPServer((req, res) => { - // res.statusCode = 404; - // res.end('OK'); - // }); - - // try { - // await assert.rejects( - // axios.get(`http://localhost:${server.address().port}`, { - // responseType: 'stream', - // }), - // async (error) => { - // assert.strictEqual(await getStream(error.response.data), 'OK'); - // return true; - // } - // ); - // } finally { - // await stopHTTPServer(server); - // } - // }); + it('should not abort stream on settle rejection', async () => { + const server = await startHTTPServer((req, res) => { + res.statusCode = 404; + res.end('OK'); + }); + + try { + let error; + + try { + await axios.get(`http://localhost:${server.address().port}`, { + responseType: 'stream', + }); + } catch (err) { + error = err; + } + + assert.ok(error, 'request should be rejected'); + assert.strictEqual(await getStream(error.response.data), 'OK'); + } finally { + await stopHTTPServer(server); + } + }); describe('keep-alive', () => { it('should not fail with "socket hang up" when using timeouts', async () => { From 12880b9207ad697e013bf734f133494790c9ad76 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 20:15:09 +0200 Subject: [PATCH 35/37] chore: remove un-needed docs --- .../rewrite_helper_tests_a2f815ee.plan.md | 55 ------------------- ...dapters-esm-ts-modernization-brainstorm.md | 33 ----------- 2 files changed, 88 deletions(-) delete mode 100644 .cursor/plans/rewrite_helper_tests_a2f815ee.plan.md delete mode 100644 docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md diff --git a/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md b/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md deleted file mode 100644 index 53614da0ba..0000000000 --- a/.cursor/plans/rewrite_helper_tests_a2f815ee.plan.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: Rewrite helper tests -overview: Migrate coverage intent from legacy helper tests into the `tests/unit` Vitest suite, while keeping legacy files untouched and avoiding config/script changes. -todos: - - id: map-legacy-to-vitest - content: Create legacy-to-tests/unit parity checklist for all helper test files - status: completed - - id: port-missing-cases - content: Port missing legacy assertions/edge cases into corresponding tests/unit files - status: completed - - id: normalize-vitest-style - content: Align rewritten tests with current repository Vitest conventions - status: completed - - id: run-vitest-unit - content: Run targeted and full unit Vitest tests to validate rewrite - status: completed - - id: verify-legacy-untouched - content: Ensure test/unit/helpers files remain unchanged - status: completed -isProject: false ---- - -# Rewrite Helper Tests To Vitest - -## Scope And Constraints - -- Keep legacy helper tests untouched in `[/Users/jay/Code/OpenSource/axiosV1/test/unit/helpers](file:///Users/jay/Code/OpenSource/axiosV1/test/unit/helpers)`. -- Rewrite/refresh the helper test coverage in `[/Users/jay/Code/OpenSource/axiosV1/tests/unit](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit)` only. -- Make no changes to test config/scripts (Vitest already targets `tests/unit/**/*.test.js` in `[/Users/jay/Code/OpenSource/axiosV1/vitest.config.js](file:///Users/jay/Code/OpenSource/axiosV1/vitest.config.js)`). - -## Implementation Plan - -1. Build a case-by-case parity matrix from legacy helper files to Vitest files: - -- `composeSignals` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/composeSignals.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/composeSignals.test.js)` -- `estimateDataURLDecodedBytes` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/estimateDataURLDecodedBytes.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/estimateDataURLDecodedBytes.test.js)` -- `fromDataURI` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/fromDataURI.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/fromDataURI.test.js)` -- `parseProtocol` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/parseProtocol.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/parseProtocol.test.js)` -- `toFormData` → `[/Users/jay/Code/OpenSource/axiosV1/tests/unit/toFormData.test.js](file:///Users/jay/Code/OpenSource/axiosV1/tests/unit/toFormData.test.js)` - -1. For each mapped file, port any missing assertions/edge cases from legacy tests into the `tests/unit` version without changing runtime behavior under test. -2. Normalize each rewritten file to the repo’s current Vitest style: - -- Use `vitest` imports (`describe`/`it` and hooks as needed). -- Keep assertion style aligned with existing repo convention (`assert`-based checks where already standard). -- Replace Mocha-only idioms (e.g., `this.skip`) with Vitest-compatible conditional patterns (`it.skip`/runtime guards). - -1. Add brief, targeted comments only where logic is non-obvious (for example, environment-gated abort/controller coverage or React Native FormData spy behavior). -2. Run focused verification on just touched unit tests, then run the full unit Vitest project to ensure no regressions. - -## Verification - -- Run targeted files first (fast feedback): `npm run test:vitest:unit -- tests/unit/{composeSignals,estimateDataURLDecodedBytes,fromDataURI,parseProtocol,toFormData}.test.js` -- Run full unit suite: `npm run test:vitest:unit` -- Confirm legacy files remain unchanged in `[/Users/jay/Code/OpenSource/axiosV1/test/unit/helpers](file:///Users/jay/Code/OpenSource/axiosV1/test/unit/helpers)`. diff --git a/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md b/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md deleted file mode 100644 index 098ed755b3..0000000000 --- a/docs/brainstorms/2026-03-04-adapters-esm-ts-modernization-brainstorm.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -date: 2026-03-04 -topic: adapters-esm-ts-modernization ---- - -# Adapters ESM + TypeScript Modernization - -## What We're Building -We want a full modernization of Axios adapters so adapter internals are TypeScript-friendly and align with modern ESM-first development. The modernization should cover `http`, `xhr`, and `fetch` adapter areas and the adapter resolution surface anchored in `lib/adapters/adapters.js`. - -The target is improved maintainability, clearer type contracts in implementation code, and cleaner long-term adapter evolution, while respecting the project's existing cross-environment adapter semantics (name/function resolution, availability checks, and runtime adapter selection behavior). - -## Why This Approach -Three options were considered: compatibility-first full modernization, milestone cleanup with controlled breaking surface, and clean-slate modern platform reset. The selected direction is compatibility-first full modernization because it matches the repo's established pattern of incremental modernization backed by broad compatibility tests and dual-module distribution support. - -This keeps momentum high while reducing ecosystem risk. It also avoids introducing unnecessary architectural churn before proving value in adapter internals and build/type ergonomics. - -## Key Decisions -- **Full modernization scope:** The effort includes TypeScript-oriented modernization across adapter internals and ESM alignment, not only test/type touch-ups. -- **Compatibility-first posture:** Preserve current runtime behavior and adapter resolution semantics as the default success condition. -- **Adapter resolver contract remains stable:** `getAdapter` behavior, adapter availability signaling (`false`/`null`), and unknown adapter error semantics remain externally consistent. -- **Dual-module reality is acknowledged:** Changes should respect existing ESM/CJS distribution expectations unless explicitly revisited later. -- **Incremental delivery bias:** Even under full scope, work should be broken into reviewable phases to reduce regression risk. - -## Resolved Questions -- **Modernization depth:** Full modernization (not partial) was explicitly requested. -- **Preferred strategy among alternatives:** No explicit alternative was selected after options were presented, so we default to the recommended compatibility-first path. - -## Open Questions -- None at this stage. - -## Next Steps -Proceed to `/workflows:plan` to define implementation phases, file-level changes, validation strategy, and rollout checkpoints. From d5de8a9c7fcaef2b58844b3cd6e9a85b29c20f91 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 20:20:47 +0200 Subject: [PATCH 36/37] chore: update package lock --- package-lock.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package-lock.json b/package-lock.json index 2cfc1271a3..2202e99320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23481,6 +23481,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -23655,6 +23656,7 @@ "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", From 1cf5415e245cc9a9af0b2e3ec230f10e9047c830 Mon Sep 17 00:00:00 2001 From: jasonsaayman Date: Fri, 6 Mar 2026 20:36:36 +0200 Subject: [PATCH 37/37] chore: update lock --- .github/workflows/run-ci.yml | 2 +- package-lock.json | 4685 ++++++++++++++-------------------- 2 files changed, 1934 insertions(+), 2753 deletions(-) diff --git a/.github/workflows/run-ci.yml b/.github/workflows/run-ci.yml index 9cb8716d3d..6fdf19609d 100644 --- a/.github/workflows/run-ci.yml +++ b/.github/workflows/run-ci.yml @@ -31,7 +31,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: npm - - name: Install dependencies + - name: Install dependencies Node 14 if: matrix.node-version == '14.x' run: npm i - name: Install dependencies diff --git a/package-lock.json b/package-lock.json index 2202e99320..b3b2885879 100644 --- a/package-lock.json +++ b/package-lock.json @@ -223,9 +223,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", - "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.7.tgz", + "integrity": "sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w==", "dev": true, "license": "MIT", "dependencies": { @@ -1614,17 +1614,17 @@ } }, "node_modules/@commitlint/cli": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.2.tgz", - "integrity": "sha512-YjYSX2yj/WsVoxh9mNiymfFS2ADbg2EK4+1WAsMuckwKMCqJ5PDG0CJU/8GvmHWcv4VRB2V02KqSiecRksWqZQ==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.4.3.tgz", + "integrity": "sha512-Z37EMoDT7+Upg500vlr/vZrgRsb6Xc5JAA3Tv7BYbobnN/ZpqUeZnSLggBg2+1O+NptRDtyujr2DD1CPV2qwhA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/format": "^20.4.0", - "@commitlint/lint": "^20.4.2", - "@commitlint/load": "^20.4.0", - "@commitlint/read": "^20.4.0", - "@commitlint/types": "^20.4.0", + "@commitlint/format": "^20.4.3", + "@commitlint/lint": "^20.4.3", + "@commitlint/load": "^20.4.3", + "@commitlint/read": "^20.4.3", + "@commitlint/types": "^20.4.3", "tinyexec": "^1.0.0", "yargs": "^17.0.0" }, @@ -1636,27 +1636,27 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.4.2.tgz", - "integrity": "sha512-rwkTF55q7Q+6dpSKUmJoScV0f3EpDlWKw2UPzklkLS4o5krMN1tPWAVOgHRtyUTMneIapLeQwaCjn44Td6OzBQ==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.4.3.tgz", + "integrity": "sha512-9RtLySbYQAs8yEqWEqhSZo9nYhbm57jx7qHXtgRmv/nmeQIjjMcwf6Dl+y5UZcGWgWx435TAYBURONaJIuCjWg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", - "conventional-changelog-conventionalcommits": "^9.1.0" + "@commitlint/types": "^20.4.3", + "conventional-changelog-conventionalcommits": "^9.2.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/config-validator": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.4.0.tgz", - "integrity": "sha512-zShmKTF+sqyNOfAE0vKcqnpvVpG0YX8F9G/ZIQHI2CoKyK+PSdladXMSns400aZ5/QZs+0fN75B//3Q5CHw++w==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.4.3.tgz", + "integrity": "sha512-jCZpZFkcSL3ZEdL5zgUzFRdytv3xPo8iukTe9VA+QGus/BGhpp1xXSVu2B006GLLb2gYUAEGEqv64kTlpZNgmA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", + "@commitlint/types": "^20.4.3", "ajv": "^8.11.0" }, "engines": { @@ -1664,13 +1664,13 @@ } }, "node_modules/@commitlint/ensure": { - "version": "20.4.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.4.1.tgz", - "integrity": "sha512-WLQqaFx1pBooiVvBrA1YfJNFqZF8wS/YGOtr5RzApDbV9tQ52qT5VkTsY65hFTnXhW8PcDfZLaknfJTmPejmlw==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.4.3.tgz", + "integrity": "sha512-WcXGKBNn0wBKpX8VlXgxqedyrLxedIlLBCMvdamLnJFEbUGJ9JZmBVx4vhLV3ZyA8uONGOb+CzW0Y9HDbQ+ONQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", + "@commitlint/types": "^20.4.3", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -1692,13 +1692,13 @@ } }, "node_modules/@commitlint/format": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.4.0.tgz", - "integrity": "sha512-i3ki3WR0rgolFVX6r64poBHXM1t8qlFel1G1eCBvVgntE3fCJitmzSvH5JD/KVJN/snz6TfaX2CLdON7+s4WVQ==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.4.3.tgz", + "integrity": "sha512-UDJVErjLbNghop6j111rsHJYGw6MjCKAi95K0GT2yf4eeiDHy3JDRLWYWEjIaFgO+r+dQSkuqgJ1CdMTtrvHsA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", + "@commitlint/types": "^20.4.3", "picocolors": "^1.1.1" }, "engines": { @@ -1706,13 +1706,13 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "20.4.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.4.1.tgz", - "integrity": "sha512-In5EO4JR1lNsAv1oOBBO24V9ND1IqdAJDKZiEpdfjDl2HMasAcT7oA+5BKONv1pRoLG380DGPE2W2RIcUwdgLA==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.4.3.tgz", + "integrity": "sha512-W5VQKZ7fdJ1X3Tko+h87YZaqRMGN1KvQKXyCM8xFdxzMIf1KCZgN4uLz3osLB1zsFcVS4ZswHY64LI26/9ACag==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", + "@commitlint/types": "^20.4.3", "semver": "^7.6.0" }, "engines": { @@ -1733,33 +1733,33 @@ } }, "node_modules/@commitlint/lint": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.4.2.tgz", - "integrity": "sha512-buquzNRtFng6xjXvBU1abY/WPEEjCgUipNQrNmIWe8QuJ6LWLtei/LDBAzEe5ASm45+Q9L2Xi3/GVvlj50GAug==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.4.3.tgz", + "integrity": "sha512-CYOXL23e+nRKij81+d0+dymtIi7Owl9QzvblJYbEfInON/4MaETNSLFDI74LDu+YJ0ML5HZyw9Vhp9QpckwQ0A==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^20.4.1", - "@commitlint/parse": "^20.4.1", - "@commitlint/rules": "^20.4.2", - "@commitlint/types": "^20.4.0" + "@commitlint/is-ignored": "^20.4.3", + "@commitlint/parse": "^20.4.3", + "@commitlint/rules": "^20.4.3", + "@commitlint/types": "^20.4.3" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.4.0.tgz", - "integrity": "sha512-Dauup/GfjwffBXRJUdlX/YRKfSVXsXZLnINXKz0VZkXdKDcaEILAi9oflHGbfydonJnJAbXEbF3nXPm9rm3G6A==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.4.3.tgz", + "integrity": "sha512-3cdJOUVP+VcgHa7bhJoWS+Z8mBNXB5aLWMBu7Q7uX8PSeWDzdbrBlR33J1MGGf7r1PZDp+mPPiFktk031PgdRw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.4.0", + "@commitlint/config-validator": "^20.4.3", "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.4.0", - "@commitlint/types": "^20.4.0", - "cosmiconfig": "^9.0.0", + "@commitlint/resolve-extends": "^20.4.3", + "@commitlint/types": "^20.4.3", + "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", "is-plain-obj": "^4.1.0", "lodash.mergewith": "^4.6.2", @@ -1787,19 +1787,6 @@ "typescript": ">=5" } }, - "node_modules/@commitlint/load/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@commitlint/load/node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -1816,9 +1803,9 @@ } }, "node_modules/@commitlint/message": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.0.tgz", - "integrity": "sha512-B5lGtvHgiLAIsK5nLINzVW0bN5hXv+EW35sKhYHE8F7V9Uz1fR4tx3wt7mobA5UNhZKUNgB/+ldVMQE6IHZRyA==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.3.tgz", + "integrity": "sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==", "dev": true, "license": "MIT", "engines": { @@ -1826,29 +1813,29 @@ } }, "node_modules/@commitlint/parse": { - "version": "20.4.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.4.1.tgz", - "integrity": "sha512-XNtZjeRcFuAfUnhYrCY02+mpxwY4OmnvD3ETbVPs25xJFFz1nRo/25nHj+5eM+zTeRFvWFwD4GXWU2JEtoK1/w==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.4.3.tgz", + "integrity": "sha512-hzC3JCo3zs3VkQ833KnGVuWjWIzR72BWZWjQM7tY/7dfKreKAm7fEsy71tIFCRtxf2RtMP2d3RLF1U9yhFSccA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.4.0", - "conventional-changelog-angular": "^8.1.0", - "conventional-commits-parser": "^6.2.1" + "@commitlint/types": "^20.4.3", + "conventional-changelog-angular": "^8.2.0", + "conventional-commits-parser": "^6.3.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/read": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.4.0.tgz", - "integrity": "sha512-QfpFn6/I240ySEGv7YWqho4vxqtPpx40FS7kZZDjUJ+eHxu3azfhy7fFb5XzfTqVNp1hNoI3tEmiEPbDB44+cg==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.4.3.tgz", + "integrity": "sha512-j42OWv3L31WfnP8WquVjHZRt03w50Y/gEE8FAyih7GQTrIv2+pZ6VZ6pWLD/ml/3PO+RV2SPtRtTp/MvlTb8rQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/top-level": "^20.4.0", - "@commitlint/types": "^20.4.0", + "@commitlint/top-level": "^20.4.3", + "@commitlint/types": "^20.4.3", "git-raw-commits": "^4.0.0", "minimist": "^1.2.8", "tinyexec": "^1.0.0" @@ -1858,14 +1845,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.4.0.tgz", - "integrity": "sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.4.3.tgz", + "integrity": "sha512-QucxcOy+00FhS9s4Uy0OyS5HeUV+hbC6OLqkTSIm6fwMdKva+OEavaCDuLtgd9akZZlsUo//XzSmPP3sLKBPog==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.4.0", - "@commitlint/types": "^20.4.0", + "@commitlint/config-validator": "^20.4.3", + "@commitlint/types": "^20.4.3", "global-directory": "^4.0.1", "import-meta-resolve": "^4.0.0", "lodash.mergewith": "^4.6.2", @@ -1876,16 +1863,16 @@ } }, "node_modules/@commitlint/rules": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.4.2.tgz", - "integrity": "sha512-oz83pnp5Yq6uwwTAabuVQPNlPfeD2Y5ZjMb7Wx8FSUlu4sLYJjbBWt8031Z0osCFPfHzAwSYrjnfDFKtuSMdKg==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.4.3.tgz", + "integrity": "sha512-Yuosd7Grn5qiT7FovngXLyRXTMUbj9PYiSkvUgWK1B5a7+ZvrbWDS7epeUapYNYatCy/KTpPFPbgLUdE+MUrBg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.4.1", - "@commitlint/message": "^20.4.0", + "@commitlint/ensure": "^20.4.3", + "@commitlint/message": "^20.4.3", "@commitlint/to-lines": "^20.0.0", - "@commitlint/types": "^20.4.0" + "@commitlint/types": "^20.4.3" }, "engines": { "node": ">=v18" @@ -1902,9 +1889,9 @@ } }, "node_modules/@commitlint/top-level": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.0.tgz", - "integrity": "sha512-NDzq8Q6jmFaIIBC/GG6n1OQEaHdmaAAYdrZRlMgW6glYWGZ+IeuXmiymDvQNXPc82mVxq2KiE3RVpcs+1OeDeA==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.3.tgz", + "integrity": "sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1915,13 +1902,13 @@ } }, "node_modules/@commitlint/types": { - "version": "20.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.4.0.tgz", - "integrity": "sha512-aO5l99BQJ0X34ft8b0h7QFkQlqxC6e7ZPVmBKz13xM9O8obDaM1Cld4sQlJDXXU/VFuUzQ30mVtHjVz74TuStw==", + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.4.3.tgz", + "integrity": "sha512-51OWa1Gi6ODOasPmfJPq6js4pZoomima4XLZZCrkldaH2V5Nb3bVhNXPeT6XV0gubbainSpTw4zi68NqAeCNCg==", "dev": true, "license": "MIT", "dependencies": { - "conventional-commits-parser": "^6.2.1", + "conventional-commits-parser": "^6.3.0", "picocolors": "^1.1.1" }, "engines": { @@ -2424,9 +2411,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2440,17 +2427,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2458,19 +2434,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -2497,30 +2460,6 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2574,19 +2513,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2613,13 +2539,13 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -2819,9 +2745,9 @@ } }, "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -2862,13 +2788,13 @@ } }, "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { @@ -2879,9 +2805,9 @@ "license": "ISC" }, "node_modules/@npmcli/git/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -2953,10 +2879,21 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@npmcli/package-json/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -2974,30 +2911,26 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" + "brace-expansion": "^2.0.2" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/package-json/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/@npmcli/package-json/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -3021,13 +2954,13 @@ } }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/promise-spawn/node_modules/which": { @@ -3075,13 +3008,13 @@ } }, "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/run-script/node_modules/which": { @@ -3173,82 +3106,129 @@ } } }, - "node_modules/@rollup/plugin-babel/node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@rollup/plugin-commonjs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz", + "integrity": "sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" }, "engines": { - "node": ">=14.0.0" + "node": ">= 8.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "rollup": "^2.22.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/plugin-babel/node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true, "license": "MIT" }, - "node_modules/@rollup/plugin-babel/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/@rollup/plugin-commonjs/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz", - "integrity": "sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ==", + "node_modules/@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-json/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { "node": ">= 8.0.0" }, "peerDependencies": { - "rollup": "^2.22.0" + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "node_modules/@rollup/plugin-json/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-json/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-json/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.0.8" + "engines": { + "node": ">=8.6" }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/@rollup/plugin-multi-entry": { @@ -3289,23 +3269,10 @@ "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/plugin-virtual": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.1.0.tgz", - "integrity": "sha512-CPPAtlKT53HFqC8jFHb/V5WErpU8Hrq2TyCR0A7kPQMlF2wNUf0o1xuAc+Qxj8NCZM0Z3Yvl+FbUXfJjVWqDwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", "dev": true, "license": "MIT", "dependencies": { @@ -3320,13 +3287,69 @@ "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "node_modules/@rollup/plugin-node-resolve/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true, "license": "MIT" }, + "node_modules/@rollup/plugin-node-resolve/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/plugin-virtual": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.1.0.tgz", + "integrity": "sha512-CPPAtlKT53HFqC8jFHb/V5WErpU8Hrq2TyCR0A7kPQMlF2wNUf0o1xuAc+Qxj8NCZM0Z3Yvl+FbUXfJjVWqDwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", @@ -3757,6 +3780,19 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -3816,6 +3852,7 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "deprecated": "Deprecated: no longer maintained and no longer used by Sinon packages. See\n https://github.com/sinonjs/nise/issues/243 for replacement details.", "dev": true, "license": "(Unlicense OR Apache-2.0)" }, @@ -3870,6 +3907,32 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -3912,9 +3975,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -3943,14 +4006,14 @@ } }, "node_modules/@types/node": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", - "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", + "version": "25.3.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.5.tgz", + "integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/puppeteer": { @@ -4121,13 +4184,6 @@ } } }, - "node_modules/@vitest/mocker/node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, "node_modules/@vitest/mocker/node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -4255,6 +4311,22 @@ "node": ">=10.0.0" } }, + "node_modules/@wdio/logger/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@wdio/logger/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4547,9 +4619,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "peer": true, @@ -4581,9 +4653,9 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "peer": true, @@ -4661,16 +4733,13 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -4822,44 +4891,19 @@ "node": ">= 6" } }, - "node_modules/archiver-utils/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/archiver/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/archiver/node_modules/tar-stream": { @@ -5092,9 +5136,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -5256,9 +5300,9 @@ } }, "node_modules/auto-changelog/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -5302,9 +5346,9 @@ "license": "MIT" }, "node_modules/b4a": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", - "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -5453,14 +5497,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", - "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.16.tgz", + "integrity": "sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.7", "semver": "^6.3.1" }, "peerDependencies": { @@ -5468,13 +5512,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", - "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.1.tgz", + "integrity": "sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.7", "core-js-compat": "^3.48.0" }, "peerDependencies": { @@ -5482,13 +5526,13 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", - "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.7.tgz", + "integrity": "sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6" + "@babel/helper-define-polyfill-provider": "^0.6.7" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -5621,6 +5665,7 @@ "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -5630,6 +5675,84 @@ } } }, + "node_modules/bare-fs": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", + "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.7.1.tgz", + "integrity": "sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", + "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.21.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", @@ -5694,13 +5817,16 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.9.18", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz", - "integrity": "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/bcrypt-pbkdf": { @@ -5737,33 +5863,158 @@ "node": ">=4" } }, - "node_modules/bin-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", - "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", + "node_modules/bin-check/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", "dev": true, "license": "MIT", "dependencies": { - "execa": "^1.0.0", - "find-versions": "^3.0.0" - }, - "engines": { - "node": ">=6" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "node_modules/bin-version-check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", - "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", + "node_modules/bin-check/node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", "dev": true, "license": "MIT", "dependencies": { - "bin-version": "^3.0.0", - "semver": "^5.6.0", - "semver-truncate": "^1.1.2" - }, - "engines": { - "node": ">=6" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-check/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bin-check/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/bin-check/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-check/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-check/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bin-check/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bin-check/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/bin-check/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/bin-check/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/bin-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", + "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^1.0.0", + "find-versions": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/bin-version-check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", + "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bin-version": "^3.0.0", + "semver": "^5.6.0", + "semver-truncate": "^1.1.2" + }, + "engines": { + "node": ">=6" } }, "node_modules/bin-version-check/node_modules/semver": { @@ -5825,6 +6076,29 @@ "node": ">=6" } }, + "node_modules/bin-version/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bin-version/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/bin-version/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -5836,9 +6110,9 @@ } }, "node_modules/bin-version/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -5960,6 +6234,21 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -5968,9 +6257,9 @@ "license": "MIT" }, "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "dev": true, "license": "MIT" }, @@ -6025,13 +6314,14 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -6146,53 +6436,6 @@ "node": ">= 0.10" } }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", @@ -6439,116 +6682,38 @@ } } }, - "node_modules/c8/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/cacache": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/c8/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/c8/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/c8/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/c8/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/c8/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacache": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "balanced-match": "^1.0.0" } }, "node_modules/cacache/node_modules/chownr": { @@ -6565,6 +6730,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -6589,23 +6755,26 @@ "dev": true, "license": "ISC" }, - "node_modules/cacache/node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^7.0.3" + "brace-expansion": "^2.0.2" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/cacache/node_modules/tar": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz", - "integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", + "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -6696,9 +6865,9 @@ } }, "node_modules/cacheable-request/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -6790,9 +6959,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001766", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", - "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", "dev": true, "funding": [ { @@ -7072,74 +7241,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } + "license": "MIT" }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", @@ -7166,6 +7304,24 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -7218,46 +7374,6 @@ "readable-stream": "^2.3.5" } }, - "node_modules/cloneable-readable/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cloneable-readable/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/cloneable-readable/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/cloneable-readable/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -7411,6 +7527,21 @@ "node": ">= 10" } }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7418,6 +7549,22 @@ "dev": true, "license": "MIT" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", @@ -7570,9 +7717,9 @@ } }, "node_modules/conventional-changelog-angular": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.1.0.tgz", - "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.0.tgz", + "integrity": "sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==", "dev": true, "license": "ISC", "dependencies": { @@ -7583,9 +7730,9 @@ } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.1.0.tgz", - "integrity": "sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.0.tgz", + "integrity": "sha512-kYFx6gAyjSIMwNtASkI3ZE99U1fuVDJr0yTYgVy+I2QG46zNZfl2her+0+eoviG82c5WQvW1jMt1eOQTeJLodA==", "dev": true, "license": "ISC", "dependencies": { @@ -7596,12 +7743,13 @@ } }, "node_modules/conventional-commits-parser": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.1.tgz", - "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz", + "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==", "dev": true, "license": "MIT", "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", "meow": "^13.0.0" }, "bin": { @@ -7710,9 +7858,9 @@ } }, "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, "license": "MIT" }, @@ -7735,9 +7883,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", "peer": true, @@ -7840,21 +7988,36 @@ "node": ">= 10" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -8158,44 +8321,14 @@ "node": ">=4" } }, - "node_modules/decompress-tar/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/decompress-tar/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/decompress-tar/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/decompress-tar/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/decompress-tar/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "engines": { + "node": ">=0.10.0" } }, "node_modules/decompress-tar/node_modules/tar-stream": { @@ -8244,6 +8377,16 @@ "node": ">=4" } }, + "node_modules/decompress-tarbz2/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decompress-targz": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", @@ -8269,6 +8412,16 @@ "node": ">=4" } }, + "node_modules/decompress-targz/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decompress-unzip": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", @@ -8649,9 +8802,9 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -8835,6 +8988,16 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/download/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/download/node_modules/json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -8964,46 +9127,6 @@ "stream-shift": "^1.0.0" } }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/each-props": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", @@ -9065,9 +9188,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.279", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.279.tgz", - "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "dev": true, "license": "ISC" }, @@ -9088,16 +9211,16 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, "license": "MIT" }, @@ -9121,6 +9244,32 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -9162,6 +9311,28 @@ "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", @@ -9176,13 +9347,6 @@ "node": ">=6.9.0" } }, - "node_modules/enhanced-resolve/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/enhanced-resolve/node_modules/memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", @@ -9197,39 +9361,6 @@ "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/enhanced-resolve/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/enhanced-resolve/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/ent": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", @@ -9500,7 +9631,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9582,9 +9712,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -9598,15 +9728,20 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/eslint/node_modules/chalk": { @@ -9626,23 +9761,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -9650,104 +9768,20 @@ "dev": true, "license": "MIT" }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "p-locate": "^5.0.0" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" + "node": ">=0.10" } }, "node_modules/espree": { @@ -9895,97 +9929,42 @@ } }, "node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "license": "MIT", "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/execa/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "license": "ISC", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" + "node": ">=16.17" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/execa/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" + "node": ">=16" }, - "bin": { - "which": "bin/which" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/execa/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true, - "license": "ISC" - }, "node_modules/executable": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", @@ -10294,9 +10273,9 @@ } }, "node_modules/extract-zip/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -10395,6 +10374,24 @@ "pend": "~1.2.0" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -10663,6 +10660,23 @@ "semver": "bin/semver" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-versions": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", @@ -10758,9 +10772,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", "dev": true, "license": "ISC" }, @@ -10775,46 +10789,6 @@ "readable-stream": "^2.3.6" } }, - "node_modules/flush-write-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/flush-write-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/flush-write-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/flush-write-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -10991,57 +10965,17 @@ "readable-stream": "^2.0.0" } }, - "node_modules/from2/node_modules/isarray": { + "node_modules/fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, "license": "MIT" }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11094,46 +11028,6 @@ "readable-stream": "1 || 2" } }, - "node_modules/fs-write-stream-atomic/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/fs-write-stream-atomic/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -11191,9 +11085,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "dev": true, "license": "MIT", "engines": { @@ -11300,6 +11194,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -11331,7 +11226,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -11408,46 +11303,6 @@ "node": ">=0.10.0" } }, - "node_modules/glob-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/glob-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/glob-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/glob-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/glob-watcher": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", @@ -11467,30 +11322,6 @@ "node": ">= 0.10" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-agent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.2.0.tgz", @@ -11523,9 +11354,9 @@ } }, "node_modules/global-agent/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -11792,22 +11623,6 @@ "wrap-ansi": "^2.0.0" } }, - "node_modules/gulp-cli/node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "node_modules/gulp-cli/node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -11825,51 +11640,32 @@ "dev": true, "license": "ISC" }, - "node_modules/gulp-cli/node_modules/isarray": { + "node_modules/gulp-cli/node_modules/is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/gulp-cli/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", - "dev": true, - "license": "ISC" - }, - "node_modules/gulp-cli/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/gulp-cli/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/gulp-cli/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/gulp-cli/node_modules/strip-ansi": { @@ -11885,13 +11681,6 @@ "node": ">=0.10.0" } }, - "node_modules/gulp-cli/node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", - "dev": true, - "license": "ISC" - }, "node_modules/gulp-cli/node_modules/wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -12020,9 +11809,9 @@ } }, "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -12264,6 +12053,26 @@ "node": ">=0.10.0" } }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -12469,6 +12278,32 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/import-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -12813,16 +12648,16 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-glob": { @@ -12919,13 +12754,16 @@ } }, "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-plain-object": { @@ -12998,13 +12836,16 @@ } }, "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-typed-array": { @@ -13097,9 +12938,9 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, "license": "MIT" }, @@ -13729,6 +13570,19 @@ "node": ">=0.12.0" } }, + "node_modules/karma-rollup-preprocessor/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/karma-rollup-preprocessor/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -13803,6 +13657,22 @@ "graceful-fs": "^4.2.10" } }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/karma/node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -13830,17 +13700,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/karma/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/karma/node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -13891,6 +13750,13 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/karma/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/karma/node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -13965,17 +13831,17 @@ "node": ">=0.12.0" } }, - "node_modules/karma/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/karma/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/karma/node_modules/readdirp": { @@ -14019,6 +13885,24 @@ "node": ">=8.0" } }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -14095,46 +13979,6 @@ "node": ">= 0.6.3" } }, - "node_modules/lazystream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -14323,30 +14167,6 @@ "node": ">=18" } }, - "node_modules/lint-staged/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/lint-staged/node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -14360,19 +14180,6 @@ "node": ">=8" } }, - "node_modules/lint-staged/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -14383,19 +14190,6 @@ "node": ">=0.12.0" } }, - "node_modules/lint-staged/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -14410,49 +14204,17 @@ "node": ">=8.6" } }, - "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/lint-staged/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/lint-staged/node_modules/to-regex-range": { @@ -14486,39 +14248,6 @@ "node": ">=18.0.0" } }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/listr2/node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -14526,58 +14255,6 @@ "dev": true, "license": "MIT" }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -14646,6 +14323,22 @@ "json5": "lib/cli.js" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", @@ -14800,6 +14493,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -14850,26 +14559,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", @@ -14903,32 +14592,14 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -14937,24 +14608,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/log4js": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", @@ -15080,9 +14733,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -15125,19 +14778,6 @@ "node": ">= 0.6" } }, - "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -15253,6 +14893,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/matched/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -15427,46 +15080,6 @@ "readable-stream": "^2.0.1" } }, - "node_modules/memory-fs/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/memory-fs/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/memory-fs/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/memory-fs/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", @@ -15597,9 +15210,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -15688,19 +15301,16 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minimist": { @@ -15714,11 +15324,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -15888,33 +15498,10 @@ "node": ">=4.0.0" } }, - "node_modules/mississippi/node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/mississippi/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/mississippi/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -15922,51 +15509,18 @@ "once": "^1.3.1" } }, - "node_modules/mississippi/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/mississippi/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/mississippi/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/mixin-deep/node_modules/is-extendable": { @@ -16061,6 +15615,22 @@ "node": ">=6" } }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/mocha/node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -16088,6 +15658,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha/node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -16138,6 +15718,13 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/mocha/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/mocha/node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -16151,23 +15738,6 @@ "node": ">=8" } }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mocha/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -16187,7 +15757,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -16250,22 +15820,6 @@ "node": ">=0.12.0" } }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", @@ -16279,46 +15833,17 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/mocha/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/mocha/node_modules/readdirp": { @@ -16378,6 +15903,24 @@ "node": ">=8.0" } }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/mocha/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -16407,19 +15950,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -16488,62 +16018,6 @@ "node": ">= 0.10.0" } }, - "node_modules/multer/node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/multer/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/multer/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/multer/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/multer/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", @@ -16843,19 +16317,19 @@ } }, "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/node-gyp/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -16866,9 +16340,9 @@ } }, "node_modules/node-gyp/node_modules/tar": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz", - "integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", + "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -16952,50 +16426,10 @@ "isarray": "^1.0.0" } }, - "node_modules/node-libs-browser/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-libs-browser/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-libs-browser/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true, "license": "MIT" }, @@ -17015,6 +16449,36 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -17092,9 +16556,9 @@ } }, "node_modules/npm-install-checks/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -17114,75 +16578,68 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-packlist": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-9.0.0.tgz", - "integrity": "sha512-8qSayfmHJQTx3nJWYbbUmflpyarbLMBc6LCAjYsiGtXxDB68HaZpb8re6zeaLGxZzDuMdhsg70jryJe+RrItVQ==", + "node_modules/npm-package-arg": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", "dev": true, "license": "ISC", "dependencies": { - "ignore-walk": "^7.0.0" + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" }, "engines": { "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-pick-manifest": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", - "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", - "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^12.0.0", - "semver": "^7.3.5" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=10" } }, - "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/npm-packlist": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-9.0.0.tgz", + "integrity": "sha512-8qSayfmHJQTx3nJWYbbUmflpyarbLMBc6LCAjYsiGtXxDB68HaZpb8re6zeaLGxZzDuMdhsg70jryJe+RrItVQ==", "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" + "ignore-walk": "^7.0.0" }, "engines": { "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-pick-manifest/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "node_modules/npm-pick-manifest": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", + "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", "dev": true, "license": "ISC", "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" }, "engines": { "node": "^18.17.0 || >=20.5.0" } }, "node_modules/npm-pick-manifest/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -17192,16 +16649,6 @@ "node": ">=10" } }, - "node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", - "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/npm-registry-fetch": { "version": "18.0.2", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", @@ -17222,86 +16669,33 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", - "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^2.0.0" + "path-key": "^4.0.0" }, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm-run-path/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/number-is-nan": { @@ -17538,16 +16932,16 @@ } }, "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", "dependencies": { - "mimic-function": "^5.0.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -17558,67 +16952,27 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/ordered-read-streams/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ordered-read-streams/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/ordered-read-streams/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } }, - "node_modules/ordered-read-streams/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "readable-stream": "^2.0.1" } }, "node_modules/os-browserify": { @@ -17697,6 +17051,38 @@ "node": ">=4" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-map": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", @@ -17772,78 +17158,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/pacote/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/pacote/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/pacote/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/pacote/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pacote/node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/pacote/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", - "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -17863,46 +17177,6 @@ "readable-stream": "^2.1.5" } }, - "node_modules/parallel-transform/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/parallel-transform/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/parallel-transform/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/parallel-transform/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -18074,6 +17348,16 @@ "dev": true, "license": "MIT" }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -18215,13 +17499,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -18355,16 +17639,6 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/playwright": { "version": "1.58.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", @@ -18443,9 +17717,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -18668,9 +17942,9 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -18785,9 +18059,9 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -18948,13 +18222,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, "node_modules/read-pkg-up/node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -18972,19 +18239,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, "node_modules/read-pkg-up/node_modules/parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -19051,16 +18305,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-pkg-up/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/read-pkg-up/node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", @@ -19074,51 +18318,29 @@ "node": ">=0.10.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/readdir-glob": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", @@ -19129,6 +18351,16 @@ "minimatch": "^5.1.0" } }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/readdir-glob/node_modules/minimatch": { "version": "5.1.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", @@ -19157,46 +18389,6 @@ "node": ">=0.10" } }, - "node_modules/readdirp/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/readdirp/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/readdirp/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -19471,9 +18663,9 @@ } }, "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz", + "integrity": "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -19500,6 +18692,13 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true, + "license": "ISC" + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -19627,6 +18826,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -19719,53 +18934,6 @@ "node": ">= 0.8" } }, - "node_modules/ripemd160/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ripemd160/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/ripemd160/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -20077,6 +19245,22 @@ "sl": "bin/sl" } }, + "node_modules/saucelabs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/saucelabs/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -20089,6 +19273,13 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/saucelabs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/saucelabs/node_modules/form-data": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", @@ -20131,6 +19322,24 @@ "node": ">=8" } }, + "node_modules/saucelabs/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/saucelabs/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -20665,9 +19874,9 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.1.tgz", + "integrity": "sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -20729,32 +19938,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -20935,6 +20118,28 @@ "ws": "~8.18.3" } }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", @@ -21005,6 +20210,16 @@ "node": ">=0.10.0" } }, + "node_modules/sort-keys/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -21114,9 +20329,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, @@ -21216,6 +20431,19 @@ "node": ">=0.10.0" } }, + "node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -21283,63 +20511,23 @@ "engines": { "node": ">= 0.8" } - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-browserify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-browserify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, - "node_modules/stream-browserify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" } }, "node_modules/stream-each": { @@ -21374,46 +20562,6 @@ "xtend": "^4.0.0" } }, - "node_modules/stream-http/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-http/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-http/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", @@ -21527,15 +20675,22 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -21557,18 +20712,21 @@ } }, "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { @@ -21587,6 +20745,13 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -21598,26 +20763,32 @@ } }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi": { @@ -21777,7 +20948,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -21813,9 +20984,9 @@ "license": "ISC" }, "node_modules/tar-fs/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -21823,6 +20994,21 @@ "once": "^1.3.1" } }, + "node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tar-fs/node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -21841,13 +21027,14 @@ } }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", "dev": true, "license": "MIT", "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } @@ -21935,6 +21122,16 @@ "dev": true, "license": "ISC" }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/terser": { "version": "5.46.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", @@ -21979,9 +21176,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "peer": true, @@ -22163,24 +21360,48 @@ "license": "MIT" }, "node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", - "minimatch": "^9.0.4" + "minimatch": "^10.2.2" }, "engines": { "node": ">=18" } }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/test-exclude/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -22198,10 +21419,59 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/test-exclude/node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude/node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -22244,46 +21514,6 @@ "xtend": "~4.0.0" } }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", @@ -22351,50 +21581,18 @@ "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, "engines": { - "node": ">=12" + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/tinyrainbow": { @@ -22453,6 +21651,13 @@ "node": ">= 0.4" } }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -22911,9 +22116,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, @@ -23086,13 +22291,6 @@ "node": ">=0.10.0" } }, - "node_modules/unset-value/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -23314,6 +22512,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-name": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/value-or-function": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", @@ -23349,6 +22557,13 @@ "extsprintf": "^1.2.0" } }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, "node_modules/vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -23396,46 +22611,6 @@ "node": ">= 0.10" } }, - "node_modules/vinyl-fs/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vinyl-fs/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/vinyl-fs/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/vinyl-fs/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", @@ -23481,7 +22656,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -23551,31 +22725,6 @@ } } }, - "node_modules/vite/node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -23591,20 +22740,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vite/node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -23739,19 +22874,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -23932,6 +23054,20 @@ "node": ">=0.12.0" } }, + "node_modules/watchpack/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/watchpack/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -24023,17 +23159,6 @@ "node": ">=10.0.0" } }, - "node_modules/webdriverio/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/webdriverio/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -24050,19 +23175,6 @@ "node": ">=10" } }, - "node_modules/webdriverio/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/webdriverio/node_modules/serialize-error": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", @@ -24161,9 +23273,9 @@ } }, "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "peer": true, @@ -24261,6 +23373,13 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true, + "license": "ISC" + }, "node_modules/which-typed-array": { "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", @@ -24335,18 +23454,18 @@ "license": "Apache-2.0" }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -24371,6 +23490,29 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -24396,29 +23538,33 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrappy": { @@ -24429,9 +23575,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { @@ -24548,6 +23694,13 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -24584,6 +23737,19 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", @@ -24620,6 +23786,21 @@ "engines": { "node": ">= 10" } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } } } }