axios 1.16.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,10 @@
1
- /*! Axios v1.16.0 Copyright (c) 2026 Matt Zabriskie and contributors */
1
+ /*! Axios v1.17.0 Copyright (c) 2026 Matt Zabriskie and contributors */
2
2
  'use strict';
3
3
 
4
4
  var FormData$1 = require('form-data');
5
5
  var crypto = require('crypto');
6
6
  var url = require('url');
7
+ var HttpsProxyAgent = require('https-proxy-agent');
7
8
  var http = require('http');
8
9
  var https = require('https');
9
10
  var http2 = require('http2');
@@ -416,7 +417,10 @@ function merge(...objs) {
416
417
  if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
417
418
  return;
418
419
  }
419
- const targetKey = caseless && findKey(result, key) || key;
420
+
421
+ // findKey lowercases the key, so caseless lookup only applies to strings —
422
+ // symbol keys are identity-matched.
423
+ const targetKey = caseless && typeof key === 'string' && findKey(result, key) || key;
420
424
  // Read via own-prop only — a bare `result[targetKey]` walks the prototype
421
425
  // chain, so a polluted Object.prototype value could surface here and get
422
426
  // copied into the merged result.
@@ -432,7 +436,21 @@ function merge(...objs) {
432
436
  }
433
437
  };
434
438
  for (let i = 0, l = objs.length; i < l; i++) {
435
- objs[i] && forEach(objs[i], assignValue);
439
+ const source = objs[i];
440
+ if (!source || isBuffer(source)) {
441
+ continue;
442
+ }
443
+ forEach(source, assignValue);
444
+ if (typeof source !== 'object' || isArray(source)) {
445
+ continue;
446
+ }
447
+ const symbols = Object.getOwnPropertySymbols(source);
448
+ for (let j = 0; j < symbols.length; j++) {
449
+ const symbol = symbols[j];
450
+ if (propertyIsEnumerable.call(source, symbol)) {
451
+ assignValue(source[symbol], symbol);
452
+ }
453
+ }
436
454
  }
437
455
  return result;
438
456
  }
@@ -649,6 +667,9 @@ const toCamelCase = str => {
649
667
  const hasOwnProperty = (({
650
668
  hasOwnProperty
651
669
  }) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
670
+ const {
671
+ propertyIsEnumerable
672
+ } = Object.prototype;
652
673
 
653
674
  /**
654
675
  * Determine if a value is a RegExp object
@@ -737,10 +758,10 @@ function isSpecCompliantForm(thing) {
737
758
  * @returns {Object} The JSON-compatible object.
738
759
  */
739
760
  const toJSONObject = obj => {
740
- const stack = new Array(10);
741
- const visit = (source, i) => {
761
+ const visited = new WeakSet();
762
+ const visit = source => {
742
763
  if (isObject(source)) {
743
- if (stack.indexOf(source) >= 0) {
764
+ if (visited.has(source)) {
744
765
  return;
745
766
  }
746
767
 
@@ -749,19 +770,20 @@ const toJSONObject = obj => {
749
770
  return source;
750
771
  }
751
772
  if (!('toJSON' in source)) {
752
- stack[i] = source;
773
+ // add-on descent / delete-on-ascent: preserves path semantics, so DAG nodes serialise at every occurrence (see #7230).
774
+ visited.add(source);
753
775
  const target = isArray(source) ? [] : {};
754
776
  forEach(source, (value, key) => {
755
- const reducedValue = visit(value, i + 1);
777
+ const reducedValue = visit(value);
756
778
  !isUndefined(reducedValue) && (target[key] = reducedValue);
757
779
  });
758
- stack[i] = undefined;
780
+ visited.delete(source);
759
781
  return target;
760
782
  }
761
783
  }
762
784
  return source;
763
785
  };
764
- return visit(obj, 0);
786
+ return visit(obj);
765
787
  };
766
788
 
767
789
  /**
@@ -928,8 +950,6 @@ var parseHeaders = rawHeaders => {
928
950
  return parsed;
929
951
  };
930
952
 
931
- const $internals = Symbol('internals');
932
- const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
933
953
  function trimSPorHTAB(str) {
934
954
  let start = 0;
935
955
  let end = str.length;
@@ -949,12 +969,32 @@ function trimSPorHTAB(str) {
949
969
  }
950
970
  return start === 0 && end === str.length ? str : str.slice(start, end);
951
971
  }
972
+
973
+ // The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
974
+ // eslint-disable-next-line no-control-regex
975
+ const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp('[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+', 'g');
976
+ // eslint-disable-next-line no-control-regex
977
+ const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp('[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+', 'g');
978
+ function sanitizeValue(value, invalidChars) {
979
+ if (utils$1.isArray(value)) {
980
+ return value.map(item => sanitizeValue(item, invalidChars));
981
+ }
982
+ return trimSPorHTAB(String(value).replace(invalidChars, ''));
983
+ }
984
+ const sanitizeHeaderValue = value => sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
985
+ const sanitizeByteStringHeaderValue = value => sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
986
+ function toByteStringHeaderObject(headers) {
987
+ const byteStringHeaders = Object.create(null);
988
+ utils$1.forEach(headers.toJSON(), (value, header) => {
989
+ byteStringHeaders[header] = sanitizeByteStringHeaderValue(value);
990
+ });
991
+ return byteStringHeaders;
992
+ }
993
+
994
+ const $internals = Symbol('internals');
952
995
  function normalizeHeader(header) {
953
996
  return header && String(header).trim().toLowerCase();
954
997
  }
955
- function sanitizeHeaderValue(str) {
956
- return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, ''));
957
- }
958
998
  function normalizeValue(value) {
959
999
  if (value === false || value == null) {
960
1000
  return value;
@@ -1014,7 +1054,7 @@ class AxiosHeaders {
1014
1054
  function setHeader(_value, _header, _rewrite) {
1015
1055
  const lHeader = normalizeHeader(_header);
1016
1056
  if (!lHeader) {
1017
- throw new Error('header name must be a non-empty string');
1057
+ return;
1018
1058
  }
1019
1059
  const key = utils$1.findKey(self, lHeader);
1020
1060
  if (!key || self[key] === undefined || _rewrite === true || _rewrite === undefined && self[key] !== false) {
@@ -1032,7 +1072,7 @@ class AxiosHeaders {
1032
1072
  key;
1033
1073
  for (const entry of header) {
1034
1074
  if (!utils$1.isArray(entry)) {
1035
- throw TypeError('Object iterator must return a key-value pair');
1075
+ throw new TypeError('Object iterator must return a key-value pair');
1036
1076
  }
1037
1077
  obj[key = entry[0]] = (dest = obj[key]) ? utils$1.isArray(dest) ? [...dest, entry[1]] : [dest, entry[1]] : entry[1];
1038
1078
  }
@@ -1510,7 +1550,7 @@ function toFormData(obj, formData, options) {
1510
1550
  throw new AxiosError('Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED);
1511
1551
  }
1512
1552
  if (stack.indexOf(value) !== -1) {
1513
- throw Error('Circular reference detected in ' + path.join('.'));
1553
+ throw new Error('Circular reference detected in ' + path.join('.'));
1514
1554
  }
1515
1555
  stack.push(value);
1516
1556
  utils$1.forEach(value, function each(el, key) {
@@ -1692,7 +1732,8 @@ var transitionalDefaults = {
1692
1732
  silentJSONParsing: true,
1693
1733
  forcedJSONParsing: true,
1694
1734
  clarifyTimeoutError: false,
1695
- legacyInterceptorReqResOrdering: true
1735
+ legacyInterceptorReqResOrdering: true,
1736
+ advertiseZstdAcceptEncoding: false
1696
1737
  };
1697
1738
 
1698
1739
  var URLSearchParams = url.URLSearchParams;
@@ -1852,7 +1893,7 @@ function formDataToJSON(formData) {
1852
1893
  }
1853
1894
  return !isNumericKey;
1854
1895
  }
1855
- if (!target[name] || !utils$1.isObject(target[name])) {
1896
+ if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
1856
1897
  target[name] = [];
1857
1898
  }
1858
1899
  const result = buildPath(path, value, target[name], index);
@@ -2193,14 +2234,16 @@ function getEnv(key) {
2193
2234
  return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
2194
2235
  }
2195
2236
 
2196
- const VERSION = "1.16.0";
2237
+ const VERSION = "1.17.0";
2197
2238
 
2198
2239
  function parseProtocol(url) {
2199
2240
  const match = /^([-+\w]{1,25}):(?:\/\/)?/.exec(url);
2200
2241
  return match && match[1] || '';
2201
2242
  }
2202
2243
 
2203
- const DATA_URL_PATTERN = /^(?:([^;]+);)?(?:[^;]+;)?(base64|),([\s\S]*)$/;
2244
+ // RFC 2397: data:[<mediatype>][;base64],<data>
2245
+ // mediatype = type/subtype followed by optional ;name=value parameters
2246
+ const DATA_URL_PATTERN = /^([^,;]+\/[^,;]+)?((?:;[^,;=]+=[^,;]+)*)(;base64)?,([\s\S]*)$/;
2204
2247
 
2205
2248
  /**
2206
2249
  * Parse data uri to a Buffer or Blob
@@ -2224,10 +2267,20 @@ function fromDataURI(uri, asBlob, options) {
2224
2267
  if (!match) {
2225
2268
  throw new AxiosError('Invalid URL', AxiosError.ERR_INVALID_URL);
2226
2269
  }
2227
- const mime = match[1];
2228
- const isBase64 = match[2];
2229
- const body = match[3];
2230
- const buffer = Buffer.from(decodeURIComponent(body), isBase64 ? 'base64' : 'utf8');
2270
+ const type = match[1];
2271
+ const params = match[2];
2272
+ const encoding = match[3] ? 'base64' : 'utf8';
2273
+ const body = match[4];
2274
+
2275
+ // RFC 2397 section 3: default mediatype is text/plain;charset=US-ASCII
2276
+ // Bare `data:,` leaves mime undefined; Blob normalises that to "" per spec.
2277
+ let mime;
2278
+ if (type) {
2279
+ mime = params ? type + params : type;
2280
+ } else if (params) {
2281
+ mime = 'text/plain' + params;
2282
+ }
2283
+ const buffer = Buffer.from(decodeURIComponent(body), encoding);
2231
2284
  if (asBlob) {
2232
2285
  if (!_Blob) {
2233
2286
  throw new AxiosError('Blob is not supported', AxiosError.ERR_NOT_SUPPORT);
@@ -2420,10 +2473,10 @@ const formDataToStream = (form, headersHandler, options) => {
2420
2473
  boundary = tag + '-' + platform.generateString(size, BOUNDARY_ALPHABET)
2421
2474
  } = options || {};
2422
2475
  if (!utils$1.isFormData(form)) {
2423
- throw TypeError('FormData instance required');
2476
+ throw new TypeError('FormData instance required');
2424
2477
  }
2425
2478
  if (boundary.length < 1 || boundary.length > 70) {
2426
- throw Error('boundary must be 1-70 characters long');
2479
+ throw new Error('boundary must be 1-70 characters long');
2427
2480
  }
2428
2481
  const boundaryBytes = textEncoder.encode('--' + boundary + CRLF);
2429
2482
  const footerBytes = textEncoder.encode('--' + boundary + '--' + CRLF);
@@ -2473,6 +2526,84 @@ class ZlibHeaderTransformStream extends stream.Transform {
2473
2526
  }
2474
2527
  }
2475
2528
 
2529
+ class Http2Sessions {
2530
+ constructor() {
2531
+ this.sessions = Object.create(null);
2532
+ }
2533
+ getSession(authority, options) {
2534
+ options = Object.assign({
2535
+ sessionTimeout: 1000
2536
+ }, options);
2537
+ let authoritySessions = this.sessions[authority];
2538
+ if (authoritySessions) {
2539
+ let len = authoritySessions.length;
2540
+ for (let i = 0; i < len; i++) {
2541
+ const [sessionHandle, sessionOptions] = authoritySessions[i];
2542
+ if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
2543
+ return sessionHandle;
2544
+ }
2545
+ }
2546
+ }
2547
+ const session = http2.connect(authority, options);
2548
+ let removed;
2549
+ let timer;
2550
+ const removeSession = () => {
2551
+ if (removed) {
2552
+ return;
2553
+ }
2554
+ removed = true;
2555
+ if (timer) {
2556
+ clearTimeout(timer);
2557
+ timer = null;
2558
+ }
2559
+ let entries = authoritySessions,
2560
+ len = entries.length,
2561
+ i = len;
2562
+ while (i--) {
2563
+ if (entries[i][0] === session) {
2564
+ if (len === 1) {
2565
+ delete this.sessions[authority];
2566
+ } else {
2567
+ entries.splice(i, 1);
2568
+ }
2569
+ if (!session.closed) {
2570
+ session.close();
2571
+ }
2572
+ return;
2573
+ }
2574
+ }
2575
+ };
2576
+ const originalRequestFn = session.request;
2577
+ const {
2578
+ sessionTimeout
2579
+ } = options;
2580
+ if (sessionTimeout != null) {
2581
+ let streamsCount = 0;
2582
+ session.request = function () {
2583
+ const stream = originalRequestFn.apply(this, arguments);
2584
+ streamsCount++;
2585
+ if (timer) {
2586
+ clearTimeout(timer);
2587
+ timer = null;
2588
+ }
2589
+ stream.once('close', () => {
2590
+ if (! --streamsCount) {
2591
+ timer = setTimeout(() => {
2592
+ timer = null;
2593
+ removeSession();
2594
+ }, sessionTimeout);
2595
+ }
2596
+ });
2597
+ return stream;
2598
+ };
2599
+ }
2600
+ session.once('close', removeSession);
2601
+ let entry = [session, options];
2602
+ authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
2603
+ return session;
2604
+ }
2605
+ }
2606
+
2476
2607
  const callbackify = (fn, reducer) => {
2477
2608
  return utils$1.isAsyncFn(fn) ? function (...args) {
2478
2609
  const cb = args.pop();
@@ -2707,6 +2838,9 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
2707
2838
  let bytesNotified = 0;
2708
2839
  const _speedometer = speedometer(50, 250);
2709
2840
  return throttle(e => {
2841
+ if (!e || typeof e.loaded !== 'number') {
2842
+ return;
2843
+ }
2710
2844
  const rawLoaded = e.loaded;
2711
2845
  const total = e.lengthComputable ? e.total : undefined;
2712
2846
  const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
@@ -2835,7 +2969,14 @@ const brotliOptions = {
2835
2969
  flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2836
2970
  finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2837
2971
  };
2972
+ const zstdOptions = {
2973
+ flush: zlib.constants.ZSTD_e_flush,
2974
+ finishFlush: zlib.constants.ZSTD_e_flush
2975
+ };
2838
2976
  const isBrotliSupported = utils$1.isFunction(zlib.createBrotliDecompress);
2977
+ const isZstdSupported = utils$1.isFunction(zlib.createZstdDecompress);
2978
+ const ACCEPT_ENCODING = 'gzip, compress, deflate' + (isBrotliSupported ? ', br' : '');
2979
+ const ACCEPT_ENCODING_WITH_ZSTD = ACCEPT_ENCODING + (isZstdSupported ? ', zstd' : '');
2839
2980
  const {
2840
2981
  http: httpFollow,
2841
2982
  https: httpsFollow
@@ -2858,6 +2999,48 @@ function setFormDataHeaders$1(headers, formHeaders, policy) {
2858
2999
  // the request currently owning that socket across keep-alive reuse (issue #10780).
2859
3000
  const kAxiosSocketListener = Symbol('axios.http.socketListener');
2860
3001
  const kAxiosCurrentReq = Symbol('axios.http.currentReq');
3002
+
3003
+ // Tags HttpsProxyAgent instances installed by setProxy() so the redirect path
3004
+ // can strip them without clobbering a user-supplied agent that happens to be
3005
+ // an HttpsProxyAgent.
3006
+ const kAxiosInstalledTunnel = Symbol('axios.http.installedTunnel');
3007
+
3008
+ // Cache of CONNECT-tunneling agents keyed by proxy config so repeat requests
3009
+ // through the same proxy reuse a single agent (and its socket pool). The
3010
+ // keyspace is bounded by the set of distinct proxy configs the process uses,
3011
+ // so unbounded growth is not a concern in practice.
3012
+ const tunnelingAgentCache = new Map();
3013
+ const tunnelingAgentCacheUser = new WeakMap();
3014
+ function getTunnelingAgent(agentOptions, userHttpsAgent) {
3015
+ const key = agentOptions.protocol + '//' + agentOptions.hostname + ':' + (agentOptions.port || '') + '#' + (agentOptions.auth || '');
3016
+ const cache = userHttpsAgent ? tunnelingAgentCacheUser.get(userHttpsAgent) || tunnelingAgentCacheUser.set(userHttpsAgent, new Map()).get(userHttpsAgent) : tunnelingAgentCache;
3017
+ let agent = cache.get(key);
3018
+ if (agent) return agent;
3019
+ // Forward the user's TLS options (custom CA, rejectUnauthorized, client cert,
3020
+ // etc.) into the tunneling agent so they apply to the origin TLS upgrade
3021
+ // performed after CONNECT. Our proxy fields take precedence on conflict.
3022
+ const merged = userHttpsAgent && userHttpsAgent.options ? {
3023
+ ...userHttpsAgent.options,
3024
+ ...agentOptions
3025
+ } : agentOptions;
3026
+ agent = new HttpsProxyAgent(merged);
3027
+ if (userHttpsAgent && userHttpsAgent.options) {
3028
+ const originTLSOptions = {
3029
+ ...userHttpsAgent.options
3030
+ };
3031
+ const callback = agent.callback;
3032
+ agent.callback = function axiosTunnelingAgentCallback(req, opts) {
3033
+ // HttpsProxyAgent v5 reads callback opts for the post-CONNECT origin TLS upgrade.
3034
+ return callback.call(this, req, {
3035
+ ...originTLSOptions,
3036
+ ...opts
3037
+ });
3038
+ };
3039
+ }
3040
+ agent[kAxiosInstalledTunnel] = true;
3041
+ cache.set(key, agent);
3042
+ return agent;
3043
+ }
2861
3044
  const supportedProtocols = platform.protocols.map(protocol => {
2862
3045
  return protocol + ':';
2863
3046
  });
@@ -2866,7 +3049,7 @@ const supportedProtocols = platform.protocols.map(protocol => {
2866
3049
  // Decode before composing the `auth` option so credentials such as
2867
3050
  // `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
2868
3051
  // original value for malformed input so a bad encoding never throws.
2869
- const decodeURIComponentSafe = value => {
3052
+ const decodeURIComponentSafe$1 = value => {
2870
3053
  if (!utils$1.isString(value)) {
2871
3054
  return value;
2872
3055
  }
@@ -2880,84 +3063,11 @@ const flushOnFinish = (stream, [throttled, flush]) => {
2880
3063
  stream.on('end', flush).on('error', flush);
2881
3064
  return throttled;
2882
3065
  };
2883
- class Http2Sessions {
2884
- constructor() {
2885
- this.sessions = Object.create(null);
2886
- }
2887
- getSession(authority, options) {
2888
- options = Object.assign({
2889
- sessionTimeout: 1000
2890
- }, options);
2891
- let authoritySessions = this.sessions[authority];
2892
- if (authoritySessions) {
2893
- let len = authoritySessions.length;
2894
- for (let i = 0; i < len; i++) {
2895
- const [sessionHandle, sessionOptions] = authoritySessions[i];
2896
- if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
2897
- return sessionHandle;
2898
- }
2899
- }
2900
- }
2901
- const session = http2.connect(authority, options);
2902
- let removed;
2903
- const removeSession = () => {
2904
- if (removed) {
2905
- return;
2906
- }
2907
- removed = true;
2908
- let entries = authoritySessions,
2909
- len = entries.length,
2910
- i = len;
2911
- while (i--) {
2912
- if (entries[i][0] === session) {
2913
- if (len === 1) {
2914
- delete this.sessions[authority];
2915
- } else {
2916
- entries.splice(i, 1);
2917
- }
2918
- if (!session.closed) {
2919
- session.close();
2920
- }
2921
- return;
2922
- }
2923
- }
2924
- };
2925
- const originalRequestFn = session.request;
2926
- const {
2927
- sessionTimeout
2928
- } = options;
2929
- if (sessionTimeout != null) {
2930
- let timer;
2931
- let streamsCount = 0;
2932
- session.request = function () {
2933
- const stream = originalRequestFn.apply(this, arguments);
2934
- streamsCount++;
2935
- if (timer) {
2936
- clearTimeout(timer);
2937
- timer = null;
2938
- }
2939
- stream.once('close', () => {
2940
- if (! --streamsCount) {
2941
- timer = setTimeout(() => {
2942
- timer = null;
2943
- removeSession();
2944
- }, sessionTimeout);
2945
- }
2946
- });
2947
- return stream;
2948
- };
2949
- }
2950
- session.once('close', removeSession);
2951
- let entry = [session, options];
2952
- authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
2953
- return session;
2954
- }
2955
- }
2956
3066
  const http2Sessions = new Http2Sessions();
2957
3067
 
2958
3068
  /**
2959
- * If the proxy or config beforeRedirects functions are defined, call them with the options
2960
- * object.
3069
+ * If the proxy, auth, or config beforeRedirects functions are defined, call them
3070
+ * with the options object.
2961
3071
  *
2962
3072
  * @param {Object<string, any>} options - The options object that was passed to the request.
2963
3073
  *
@@ -2967,6 +3077,9 @@ function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
2967
3077
  if (options.beforeRedirects.proxy) {
2968
3078
  options.beforeRedirects.proxy(options);
2969
3079
  }
3080
+ if (options.beforeRedirects.auth) {
3081
+ options.beforeRedirects.auth(options);
3082
+ }
2970
3083
  if (options.beforeRedirects.config) {
2971
3084
  options.beforeRedirects.config(options, responseDetails, requestDetails);
2972
3085
  }
@@ -2981,7 +3094,7 @@ function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
2981
3094
  *
2982
3095
  * @returns {http.ClientRequestArgs}
2983
3096
  */
2984
- function setProxy(options, configProxy, location, isRedirect) {
3097
+ function setProxy(options, configProxy, location, isRedirect, configHttpsAgent) {
2985
3098
  let proxy = configProxy;
2986
3099
  if (!proxy && proxy !== false) {
2987
3100
  const proxyUrl = getProxyForUrl(location);
@@ -3002,6 +3115,13 @@ function setProxy(options, configProxy, location, isRedirect) {
3002
3115
  }
3003
3116
  }
3004
3117
  }
3118
+ // Strip any tunneling agent we installed for the previous hop so a redirect
3119
+ // that drops the proxy or crosses an HTTPS↔HTTP boundary doesn't reuse a
3120
+ // stale one. Match on our Symbol marker so a user-supplied HttpsProxyAgent
3121
+ // (which won't carry the marker) is left alone.
3122
+ if (isRedirect && options.agent && options.agent[kAxiosInstalledTunnel]) {
3123
+ options.agent = undefined;
3124
+ }
3005
3125
  if (proxy) {
3006
3126
  // Read proxy fields without traversing the prototype chain. URL instances expose
3007
3127
  // username/password/hostname/host/port/protocol via getters on URL.prototype (so
@@ -3034,37 +3154,84 @@ function setProxy(options, configProxy, location, isRedirect) {
3034
3154
  proxy
3035
3155
  });
3036
3156
  }
3037
- const base64 = Buffer.from(proxyAuth, 'utf8').toString('base64');
3038
- options.headers['Proxy-Authorization'] = 'Basic ' + base64;
3039
3157
  }
3158
+ const targetIsHttps = isHttps.test(options.protocol);
3159
+ if (targetIsHttps) {
3160
+ // CONNECT-tunneling path for HTTPS targets. Preserves end-to-end TLS to
3161
+ // the origin so the proxy cannot inspect the URL, headers, or body — the
3162
+ // behavior already promised by THREATMODEL.md (T-R9). HttpsProxyAgent
3163
+ // sends Proxy-Authorization on the CONNECT request only, never on the
3164
+ // wrapped TLS request, which is why we don't stamp it onto
3165
+ // options.headers here. If the user already supplied an HttpsProxyAgent,
3166
+ // they own tunneling end-to-end and we leave them alone; otherwise we
3167
+ // install our own tunneling agent and forward their TLS options (if any)
3168
+ // so a custom httpsAgent for cert pinning / rejectUnauthorized still
3169
+ // applies to the origin TLS upgrade.
3170
+ if (!(configHttpsAgent instanceof HttpsProxyAgent)) {
3171
+ const proxyHost = readProxyField('hostname') || readProxyField('host');
3172
+ const proxyPort = readProxyField('port');
3173
+ const rawProxyProtocol = readProxyField('protocol');
3174
+ const normalizedProtocol = rawProxyProtocol ? rawProxyProtocol.includes(':') ? rawProxyProtocol : `${rawProxyProtocol}:` : 'http:';
3175
+ // Bracket IPv6 literals for URL parsing; URL.hostname strips the
3176
+ // brackets again on read so the agent receives the raw form.
3177
+ const proxyHostForURL = proxyHost && proxyHost.includes(':') && !proxyHost.startsWith('[') ? `[${proxyHost}]` : proxyHost;
3178
+ const proxyURL = new URL(`${normalizedProtocol}//${proxyHostForURL}${proxyPort ? ':' + proxyPort : ''}`);
3179
+ const agentOptions = {
3180
+ protocol: proxyURL.protocol,
3181
+ hostname: proxyURL.hostname.replace(/^\[|\]$/g, ''),
3182
+ port: proxyURL.port,
3183
+ auth: proxyAuth && typeof proxyAuth === 'string' ? proxyAuth : undefined
3184
+ };
3185
+ if (proxyURL.protocol === 'https:') {
3186
+ agentOptions.ALPNProtocols = ['http/1.1'];
3187
+ }
3188
+ const tunnelingAgent = getTunnelingAgent(agentOptions, configHttpsAgent);
3189
+ // Set both: `options.agent` is consumed by the native https.request path
3190
+ // (config.maxRedirects === 0); `options.agents.https` is consumed by
3191
+ // follow-redirects, which ignores `options.agent` when `options.agents`
3192
+ // is present.
3193
+ options.agent = tunnelingAgent;
3194
+ if (options.agents) {
3195
+ options.agents.https = tunnelingAgent;
3196
+ }
3197
+ }
3198
+ } else {
3199
+ // Forward-proxy mode for plaintext HTTP targets. The request line carries
3200
+ // the absolute URL and the proxy sees everything — acceptable for plain
3201
+ // HTTP since the wire was already plaintext.
3202
+ if (proxyAuth) {
3203
+ const base64 = Buffer.from(proxyAuth, 'utf8').toString('base64');
3204
+ options.headers['Proxy-Authorization'] = 'Basic ' + base64;
3205
+ }
3040
3206
 
3041
- // Preserve a user-supplied Host header (case-insensitive) so callers can override
3042
- // the value forwarded to the proxy; otherwise default to the request URL's host.
3043
- let hasUserHostHeader = false;
3044
- for (const name of Object.keys(options.headers)) {
3045
- if (name.toLowerCase() === 'host') {
3046
- hasUserHostHeader = true;
3047
- break;
3207
+ // Preserve a user-supplied Host header (case-insensitive) so callers can override
3208
+ // the value forwarded to the proxy; otherwise default to the request URL's host.
3209
+ let hasUserHostHeader = false;
3210
+ for (const name of Object.keys(options.headers)) {
3211
+ if (name.toLowerCase() === 'host') {
3212
+ hasUserHostHeader = true;
3213
+ break;
3214
+ }
3215
+ }
3216
+ if (!hasUserHostHeader) {
3217
+ options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
3218
+ }
3219
+ const proxyHost = readProxyField('hostname') || readProxyField('host');
3220
+ options.hostname = proxyHost;
3221
+ // Replace 'host' since options is not a URL object
3222
+ options.host = proxyHost;
3223
+ options.port = readProxyField('port');
3224
+ options.path = location;
3225
+ const proxyProtocol = readProxyField('protocol');
3226
+ if (proxyProtocol) {
3227
+ options.protocol = proxyProtocol.includes(':') ? proxyProtocol : `${proxyProtocol}:`;
3048
3228
  }
3049
- }
3050
- if (!hasUserHostHeader) {
3051
- options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
3052
- }
3053
- const proxyHost = readProxyField('hostname') || readProxyField('host');
3054
- options.hostname = proxyHost;
3055
- // Replace 'host' since options is not a URL object
3056
- options.host = proxyHost;
3057
- options.port = readProxyField('port');
3058
- options.path = location;
3059
- const proxyProtocol = readProxyField('protocol');
3060
- if (proxyProtocol) {
3061
- options.protocol = proxyProtocol.includes(':') ? proxyProtocol : `${proxyProtocol}:`;
3062
3229
  }
3063
3230
  }
3064
3231
  options.beforeRedirects.proxy = function beforeRedirect(redirectOptions) {
3065
3232
  // Configure proxy for redirected request, passing the original config proxy to apply
3066
3233
  // the exact same logic as if the redirected request was performed by axios directly.
3067
- setProxy(redirectOptions, configProxy, redirectOptions.href, true);
3234
+ setProxy(redirectOptions, configProxy, redirectOptions.href, true, configHttpsAgent);
3068
3235
  };
3069
3236
  }
3070
3237
  const isHttpAdapterSupported = typeof process !== 'undefined' && utils$1.kindOf(process) === 'process';
@@ -3148,6 +3315,7 @@ const http2Transport = {
3148
3315
  var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3149
3316
  return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
3150
3317
  const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
3318
+ const transitional = own('transitional') || transitionalDefaults;
3151
3319
  let data = own('data');
3152
3320
  let lookup = own('lookup');
3153
3321
  let family = own('family');
@@ -3187,7 +3355,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3187
3355
  try {
3188
3356
  abortEmitter.emit('abort', !reason || reason.type ? new CanceledError(null, config, req) : reason);
3189
3357
  } catch (err) {
3190
- console.warn('emit error', err);
3358
+ // ignore emit errors
3191
3359
  }
3192
3360
  }
3193
3361
  function clearConnectPhaseTimer() {
@@ -3198,7 +3366,6 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3198
3366
  }
3199
3367
  function createTimeoutError() {
3200
3368
  let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
3201
- const transitional = config.transitional || transitionalDefaults;
3202
3369
  if (config.timeoutErrorMessage) {
3203
3370
  timeoutErrorMessage = config.timeoutErrorMessage;
3204
3371
  }
@@ -3371,9 +3538,9 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3371
3538
  const password = configAuth.password || '';
3372
3539
  auth = username + ':' + password;
3373
3540
  }
3374
- if (!auth && parsed.username) {
3375
- const urlUsername = decodeURIComponentSafe(parsed.username);
3376
- const urlPassword = decodeURIComponentSafe(parsed.password);
3541
+ if (!auth && (parsed.username || parsed.password)) {
3542
+ const urlUsername = decodeURIComponentSafe$1(parsed.username);
3543
+ const urlPassword = decodeURIComponentSafe$1(parsed.password);
3377
3544
  auth = urlUsername + ':' + urlPassword;
3378
3545
  }
3379
3546
  auth && headers.delete('authorization');
@@ -3387,14 +3554,14 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3387
3554
  customErr.exists = true;
3388
3555
  return reject(customErr);
3389
3556
  }
3390
- headers.set('Accept-Encoding', 'gzip, compress, deflate' + (isBrotliSupported ? ', br' : ''), false);
3557
+ headers.set('Accept-Encoding', utils$1.hasOwnProp(transitional, 'advertiseZstdAcceptEncoding') && transitional.advertiseZstdAcceptEncoding === true ? ACCEPT_ENCODING_WITH_ZSTD : ACCEPT_ENCODING, false);
3391
3558
 
3392
3559
  // Null-prototype to block prototype pollution gadgets on properties read
3393
3560
  // directly by Node's http.request (e.g. insecureHTTPParser, lookup).
3394
3561
  const options = Object.assign(Object.create(null), {
3395
3562
  path: path$1,
3396
3563
  method: method,
3397
- headers: headers.toJSON(),
3564
+ headers: toByteStringHeaderObject(headers),
3398
3565
  agents: {
3399
3566
  http: config.httpAgent,
3400
3567
  https: config.httpsAgent
@@ -3409,28 +3576,34 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3409
3576
 
3410
3577
  // cacheable-lookup integration hotfix
3411
3578
  !utils$1.isUndefined(lookup) && (options.lookup = lookup);
3412
- if (config.socketPath) {
3413
- if (typeof config.socketPath !== 'string') {
3579
+ const socketPath = own('socketPath');
3580
+ if (socketPath) {
3581
+ if (typeof socketPath !== 'string') {
3414
3582
  return reject(new AxiosError('socketPath must be a string', AxiosError.ERR_BAD_OPTION_VALUE, config));
3415
3583
  }
3416
- if (config.allowedSocketPaths != null) {
3417
- const allowed = Array.isArray(config.allowedSocketPaths) ? config.allowedSocketPaths : [config.allowedSocketPaths];
3418
- const resolvedSocket = path.resolve(config.socketPath);
3584
+ const allowedSocketPaths = own('allowedSocketPaths');
3585
+ if (allowedSocketPaths != null) {
3586
+ const allowed = Array.isArray(allowedSocketPaths) ? allowedSocketPaths : [allowedSocketPaths];
3587
+ const resolvedSocket = path.resolve(socketPath);
3419
3588
  const isAllowed = allowed.some(entry => typeof entry === 'string' && path.resolve(entry) === resolvedSocket);
3420
3589
  if (!isAllowed) {
3421
- return reject(new AxiosError(`socketPath "${config.socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config));
3590
+ return reject(new AxiosError(`socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config));
3422
3591
  }
3423
3592
  }
3424
- options.socketPath = config.socketPath;
3593
+ options.socketPath = socketPath;
3425
3594
  } else {
3426
3595
  options.hostname = parsed.hostname.startsWith('[') ? parsed.hostname.slice(1, -1) : parsed.hostname;
3427
3596
  options.port = parsed.port;
3428
- setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
3597
+ setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path, false, config.httpsAgent);
3429
3598
  }
3430
3599
  let transport;
3431
3600
  let isNativeTransport = false;
3432
3601
  const isHttpsRequest = isHttps.test(options.protocol);
3433
- options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
3602
+ // Don't clobber a CONNECT-tunneling agent installed by setProxy() for an
3603
+ // HTTPS target.
3604
+ if (options.agent == null) {
3605
+ options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
3606
+ }
3434
3607
  if (isHttp2) {
3435
3608
  transport = http2Transport;
3436
3609
  } else {
@@ -3448,6 +3621,23 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3448
3621
  if (configBeforeRedirect) {
3449
3622
  options.beforeRedirects.config = configBeforeRedirect;
3450
3623
  }
3624
+ if (auth) {
3625
+ // Restore HTTP Basic credentials on same-origin redirects only.
3626
+ // follow-redirects >= 1.15.8 strips Authorization on every redirect (see #6929);
3627
+ // cross-origin stripping is the documented mitigation for T-R2 in THREATMODEL.md
3628
+ // and is preserved by deliberately not restoring on origin change.
3629
+ const requestOrigin = parsed.origin;
3630
+ const authToRestore = auth;
3631
+ options.beforeRedirects.auth = function beforeRedirectAuth(redirectOptions) {
3632
+ try {
3633
+ if (new URL(redirectOptions.href).origin === requestOrigin) {
3634
+ redirectOptions.auth = authToRestore;
3635
+ }
3636
+ } catch (e) {
3637
+ // ignore malformed URL: leaving auth stripped is fail-safe
3638
+ }
3639
+ };
3640
+ }
3451
3641
  transport = isHttpsRequest ? httpsFollow : httpFollow;
3452
3642
  }
3453
3643
  }
@@ -3516,6 +3706,13 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
3516
3706
  streams.push(zlib.createBrotliDecompress(brotliOptions));
3517
3707
  delete res.headers['content-encoding'];
3518
3708
  }
3709
+ break;
3710
+ case 'zstd':
3711
+ if (isZstdSupported) {
3712
+ streams.push(zlib.createZstdDecompress(zstdOptions));
3713
+ delete res.headers['content-encoding'];
3714
+ }
3715
+ break;
3519
3716
  }
3520
3717
  }
3521
3718
  responseStream = streams.length > 1 ? stream.pipeline(streams, utils$1.noop) : streams[0];
@@ -3927,8 +4124,8 @@ function setFormDataHeaders(headers, formHeaders, policy) {
3927
4124
  *
3928
4125
  * @returns {string} UTF-8 bytes as a Latin-1 string
3929
4126
  */
3930
- const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
3931
- var resolveConfig = config => {
4127
+ const encodeUTF8$1 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
4128
+ function resolveConfig(config) {
3932
4129
  const newConfig = mergeConfig({}, config);
3933
4130
 
3934
4131
  // Read only own properties to prevent prototype pollution gadgets
@@ -3944,15 +4141,15 @@ var resolveConfig = config => {
3944
4141
  const allowAbsoluteUrls = own('allowAbsoluteUrls');
3945
4142
  const url = own('url');
3946
4143
  newConfig.headers = headers = AxiosHeaders.from(headers);
3947
- newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls), config.params, config.paramsSerializer);
4144
+ newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls), own('params'), own('paramsSerializer'));
3948
4145
 
3949
4146
  // HTTP basic authentication
3950
4147
  if (auth) {
3951
- headers.set('Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : '')));
4148
+ headers.set('Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8$1(auth.password) : '')));
3952
4149
  }
3953
4150
  if (utils$1.isFormData(data)) {
3954
- if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {
3955
- headers.setContentType(undefined); // browser handles it
4151
+ if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv || utils$1.isReactNative(data)) {
4152
+ headers.setContentType(undefined); // browser/web worker/RN handles it
3956
4153
  } else if (utils$1.isFunction(data.getHeaders)) {
3957
4154
  // Node.js FormData (like form-data package)
3958
4155
  setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
@@ -3980,7 +4177,7 @@ var resolveConfig = config => {
3980
4177
  }
3981
4178
  }
3982
4179
  return newConfig;
3983
- };
4180
+ }
3984
4181
 
3985
4182
  const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
3986
4183
  var xhrAdapter = isXHRAdapterSupported && function (config) {
@@ -4102,7 +4299,7 @@ var xhrAdapter = isXHRAdapterSupported && function (config) {
4102
4299
 
4103
4300
  // Add headers to the request
4104
4301
  if ('setRequestHeader' in request) {
4105
- utils$1.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {
4302
+ utils$1.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) {
4106
4303
  request.setRequestHeader(key, val);
4107
4304
  });
4108
4305
  }
@@ -4158,41 +4355,41 @@ var xhrAdapter = isXHRAdapterSupported && function (config) {
4158
4355
  };
4159
4356
 
4160
4357
  const composeSignals = (signals, timeout) => {
4161
- const {
4162
- length
4163
- } = signals = signals ? signals.filter(Boolean) : [];
4164
- if (timeout || length) {
4165
- let controller = new AbortController();
4166
- let aborted;
4167
- const onabort = function (reason) {
4168
- if (!aborted) {
4169
- aborted = true;
4170
- unsubscribe();
4171
- const err = reason instanceof Error ? reason : this.reason;
4172
- controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));
4173
- }
4174
- };
4175
- let timer = timeout && setTimeout(() => {
4176
- timer = null;
4177
- onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
4178
- }, timeout);
4179
- const unsubscribe = () => {
4180
- if (signals) {
4181
- timer && clearTimeout(timer);
4182
- timer = null;
4183
- signals.forEach(signal => {
4184
- signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort);
4185
- });
4186
- signals = null;
4187
- }
4188
- };
4189
- signals.forEach(signal => signal.addEventListener('abort', onabort));
4190
- const {
4191
- signal
4192
- } = controller;
4193
- signal.unsubscribe = () => utils$1.asap(unsubscribe);
4194
- return signal;
4358
+ signals = signals ? signals.filter(Boolean) : [];
4359
+ if (!timeout && !signals.length) {
4360
+ return;
4195
4361
  }
4362
+ const controller = new AbortController();
4363
+ let aborted = false;
4364
+ const onabort = function (reason) {
4365
+ if (!aborted) {
4366
+ aborted = true;
4367
+ unsubscribe();
4368
+ const err = reason instanceof Error ? reason : this.reason;
4369
+ controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));
4370
+ }
4371
+ };
4372
+ let timer = timeout && setTimeout(() => {
4373
+ timer = null;
4374
+ onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
4375
+ }, timeout);
4376
+ const unsubscribe = () => {
4377
+ if (!signals) {
4378
+ return;
4379
+ }
4380
+ timer && clearTimeout(timer);
4381
+ timer = null;
4382
+ signals.forEach(signal => {
4383
+ signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort);
4384
+ });
4385
+ signals = null;
4386
+ };
4387
+ signals.forEach(signal => signal.addEventListener('abort', onabort));
4388
+ const {
4389
+ signal
4390
+ } = controller;
4391
+ signal.unsubscribe = () => utils$1.asap(unsubscribe);
4392
+ return signal;
4196
4393
  };
4197
4394
 
4198
4395
  const streamChunk = function* (chunk, chunkSize) {
@@ -4281,6 +4478,31 @@ const DEFAULT_CHUNK_SIZE = 64 * 1024;
4281
4478
  const {
4282
4479
  isFunction
4283
4480
  } = utils$1;
4481
+
4482
+ /**
4483
+ * Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
4484
+ * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
4485
+ *
4486
+ * @param {string} str The string to encode
4487
+ *
4488
+ * @returns {string} UTF-8 bytes as a Latin-1 string
4489
+ */
4490
+ const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
4491
+
4492
+ // Node's WHATWG URL parser returns `username` and `password` percent-encoded.
4493
+ // Decode before composing the `auth` option so credentials such as
4494
+ // `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
4495
+ // original value for malformed input so a bad encoding never throws.
4496
+ const decodeURIComponentSafe = value => {
4497
+ if (!utils$1.isString(value)) {
4498
+ return value;
4499
+ }
4500
+ try {
4501
+ return decodeURIComponent(value);
4502
+ } catch (error) {
4503
+ return value;
4504
+ }
4505
+ };
4284
4506
  const test = (fn, ...args) => {
4285
4507
  try {
4286
4508
  return !!fn(...args);
@@ -4288,9 +4510,16 @@ const test = (fn, ...args) => {
4288
4510
  return false;
4289
4511
  }
4290
4512
  };
4513
+ const maybeWithAuthCredentials = url => {
4514
+ const protocolIndex = url.indexOf('://');
4515
+ let urlToCheck = url;
4516
+ if (protocolIndex !== -1) {
4517
+ urlToCheck = urlToCheck.slice(protocolIndex + 3);
4518
+ }
4519
+ return urlToCheck.includes('@') || urlToCheck.includes(':');
4520
+ };
4291
4521
  const factory = env => {
4292
- var _utils$global;
4293
- const globalObject = (_utils$global = utils$1.global) !== null && _utils$global !== void 0 ? _utils$global : globalThis;
4522
+ const globalObject = utils$1.global !== undefined && utils$1.global !== null ? utils$1.global : globalThis;
4294
4523
  const {
4295
4524
  ReadableStream,
4296
4525
  TextEncoder
@@ -4392,6 +4621,7 @@ const factory = env => {
4392
4621
  } = resolveConfig(config);
4393
4622
  const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
4394
4623
  const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
4624
+ const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
4395
4625
  let _fetch = envFetch || fetch;
4396
4626
  responseType = responseType ? (responseType + '').toLowerCase() : 'text';
4397
4627
  let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
@@ -4401,6 +4631,38 @@ const factory = env => {
4401
4631
  });
4402
4632
  let requestContentLength;
4403
4633
  try {
4634
+ // HTTP basic authentication
4635
+ let auth = undefined;
4636
+ const configAuth = own('auth');
4637
+ if (configAuth) {
4638
+ const username = configAuth.username || '';
4639
+ const password = configAuth.password || '';
4640
+ auth = {
4641
+ username,
4642
+ password
4643
+ };
4644
+ }
4645
+ if (maybeWithAuthCredentials(url)) {
4646
+ const parsedURL = new URL(url, platform.origin);
4647
+ if (!auth && (parsedURL.username || parsedURL.password)) {
4648
+ const urlUsername = decodeURIComponentSafe(parsedURL.username);
4649
+ const urlPassword = decodeURIComponentSafe(parsedURL.password);
4650
+ auth = {
4651
+ username: urlUsername,
4652
+ password: urlPassword
4653
+ };
4654
+ }
4655
+ if (parsedURL.username || parsedURL.password) {
4656
+ parsedURL.username = '';
4657
+ parsedURL.password = '';
4658
+ url = parsedURL.href;
4659
+ }
4660
+ }
4661
+ if (auth) {
4662
+ headers.delete('authorization');
4663
+ headers.set('Authorization', 'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || ''))));
4664
+ }
4665
+
4404
4666
  // Enforce maxContentLength for data: URLs up-front so we never materialize
4405
4667
  // an oversized payload. The HTTP adapter applies the same check (see http.js
4406
4668
  // "if (protocol === 'data:')" branch).
@@ -4459,7 +4721,7 @@ const factory = env => {
4459
4721
  ...fetchOptions,
4460
4722
  signal: composedSignal,
4461
4723
  method: method.toUpperCase(),
4462
- headers: headers.normalize().toJSON(),
4724
+ headers: toByteStringHeaderObject(headers.normalize()),
4463
4725
  body: data,
4464
4726
  duplex: 'half',
4465
4727
  credentials: isCredentialsSupported ? withCredentials : undefined
@@ -4917,7 +5179,8 @@ class Axios {
4917
5179
  silentJSONParsing: validators.transitional(validators.boolean),
4918
5180
  forcedJSONParsing: validators.transitional(validators.boolean),
4919
5181
  clarifyTimeoutError: validators.transitional(validators.boolean),
4920
- legacyInterceptorReqResOrdering: validators.transitional(validators.boolean)
5182
+ legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
5183
+ advertiseZstdAcceptEncoding: validators.transitional(validators.boolean)
4921
5184
  }, false);
4922
5185
  }
4923
5186
  if (paramsSerializer != null) {