...**/!(*.map|*.min.js)Size
Gzip
Dependencies
Publish
Install
@@ -66,7 +66,9 @@ | |||
| 66 | ...targets: Array<AxiosHeaders | axios.RawAxiosHeaders | string | undefined | null> | 66 | ...targets: Array<AxiosHeaders | axios.RawAxiosHeaders | string | undefined | null> |
| 67 | ): AxiosHeaders; | 67 | ): AxiosHeaders; |
| 68 | 68 | ||
| 69 | toJSON(asStrings?: boolean): axios.RawAxiosHeaders; | 69 | toJSON(asStrings: true): Record<string, string>; |
| 70 | toJSON(asStrings?: false): Record<string, string | string[]>; | ||
| 71 | toJSON(asStrings?: boolean): Record<string, string | string[]>; | ||
| 70 | 72 | ||
| 71 | static from(thing?: AxiosHeaders | axios.RawAxiosHeaders | string): AxiosHeaders; | 73 | static from(thing?: AxiosHeaders | axios.RawAxiosHeaders | string): AxiosHeaders; |
| 72 | 74 | ||
@@ -162,7 +164,9 @@ | |||
| 162 | static readonly ETIMEDOUT = 'ETIMEDOUT'; | 164 | static readonly ETIMEDOUT = 'ETIMEDOUT'; |
| 163 | } | 165 | } |
| 164 | 166 | ||
| 165 | declare class CanceledError<T> extends AxiosError<T> {} | 167 | declare class CanceledError<T> extends AxiosError<T> { |
| 168 | readonly name: 'CanceledError'; | ||
| 169 | } | ||
| 166 | 170 | ||
| 167 | declare class Axios { | 171 | declare class Axios { |
| 168 | constructor(config?: axios.AxiosRequestConfig); | 172 | constructor(config?: axios.AxiosRequestConfig); |
@@ -392,6 +396,7 @@ | |||
| 392 | forcedJSONParsing?: boolean; | 396 | forcedJSONParsing?: boolean; |
| 393 | clarifyTimeoutError?: boolean; | 397 | clarifyTimeoutError?: boolean; |
| 394 | legacyInterceptorReqResOrdering?: boolean; | 398 | legacyInterceptorReqResOrdering?: boolean; |
| 399 | advertiseZstdAcceptEncoding?: boolean; | ||
| 395 | } | 400 | } |
| 396 | 401 | ||
| 397 | interface GenericAbortSignal { | 402 | interface GenericAbortSignal { |
@@ -691,7 +696,7 @@ | |||
| 691 | CanceledError: typeof CanceledError; | 696 | CanceledError: typeof CanceledError; |
| 692 | HttpStatusCode: typeof HttpStatusCode; | 697 | HttpStatusCode: typeof HttpStatusCode; |
| 693 | readonly VERSION: string; | 698 | readonly VERSION: string; |
| 694 | isCancel(value: any): value is Cancel; | 699 | isCancel<T = any>(value: any): value is CanceledError<T>; |
| 695 | all<T>(values: Array<T | Promise<T>>): Promise<T[]>; | 700 | all<T>(values: Array<T | Promise<T>>): Promise<T[]>; |
| 696 | spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R; | 701 | spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R; |
| 697 | isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>; | 702 | isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>; |
@@ -101,6 +101,7 @@ | |||
| 101 | forcedJSONParsing: validators.transitional(validators.boolean), | 101 | forcedJSONParsing: validators.transitional(validators.boolean), |
| 102 | clarifyTimeoutError: validators.transitional(validators.boolean), | 102 | clarifyTimeoutError: validators.transitional(validators.boolean), |
| 103 | legacyInterceptorReqResOrdering: validators.transitional(validators.boolean), | 103 | legacyInterceptorReqResOrdering: validators.transitional(validators.boolean), |
| 104 | advertiseZstdAcceptEncoding: validators.transitional(validators.boolean), | ||
| 104 | }, | 105 | }, |
| 105 | false | 106 | false |
| 106 | ); | 107 | ); |
@@ -89,7 +89,7 @@ | |||
| 89 | const lHeader = normalizeHeader(_header); | 89 | const lHeader = normalizeHeader(_header); |
| 90 | 90 | ||
| 91 | if (!lHeader) { | 91 | if (!lHeader) { |
| 92 | throw new Error('header name must be a non-empty string'); | 92 | return; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | const key = utils.findKey(self, lHeader); | 95 | const key = utils.findKey(self, lHeader); |
@@ -117,7 +117,7 @@ | |||
| 117 | key; | 117 | key; |
| 118 | for (const entry of header) { | 118 | for (const entry of header) { |
| 119 | if (!utils.isArray(entry)) { | 119 | if (!utils.isArray(entry)) { |
| 120 | throw TypeError('Object iterator must return a key-value pair'); | 120 | throw new TypeError('Object iterator must return a key-value pair'); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | obj[(key = entry[0])] = (dest = obj[key]) | 123 | obj[(key = entry[0])] = (dest = obj[key]) |
@@ -1,7 +1,7 @@ | |||
| 1 | 'use strict'; | 1 | 'use strict'; |
| 2 | 2 | ||
| 3 | import utils from '../utils.js'; | 3 | import utils from '../utils.js'; |
| 4 | import AxiosURLSearchParams from '../helpers/AxiosURLSearchParams.js'; | 4 | import AxiosURLSearchParams from './AxiosURLSearchParams.js'; |
| 5 | 5 | ||
| 6 | /** | 6 | /** |
| 7 | * It replaces URL-encoded forms of `:`, `$`, `,`, and spaces with | 7 | * It replaces URL-encoded forms of `:`, `$`, `,`, and spaces with |
@@ -19,6 +19,35 @@ | |||
| 19 | 19 | ||
| 20 | const { isFunction } = utils; | 20 | const { isFunction } = utils; |
| 21 | 21 | ||
| 22 | /** | ||
| 23 | * Encode a UTF-8 string to a Latin-1 byte string for use with btoa(). | ||
| 24 | * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern. | ||
| 25 | * | ||
| 26 | * @param {string} str The string to encode | ||
| 27 | * | ||
| 28 | * @returns {string} UTF-8 bytes as a Latin-1 string | ||
| 29 | */ | ||
| 30 | const encodeUTF8 = (str) => | ||
| 31 | encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => | ||
| 32 | String.fromCharCode(parseInt(hex, 16)) | ||
| 33 | ); | ||
| 34 | |||
| 35 | // Node's WHATWG URL parser returns `username` and `password` percent-encoded. | ||
| 36 | // Decode before composing the `auth` option so credentials such as | ||
| 37 | // `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the | ||
| 38 | // original value for malformed input so a bad encoding never throws. | ||
| 39 | const decodeURIComponentSafe = (value) => { | ||
| 40 | if (!utils.isString(value)) { | ||
| 41 | return value; | ||
| 42 | } | ||
| 43 | |||
| 44 | try { | ||
| 45 | return decodeURIComponent(value); | ||
| 46 | } catch (error) { | ||
| 47 | return value; | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 22 | const test = (fn, ...args) => { | 51 | const test = (fn, ...args) => { |
| 23 | try { | 52 | try { |
| 24 | return !!fn(...args); | 53 | return !!fn(...args); |
@@ -27,6 +56,15 @@ | |||
| 27 | } | 56 | } |
| 28 | }; | 57 | }; |
| 29 | 58 | ||
| 59 | const maybeWithAuthCredentials = (url) => { | ||
| 60 | const protocolIndex = url.indexOf('://'); | ||
| 61 | let urlToCheck = url; | ||
| 62 | if (protocolIndex !== -1) { | ||
| 63 | urlToCheck = urlToCheck.slice(protocolIndex + 3); | ||
| 64 | } | ||
| 65 | return urlToCheck.includes('@') || urlToCheck.includes(':'); | ||
| 66 | }; | ||
| 67 | |||
| 30 | const factory = (env) => { | 68 | const factory = (env) => { |
| 31 | const globalObject = | 69 | const globalObject = |
| 32 | utils.global !== undefined && utils.global !== null | 70 | utils.global !== undefined && utils.global !== null |
@@ -174,6 +212,7 @@ | |||
| 174 | 212 | ||
| 175 | const hasMaxContentLength = utils.isNumber(maxContentLength) && maxContentLength > -1; | 213 | const hasMaxContentLength = utils.isNumber(maxContentLength) && maxContentLength > -1; |
| 176 | const hasMaxBodyLength = utils.isNumber(maxBodyLength) && maxBodyLength > -1; | 214 | const hasMaxBodyLength = utils.isNumber(maxBodyLength) && maxBodyLength > -1; |
| 215 | const own = (key) => (utils.hasOwnProp(config, key) ? config[key] : undefined); | ||
| 177 | 216 | ||
| 178 | let _fetch = envFetch || fetch; | 217 | let _fetch = envFetch || fetch; |
| 179 | 218 | ||
@@ -196,6 +235,46 @@ | |||
| 196 | let requestContentLength; | 235 | let requestContentLength; |
| 197 | 236 | ||
| 198 | try { | 237 | try { |
| 238 | // HTTP basic authentication | ||
| 239 | let auth = undefined; | ||
| 240 | const configAuth = own('auth'); | ||
| 241 | |||
| 242 | if (configAuth) { | ||
| 243 | const username = configAuth.username || ''; | ||
| 244 | const password = configAuth.password || ''; | ||
| 245 | auth = { | ||
| 246 | username, | ||
| 247 | password | ||
| 248 | }; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (maybeWithAuthCredentials(url)) { | ||
| 252 | const parsedURL = new URL(url, platform.origin); | ||
| 253 | |||
| 254 | if (!auth && (parsedURL.username || parsedURL.password)) { | ||
| 255 | const urlUsername = decodeURIComponentSafe(parsedURL.username); | ||
| 256 | const urlPassword = decodeURIComponentSafe(parsedURL.password); | ||
| 257 | auth = { | ||
| 258 | username: urlUsername, | ||
| 259 | password: urlPassword | ||
| 260 | }; | ||
| 261 | } | ||
| 262 | |||
| 263 | if (parsedURL.username || parsedURL.password) { | ||
| 264 | parsedURL.username = ''; | ||
| 265 | parsedURL.password = ''; | ||
| 266 | url = parsedURL.href; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | if (auth) { | ||
| 271 | headers.delete('authorization'); | ||
| 272 | headers.set( | ||
| 273 | 'Authorization', | ||
| 274 | 'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || ''))) | ||
| 275 | ); | ||
| 276 | } | ||
| 277 | |||
| 199 | // Enforce maxContentLength for data: URLs up-front so we never materialize | 278 | // Enforce maxContentLength for data: URLs up-front so we never materialize |
| 200 | // an oversized payload. The HTTP adapter applies the same check (see http.js | 279 | // an oversized payload. The HTTP adapter applies the same check (see http.js |
| 201 | // "if (protocol === 'data:')" branch). | 280 | // "if (protocol === 'data:')" branch). |
@@ -73,11 +73,11 @@ | |||
| 73 | } = options || {}; | 73 | } = options || {}; |
| 74 | 74 | ||
| 75 | if (!utils.isFormData(form)) { | 75 | if (!utils.isFormData(form)) { |
| 76 | throw TypeError('FormData instance required'); | 76 | throw new TypeError('FormData instance required'); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | if (boundary.length < 1 || boundary.length > 70) { | 79 | if (boundary.length < 1 || boundary.length > 70) { |
| 80 | throw Error('boundary must be 1-70 characters long'); | 80 | throw new Error('boundary must be 1-70 characters long'); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | const boundaryBytes = textEncoder.encode('--' + boundary + CRLF); | 83 | const boundaryBytes = textEncoder.encode('--' + boundary + CRLF); |
@@ -35,7 +35,7 @@ | |||
| 35 | String.fromCharCode(parseInt(hex, 16)) | 35 | String.fromCharCode(parseInt(hex, 16)) |
| 36 | ); | 36 | ); |
| 37 | 37 | ||
| 38 | export default (config) => { | 38 | function resolveConfig(config) { |
| 39 | const newConfig = mergeConfig({}, config); | 39 | const newConfig = mergeConfig({}, config); |
| 40 | 40 | ||
| 41 | // Read only own properties to prevent prototype pollution gadgets | 41 | // Read only own properties to prevent prototype pollution gadgets |
@@ -56,8 +56,8 @@ | |||
| 56 | 56 | ||
| 57 | newConfig.url = buildURL( | 57 | newConfig.url = buildURL( |
| 58 | buildFullPath(baseURL, url, allowAbsoluteUrls), | 58 | buildFullPath(baseURL, url, allowAbsoluteUrls), |
| 59 | config.params, | ||
| 60 | config.paramsSerializer | 59 | own('params'), |
| 60 | own('paramsSerializer') | ||
| 61 | ); | 61 | ); |
| 62 | 62 | ||
| 63 | // HTTP basic authentication | 63 | // HTTP basic authentication |
@@ -70,8 +70,12 @@ | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | if (utils.isFormData(data)) { | 72 | if (utils.isFormData(data)) { |
| 73 | if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) { | ||
| 74 | headers.setContentType(undefined); // browser handles it | 73 | if ( |
| 74 | platform.hasStandardBrowserEnv || | ||
| 75 | platform.hasStandardBrowserWebWorkerEnv || | ||
| 76 | utils.isReactNative(data) | ||
| 77 | ) { | ||
| 78 | headers.setContentType(undefined); // browser/web worker/RN handles it | ||
| 75 | } else if (utils.isFunction(data.getHeaders)) { | 79 | } else if (utils.isFunction(data.getHeaders)) { |
| 76 | // Node.js FormData (like form-data package) | 80 | // Node.js FormData (like form-data package) |
| 77 | setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy')); | 81 | setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy')); |
@@ -103,4 +107,6 @@ | |||
| 103 | } | 107 | } |
| 104 | 108 | ||
| 105 | return newConfig; | 109 | return newConfig; |
| 106 | }; | 110 | } |
| 111 | |||
| 112 | export default resolveConfig; | ||
@@ -219,7 +219,7 @@ | |||
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | if (stack.indexOf(value) !== -1) { | 221 | if (stack.indexOf(value) !== -1) { |
| 222 | throw Error('Circular reference detected in ' + path.join('.')); | 222 | throw new Error('Circular reference detected in ' + path.join('.')); |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | stack.push(value); | 225 | stack.push(value); |
@@ -412,7 +412,9 @@ | |||
| 412 | return; | 412 | return; |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | const targetKey = (caseless && findKey(result, key)) || key; | 415 | // findKey lowercases the key, so caseless lookup only applies to strings — |
| 416 | // symbol keys are identity-matched. | ||
| 417 | const targetKey = (caseless && typeof key === 'string' && findKey(result, key)) || key; | ||
| 416 | // Read via own-prop only — a bare `result[targetKey]` walks the prototype | 418 | // Read via own-prop only — a bare `result[targetKey]` walks the prototype |
| 417 | // chain, so a polluted Object.prototype value could surface here and get | 419 | // chain, so a polluted Object.prototype value could surface here and get |
| 418 | // copied into the merged result. | 420 | // copied into the merged result. |
@@ -429,7 +431,24 @@ | |||
| 429 | }; | 431 | }; |
| 430 | 432 | ||
| 431 | for (let i = 0, l = objs.length; i < l; i++) { | 433 | for (let i = 0, l = objs.length; i < l; i++) { |
| 432 | objs[i] && forEach(objs[i], assignValue); | 434 | const source = objs[i]; |
| 435 | if (!source || isBuffer(source)) { | ||
| 436 | continue; | ||
| 437 | } | ||
| 438 | |||
| 439 | forEach(source, assignValue); | ||
| 440 | |||
| 441 | if (typeof source !== 'object' || isArray(source)) { | ||
| 442 | continue; | ||
| 443 | } | ||
| 444 | |||
| 445 | const symbols = Object.getOwnPropertySymbols(source); | ||
| 446 | for (let j = 0; j < symbols.length; j++) { | ||
| 447 | const symbol = symbols[j]; | ||
| 448 | if (propertyIsEnumerable.call(source, symbol)) { | ||
| 449 | assignValue(source[symbol], symbol); | ||
| 450 | } | ||
| 451 | } | ||
| 433 | } | 452 | } |
| 434 | return result; | 453 | return result; |
| 435 | } | 454 | } |
@@ -658,6 +677,8 @@ | |||
| 658 | hasOwnProperty.call(obj, prop) | 677 | hasOwnProperty.call(obj, prop) |
| 659 | )(Object.prototype); | 678 | )(Object.prototype); |
| 660 | 679 | ||
| 680 | const { propertyIsEnumerable } = Object.prototype; | ||
| 681 | |||
| 661 | /** | 682 | /** |
| 662 | * Determine if a value is a RegExp object | 683 | * Determine if a value is a RegExp object |
| 663 | * | 684 | * |
@@ -1,6 +1,6 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "axios", | 2 | "name": "axios", |
| 3 | "version": "1.16.1", | 3 | "version": "1.17.0", |
| 4 | "description": "Promise based HTTP client for the browser and node.js", | 4 | "description": "Promise based HTTP client for the browser and node.js", |
| 5 | "main": "./dist/node/axios.cjs", | 5 | "main": "./dist/node/axios.cjs", |
| 6 | "module": "./index.js", | 6 | "module": "./index.js", |
@@ -86,8 +86,8 @@ | |||
| 86 | "Justin Beckwith (https://github.com/JustinBeckwith)", | 86 | "Justin Beckwith (https://github.com/JustinBeckwith)", |
| 87 | "Martti Laine (https://github.com/codeclown)", | 87 | "Martti Laine (https://github.com/codeclown)", |
| 88 | "Xianming Zhong (https://github.com/chinesedfan)", | 88 | "Xianming Zhong (https://github.com/chinesedfan)", |
| 89 | "Shaan Majid (https://github.com/shaanmajid)", | ||
| 89 | "Willian Agostini (https://github.com/WillianAgostini)", | 90 | "Willian Agostini (https://github.com/WillianAgostini)", |
| 90 | "Shaan Majid (https://github.com/shaanmajid)", | ||
| 91 | "Remco Haszing (https://github.com/remcohaszing)", | 91 | "Remco Haszing (https://github.com/remcohaszing)", |
| 92 | "Rikki Gibson (https://github.com/RikkiGibson)" | 92 | "Rikki Gibson (https://github.com/RikkiGibson)" |
| 93 | ], | 93 | ], |
@@ -97,6 +97,22 @@ | |||
| 97 | "url": "https://github.com/axios/axios/issues" | 97 | "url": "https://github.com/axios/axios/issues" |
| 98 | }, | 98 | }, |
| 99 | "homepage": "https://axios-http.com", | 99 | "homepage": "https://axios-http.com", |
| 100 | "files": [ | ||
| 101 | "index.js", | ||
| 102 | "index.d.ts", | ||
| 103 | "index.d.cts", | ||
| 104 | "CHANGELOG.md", | ||
| 105 | "MIGRATION_GUIDE.md", | ||
| 106 | "lib/", | ||
| 107 | "dist/axios.js", | ||
| 108 | "dist/axios.min.js", | ||
| 109 | "dist/axios.min.js.map", | ||
| 110 | "dist/esm/axios.js", | ||
| 111 | "dist/esm/axios.min.js", | ||
| 112 | "dist/esm/axios.min.js.map", | ||
| 113 | "dist/browser/axios.cjs", | ||
| 114 | "dist/node/axios.cjs" | ||
| 115 | ], | ||
| 100 | "scripts": { | 116 | "scripts": { |
| 101 | "build": "gulp clear && cross-env NODE_ENV=production rollup -c -m", | 117 | "build": "gulp clear && cross-env NODE_ENV=production rollup -c -m", |
| 102 | "version": "npm run build && git add package.json", | 118 | "version": "npm run build && git add package.json", |
@@ -128,9 +144,9 @@ | |||
| 128 | }, | 144 | }, |
| 129 | "devDependencies": { | 145 | "devDependencies": { |
| 130 | "@babel/core": "^7.29.0", | 146 | "@babel/core": "^7.29.0", |
| 131 | "@babel/preset-env": "^7.29.2", | ||
| 132 | "@commitlint/cli": "^20.5.0", | ||
| 133 | "@commitlint/config-conventional": "^20.5.0", | 147 | "@babel/preset-env": "^7.29.5", |
| 148 | "@commitlint/cli": "^21.0.1", | ||
| 149 | "@commitlint/config-conventional": "^21.0.1", | ||
| 134 | "@eslint/js": "^10.0.1", | 150 | "@eslint/js": "^10.0.1", |
| 135 | "@rollup/plugin-alias": "^6.0.0", | 151 | "@rollup/plugin-alias": "^6.0.0", |
| 136 | "@rollup/plugin-babel": "^7.0.0", | 152 | "@rollup/plugin-babel": "^7.0.0", |
@@ -138,34 +154,34 @@ | |||
| 138 | "@rollup/plugin-json": "^6.1.0", | 154 | "@rollup/plugin-json": "^6.1.0", |
| 139 | "@rollup/plugin-node-resolve": "^16.0.3", | 155 | "@rollup/plugin-node-resolve": "^16.0.3", |
| 140 | "@rollup/plugin-terser": "^1.0.0", | 156 | "@rollup/plugin-terser": "^1.0.0", |
| 141 | "@vitest/browser": "^4.1.5", | ||
| 142 | "@vitest/browser-playwright": "^4.1.5", | 157 | "@vitest/browser": "^4.1.7", |
| 158 | "@vitest/browser-playwright": "^4.1.7", | ||
| 143 | "abortcontroller-polyfill": "^1.7.8", | 159 | "abortcontroller-polyfill": "^1.7.8", |
| 144 | "acorn": "^8.16.0", | 160 | "acorn": "^8.16.0", |
| 145 | "body-parser": "^2.2.2", | 161 | "body-parser": "^2.2.2", |
| 146 | "chalk": "^5.6.2", | 162 | "chalk": "^5.6.2", |
| 147 | "cross-env": "^10.1.0", | 163 | "cross-env": "^10.1.0", |
| 148 | "dev-null": "^0.1.1", | 164 | "dev-null": "^0.1.1", |
| 149 | "eslint": "^10.2.1", | 165 | "eslint": "^10.4.0", |
| 150 | "express": "^5.2.1", | 166 | "express": "^5.2.1", |
| 151 | "formdata-node": "^6.0.3", | 167 | "formdata-node": "^6.0.3", |
| 152 | "formidable": "^3.5.4", | 168 | "formidable": "^3.5.4", |
| 153 | "fs-extra": "^11.3.4", | 169 | "fs-extra": "^11.3.4", |
| 154 | "get-stream": "^9.0.1", | 170 | "get-stream": "^9.0.1", |
| 155 | "globals": "^17.5.0", | 171 | "globals": "^17.6.0", |
| 156 | "gulp": "^5.0.1", | 172 | "gulp": "^5.0.1", |
| 157 | "husky": "^9.1.7", | 173 | "husky": "^9.1.7", |
| 158 | "lint-staged": "^16.4.0", | 174 | "lint-staged": "^17.0.5", |
| 159 | "minimist": "^1.2.8", | 175 | "minimist": "^1.2.8", |
| 160 | "multer": "^2.1.1", | 176 | "multer": "^2.1.1", |
| 161 | "playwright": "^1.59.1", | 177 | "playwright": "^1.60.0", |
| 162 | "prettier": "^3.8.3", | 178 | "prettier": "^3.8.3", |
| 163 | "rollup": "^4.60.2", | 179 | "rollup": "^4.60.4", |
| 164 | "rollup-plugin-bundle-size": "^1.0.3", | 180 | "rollup-plugin-bundle-size": "^1.0.3", |
| 165 | "selfsigned": "^5.5.0", | 181 | "selfsigned": "^5.5.0", |
| 166 | "stream-throttle": "^0.1.3", | 182 | "stream-throttle": "^0.1.3", |
| 167 | "typescript": "^5.9.3", | 183 | "typescript": "^5.9.3", |
| 168 | "vitest": "^4.1.5" | 184 | "vitest": "^4.1.7" |
| 169 | }, | 185 | }, |
| 170 | "commitlint": { | 186 | "commitlint": { |
| 171 | "rules": { | 187 | "rules": { |
@@ -1,5 +1,47 @@ | |||
| 1 | # Changelog | 1 | # Changelog |
| 2 | 2 | ||
| 3 | ## v1.16.1 — May 13, 2026 | ||
| 4 | |||
| 5 | This release ships a defence-in-depth fix for prototype pollution in `formDataToJSON`, hardens proxy and CI workflows, restores Webpack 4 compatibility for the fetch adapter, and includes several small bug fixes and maintenance improvements. | ||
| 6 | |||
| 7 | ## 🔒 Security Fixes | ||
| 8 | |||
| 9 | * **Prototype Pollution Defence-in-Depth:** Hardened `formDataToJSON` against already-polluted `Object.prototype` by walking own properties only, so attacker-controlled keys inherited from a poisoned prototype cannot propagate through deserialization. (__#7413__) | ||
| 10 | * **Proxy Cleartext Leak:** Fixed an issue where HTTPS request data could be transmitted in cleartext to an HTTP proxy under certain configurations. (__#10858__) | ||
| 11 | * **CI Cache Removal:** Removed all GitHub Actions caches as a defence-in-depth measure against cache poisoning vectors in the build pipeline. (__#10882__) | ||
| 12 | |||
| 13 | ## 🐛 Bug Fixes | ||
| 14 | |||
| 15 | * **Data URI Parsing:** Updated the `fromDataURI` regex to match RFC 2397 more strictly, fixing edge cases in `data:` URL handling. (__#10829__) | ||
| 16 | * **Unicode Headers:** Preserved Unicode header values when running through request interceptors, so non-ASCII header content is no longer corrupted before dispatch. (__#10850__) | ||
| 17 | * **XHR Upload Progress:** Guarded against malformed `ProgressEvent` payloads emitted by some environments during XHR upload, preventing crashes when `loaded` / `total` are missing or invalid. (__#10868__) | ||
| 18 | * **Webpack 4 Fetch Adapter:** Fixed an "unexpected token" error caused by syntax in the fetch adapter that Webpack 4 could not parse, restoring compatibility for legacy bundler users. (__#10864__) | ||
| 19 | * **Type Definitions:** Made `parseReviver` `context.source` optional in the type definitions to align with the ES2023 specification. (__#10837__) | ||
| 20 | * **URL Object Support Reverted:** Reverted the change that allowed passing a `URL` object as `config.url` (originally __#10866__) due to regressions; this support will be reintroduced in a later release once the underlying issues are addressed. (__#10874__) | ||
| 21 | |||
| 22 | ## 🔧 Maintenance & Chores | ||
| 23 | |||
| 24 | * **Cycle Detection Refactor:** Replaced the array-based cycle tracker in `toJSONObject` with a `WeakSet`, improving performance and memory behaviour on large nested structures. (__#10832__) | ||
| 25 | * **composeSignals Cleanup:** Refactored `composeSignals` to use a clearer early-return structure, simplifying the cancellation/abort composition path. (__#10844__) | ||
| 26 | * **AI Readiness & Repo Docs:** Added `AGENTS.md` and related contributor-guide updates for both human and AI agents, plus post-release documentation improvements. (__#10835__, __#10841__) | ||
| 27 | * **Docs Improvements:** Clarified the GET request example, fixed the interceptor `eject` example to reference the correct instance, and corrected the Buzzoid sponsor description in the README. (__#10836__, __#10853__, __#10856__) | ||
| 28 | * **Sponsorship Tooling:** Fixed empty sponsor arrays in the sponsor processing script, added the ability to inject additional sponsors, updated the sponsorship link, and added a Twicsy advertisement entry. (__#10843__, __#10859__, __#10869__) | ||
| 29 | * **Dependencies:** Bumped `@commitlint/cli` from 20.5.0 to 20.5.2. (__#10846__) | ||
| 30 | |||
| 31 | ## 🌟 New Contributors | ||
| 32 | |||
| 33 | We are thrilled to welcome our new contributors. Thank you for helping improve axios: | ||
| 34 | |||
| 35 | * __@hpinmetaverse__ (__#10836__) | ||
| 36 | * __@tommyhgunz14__ (__#7413__) | ||
| 37 | * __@abhu85__ (__#10829__) | ||
| 38 | * __@divyanshuraj1095__ (__#10853__) | ||
| 39 | * __@sagodi97__ (__#10856__) | ||
| 40 | * __@rkdfx__ (__#10868__) | ||
| 41 | * __@Liuwei1125__ (__#10866__) | ||
| 42 | |||
| 43 | [Full Changelog](https://github.com/axios/axios/compare/v1.16.0...v1.16.1) | ||
| 44 | |||
| 3 | ## v1.16.0 — May 2, 2026 | 45 | ## v1.16.0 — May 2, 2026 |
| 4 | 46 | ||
| 5 | This release adds support for the QUERY HTTP method and a new `ECONNREFUSED` error constant, lands a substantial wave of HTTP, fetch, and XHR adapter bug fixes around redirects, aborts, headers, and timeouts, and welcomes 23 new contributors. | 47 | This release adds support for the QUERY HTTP method and a new `ECONNREFUSED` error constant, lands a substantial wave of HTTP, fetch, and XHR adapter bug fixes around redirects, aborts, headers, and timeouts, and welcomes 23 new contributors. |
@@ -47,7 +47,9 @@ | |||
| 47 | ...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null> | 47 | ...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null> |
| 48 | ): AxiosHeaders; | 48 | ): AxiosHeaders; |
| 49 | 49 | ||
| 50 | toJSON(asStrings?: boolean): RawAxiosHeaders; | 50 | toJSON(asStrings: true): Record<string, string>; |
| 51 | toJSON(asStrings?: false): Record<string, string | string[]>; | ||
| 52 | toJSON(asStrings?: boolean): Record<string, string | string[]>; | ||
| 51 | 53 | ||
| 52 | static from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders; | 54 | static from(thing?: AxiosHeaders | RawAxiosHeaders | string): AxiosHeaders; |
| 53 | 55 | ||
@@ -281,6 +283,7 @@ | |||
| 281 | forcedJSONParsing?: boolean; | 283 | forcedJSONParsing?: boolean; |
| 282 | clarifyTimeoutError?: boolean; | 284 | clarifyTimeoutError?: boolean; |
| 283 | legacyInterceptorReqResOrdering?: boolean; | 285 | legacyInterceptorReqResOrdering?: boolean; |
| 286 | advertiseZstdAcceptEncoding?: boolean; | ||
| 284 | } | 287 | } |
| 285 | 288 | ||
| 286 | export interface GenericAbortSignal { | 289 | export interface GenericAbortSignal { |
@@ -0,0 +1,119 @@ | |
| 1 | 'use strict'; |
| 2 | |
| 3 | // Node-only: relies on the built-in `http2` module. Browser/react-native |
| 4 | // builds replace `lib/adapters/http.js` (the sole importer) with `lib/helpers/null.js` |
| 5 | // via the `browser` package.json field, so this module is never reached in |
| 6 | // those environments. Do not import it from any browser-reachable code path. |
| 7 | |
| 8 | import http2 from 'http2'; |
| 9 | import util from 'util'; |
| 10 | |
| 11 | class Http2Sessions { |
| 12 | constructor() { |
| 13 | this.sessions = Object.create(null); |
| 14 | } |
| 15 | |
| 16 | getSession(authority, options) { |
| 17 | options = Object.assign( |
| 18 | { |
| 19 | sessionTimeout: 1000, |
| 20 | }, |
| 21 | options |
| 22 | ); |
| 23 | |
| 24 | let authoritySessions = this.sessions[authority]; |
| 25 | |
| 26 | if (authoritySessions) { |
| 27 | let len = authoritySessions.length; |
| 28 | |
| 29 | for (let i = 0; i < len; i++) { |
| 30 | const [sessionHandle, sessionOptions] = authoritySessions[i]; |
| 31 | if ( |
| 32 | !sessionHandle.destroyed && |
| 33 | !sessionHandle.closed && |
| 34 | util.isDeepStrictEqual(sessionOptions, options) |
| 35 | ) { |
| 36 | return sessionHandle; |
| 37 | } |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | const session = http2.connect(authority, options); |
| 42 | |
| 43 | let removed; |
| 44 | let timer; |
| 45 | |
| 46 | const removeSession = () => { |
| 47 | if (removed) { |
| 48 | return; |
| 49 | } |
| 50 | |
| 51 | removed = true; |
| 52 | |
| 53 | if (timer) { |
| 54 | clearTimeout(timer); |
| 55 | timer = null; |
| 56 | } |
| 57 | |
| 58 | let entries = authoritySessions, |
| 59 | len = entries.length, |
| 60 | i = len; |
| 61 | |
| 62 | while (i--) { |
| 63 | if (entries[i][0] === session) { |
| 64 | if (len === 1) { |
| 65 | delete this.sessions[authority]; |
| 66 | } else { |
| 67 | entries.splice(i, 1); |
| 68 | } |
| 69 | if (!session.closed) { |
| 70 | session.close(); |
| 71 | } |
| 72 | return; |
| 73 | } |
| 74 | } |
| 75 | }; |
| 76 | |
| 77 | const originalRequestFn = session.request; |
| 78 | |
| 79 | const { sessionTimeout } = options; |
| 80 | |
| 81 | if (sessionTimeout != null) { |
| 82 | let streamsCount = 0; |
| 83 | |
| 84 | session.request = function () { |
| 85 | const stream = originalRequestFn.apply(this, arguments); |
| 86 | |
| 87 | streamsCount++; |
| 88 | |
| 89 | if (timer) { |
| 90 | clearTimeout(timer); |
| 91 | timer = null; |
| 92 | } |
| 93 | |
| 94 | stream.once('close', () => { |
| 95 | if (!--streamsCount) { |
| 96 | timer = setTimeout(() => { |
| 97 | timer = null; |
| 98 | removeSession(); |
| 99 | }, sessionTimeout); |
| 100 | } |
| 101 | }); |
| 102 | |
| 103 | return stream; |
| 104 | }; |
| 105 | } |
| 106 | |
| 107 | session.once('close', removeSession); |
| 108 | |
| 109 | let entry = [session, options]; |
| 110 | |
| 111 | authoritySessions |
| 112 | ? authoritySessions.push(entry) |
| 113 | : (authoritySessions = this.sessions[authority] = [entry]); |
| 114 | |
| 115 | return session; |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | export default Http2Sessions; |
Publish
Install
Size
Gzip
Dependencies