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,4 +1,4 @@
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
  /**
@@ -424,7 +424,9 @@ function merge(...objs) {
424
424
  return;
425
425
  }
426
426
 
427
- const targetKey = (caseless && findKey(result, key)) || key;
427
+ // findKey lowercases the key, so caseless lookup only applies to strings —
428
+ // symbol keys are identity-matched.
429
+ const targetKey = (caseless && typeof key === 'string' && findKey(result, key)) || key;
428
430
  // Read via own-prop only — a bare `result[targetKey]` walks the prototype
429
431
  // chain, so a polluted Object.prototype value could surface here and get
430
432
  // copied into the merged result.
@@ -441,7 +443,24 @@ function merge(...objs) {
441
443
  };
442
444
 
443
445
  for (let i = 0, l = objs.length; i < l; i++) {
444
- objs[i] && forEach(objs[i], assignValue);
446
+ const source = objs[i];
447
+ if (!source || isBuffer(source)) {
448
+ continue;
449
+ }
450
+
451
+ forEach(source, assignValue);
452
+
453
+ if (typeof source !== 'object' || isArray(source)) {
454
+ continue;
455
+ }
456
+
457
+ const symbols = Object.getOwnPropertySymbols(source);
458
+ for (let j = 0; j < symbols.length; j++) {
459
+ const symbol = symbols[j];
460
+ if (propertyIsEnumerable.call(source, symbol)) {
461
+ assignValue(source[symbol], symbol);
462
+ }
463
+ }
445
464
  }
446
465
  return result;
447
466
  }
@@ -670,6 +689,8 @@ const hasOwnProperty = (
670
689
  hasOwnProperty.call(obj, prop)
671
690
  )(Object.prototype);
672
691
 
692
+ const { propertyIsEnumerable } = Object.prototype;
693
+
673
694
  /**
674
695
  * Determine if a value is a RegExp object
675
696
  *
@@ -775,11 +796,11 @@ function isSpecCompliantForm(thing) {
775
796
  * @returns {Object} The JSON-compatible object.
776
797
  */
777
798
  const toJSONObject = (obj) => {
778
- const stack = new Array(10);
799
+ const visited = new WeakSet();
779
800
 
780
- const visit = (source, i) => {
801
+ const visit = (source) => {
781
802
  if (isObject(source)) {
782
- if (stack.indexOf(source) >= 0) {
803
+ if (visited.has(source)) {
783
804
  return;
784
805
  }
785
806
 
@@ -789,15 +810,16 @@ const toJSONObject = (obj) => {
789
810
  }
790
811
 
791
812
  if (!('toJSON' in source)) {
792
- stack[i] = source;
813
+ // add-on descent / delete-on-ascent: preserves path semantics, so DAG nodes serialise at every occurrence (see #7230).
814
+ visited.add(source);
793
815
  const target = isArray(source) ? [] : {};
794
816
 
795
817
  forEach(source, (value, key) => {
796
- const reducedValue = visit(value, i + 1);
818
+ const reducedValue = visit(value);
797
819
  !isUndefined(reducedValue) && (target[key] = reducedValue);
798
820
  });
799
821
 
800
- stack[i] = undefined;
822
+ visited.delete(source);
801
823
 
802
824
  return target;
803
825
  }
@@ -806,7 +828,7 @@ const toJSONObject = (obj) => {
806
828
  return source;
807
829
  };
808
830
 
809
- return visit(obj, 0);
831
+ return visit(obj);
810
832
  };
811
833
 
812
834
  /**
@@ -1008,10 +1030,6 @@ var parseHeaders = (rawHeaders) => {
1008
1030
  return parsed;
1009
1031
  };
1010
1032
 
1011
- const $internals = Symbol('internals');
1012
-
1013
- const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
1014
-
1015
1033
  function trimSPorHTAB(str) {
1016
1034
  let start = 0;
1017
1035
  let end = str.length;
@@ -1039,12 +1057,40 @@ function trimSPorHTAB(str) {
1039
1057
  return start === 0 && end === str.length ? str : str.slice(start, end);
1040
1058
  }
1041
1059
 
1042
- function normalizeHeader(header) {
1043
- return header && String(header).trim().toLowerCase();
1060
+ // The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
1061
+ // eslint-disable-next-line no-control-regex
1062
+ const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp('[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+', 'g');
1063
+ // eslint-disable-next-line no-control-regex
1064
+ const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp('[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+', 'g');
1065
+
1066
+ function sanitizeValue(value, invalidChars) {
1067
+ if (utils$1.isArray(value)) {
1068
+ return value.map((item) => sanitizeValue(item, invalidChars));
1069
+ }
1070
+
1071
+ return trimSPorHTAB(String(value).replace(invalidChars, ''));
1072
+ }
1073
+
1074
+ const sanitizeHeaderValue = (value) =>
1075
+ sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
1076
+
1077
+ const sanitizeByteStringHeaderValue = (value) =>
1078
+ sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
1079
+
1080
+ function toByteStringHeaderObject(headers) {
1081
+ const byteStringHeaders = Object.create(null);
1082
+
1083
+ utils$1.forEach(headers.toJSON(), (value, header) => {
1084
+ byteStringHeaders[header] = sanitizeByteStringHeaderValue(value);
1085
+ });
1086
+
1087
+ return byteStringHeaders;
1044
1088
  }
1045
1089
 
1046
- function sanitizeHeaderValue(str) {
1047
- return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, ''));
1090
+ const $internals = Symbol('internals');
1091
+
1092
+ function normalizeHeader(header) {
1093
+ return header && String(header).trim().toLowerCase();
1048
1094
  }
1049
1095
 
1050
1096
  function normalizeValue(value) {
@@ -1126,7 +1172,7 @@ class AxiosHeaders {
1126
1172
  const lHeader = normalizeHeader(_header);
1127
1173
 
1128
1174
  if (!lHeader) {
1129
- throw new Error('header name must be a non-empty string');
1175
+ return;
1130
1176
  }
1131
1177
 
1132
1178
  const key = utils$1.findKey(self, lHeader);
@@ -1154,7 +1200,7 @@ class AxiosHeaders {
1154
1200
  key;
1155
1201
  for (const entry of header) {
1156
1202
  if (!utils$1.isArray(entry)) {
1157
- throw TypeError('Object iterator must return a key-value pair');
1203
+ throw new TypeError('Object iterator must return a key-value pair');
1158
1204
  }
1159
1205
 
1160
1206
  obj[(key = entry[0])] = (dest = obj[key])
@@ -1769,7 +1815,7 @@ function toFormData(obj, formData, options) {
1769
1815
  }
1770
1816
 
1771
1817
  if (stack.indexOf(value) !== -1) {
1772
- throw Error('Circular reference detected in ' + path.join('.'));
1818
+ throw new Error('Circular reference detected in ' + path.join('.'));
1773
1819
  }
1774
1820
 
1775
1821
  stack.push(value);
@@ -1986,6 +2032,7 @@ var transitionalDefaults = {
1986
2032
  forcedJSONParsing: true,
1987
2033
  clarifyTimeoutError: false,
1988
2034
  legacyInterceptorReqResOrdering: true,
2035
+ advertiseZstdAcceptEncoding: false,
1989
2036
  };
1990
2037
 
1991
2038
  var URLSearchParams$1 = typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams;
@@ -2143,7 +2190,7 @@ function formDataToJSON(formData) {
2143
2190
  return !isNumericKey;
2144
2191
  }
2145
2192
 
2146
- if (!target[name] || !utils$1.isObject(target[name])) {
2193
+ if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
2147
2194
  target[name] = [];
2148
2195
  }
2149
2196
 
@@ -2508,6 +2555,9 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
2508
2555
  const _speedometer = speedometer(50, 250);
2509
2556
 
2510
2557
  return throttle((e) => {
2558
+ if (!e || typeof e.loaded !== 'number') {
2559
+ return;
2560
+ }
2511
2561
  const rawLoaded = e.loaded;
2512
2562
  const total = e.lengthComputable ? e.total : undefined;
2513
2563
  const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
@@ -2817,12 +2867,12 @@ function setFormDataHeaders(headers, formHeaders, policy) {
2817
2867
  *
2818
2868
  * @returns {string} UTF-8 bytes as a Latin-1 string
2819
2869
  */
2820
- const encodeUTF8 = (str) =>
2870
+ const encodeUTF8$1 = (str) =>
2821
2871
  encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
2822
2872
  String.fromCharCode(parseInt(hex, 16))
2823
2873
  );
2824
2874
 
2825
- var resolveConfig = (config) => {
2875
+ function resolveConfig(config) {
2826
2876
  const newConfig = mergeConfig({}, config);
2827
2877
 
2828
2878
  // Read only own properties to prevent prototype pollution gadgets
@@ -2843,8 +2893,8 @@ var resolveConfig = (config) => {
2843
2893
 
2844
2894
  newConfig.url = buildURL(
2845
2895
  buildFullPath(baseURL, url, allowAbsoluteUrls),
2846
- config.params,
2847
- config.paramsSerializer
2896
+ own('params'),
2897
+ own('paramsSerializer')
2848
2898
  );
2849
2899
 
2850
2900
  // HTTP basic authentication
@@ -2852,13 +2902,17 @@ var resolveConfig = (config) => {
2852
2902
  headers.set(
2853
2903
  'Authorization',
2854
2904
  'Basic ' +
2855
- btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : ''))
2905
+ btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8$1(auth.password) : ''))
2856
2906
  );
2857
2907
  }
2858
2908
 
2859
2909
  if (utils$1.isFormData(data)) {
2860
- if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {
2861
- headers.setContentType(undefined); // browser handles it
2910
+ if (
2911
+ platform.hasStandardBrowserEnv ||
2912
+ platform.hasStandardBrowserWebWorkerEnv ||
2913
+ utils$1.isReactNative(data)
2914
+ ) {
2915
+ headers.setContentType(undefined); // browser/web worker/RN handles it
2862
2916
  } else if (utils$1.isFunction(data.getHeaders)) {
2863
2917
  // Node.js FormData (like form-data package)
2864
2918
  setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
@@ -2890,7 +2944,7 @@ var resolveConfig = (config) => {
2890
2944
  }
2891
2945
 
2892
2946
  return newConfig;
2893
- };
2947
+ }
2894
2948
 
2895
2949
  const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
2896
2950
 
@@ -3039,7 +3093,7 @@ var xhrAdapter = isXHRAdapterSupported &&
3039
3093
 
3040
3094
  // Add headers to the request
3041
3095
  if ('setRequestHeader' in request) {
3042
- utils$1.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {
3096
+ utils$1.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) {
3043
3097
  request.setRequestHeader(key, val);
3044
3098
  });
3045
3099
  }
@@ -3109,54 +3163,55 @@ var xhrAdapter = isXHRAdapterSupported &&
3109
3163
  };
3110
3164
 
3111
3165
  const composeSignals = (signals, timeout) => {
3112
- const { length } = (signals = signals ? signals.filter(Boolean) : []);
3113
-
3114
- if (timeout || length) {
3115
- let controller = new AbortController();
3116
-
3117
- let aborted;
3118
-
3119
- const onabort = function (reason) {
3120
- if (!aborted) {
3121
- aborted = true;
3122
- unsubscribe();
3123
- const err = reason instanceof Error ? reason : this.reason;
3124
- controller.abort(
3125
- err instanceof AxiosError
3126
- ? err
3127
- : new CanceledError(err instanceof Error ? err.message : err)
3128
- );
3129
- }
3130
- };
3166
+ signals = signals ? signals.filter(Boolean) : [];
3131
3167
 
3132
- let timer =
3133
- timeout &&
3134
- setTimeout(() => {
3135
- timer = null;
3136
- onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
3137
- }, timeout);
3138
-
3139
- const unsubscribe = () => {
3140
- if (signals) {
3141
- timer && clearTimeout(timer);
3142
- timer = null;
3143
- signals.forEach((signal) => {
3144
- signal.unsubscribe
3145
- ? signal.unsubscribe(onabort)
3146
- : signal.removeEventListener('abort', onabort);
3147
- });
3148
- signals = null;
3149
- }
3150
- };
3168
+ if (!timeout && !signals.length) {
3169
+ return;
3170
+ }
3151
3171
 
3152
- signals.forEach((signal) => signal.addEventListener('abort', onabort));
3172
+ const controller = new AbortController();
3153
3173
 
3154
- const { signal } = controller;
3174
+ let aborted = false;
3155
3175
 
3156
- signal.unsubscribe = () => utils$1.asap(unsubscribe);
3176
+ const onabort = function (reason) {
3177
+ if (!aborted) {
3178
+ aborted = true;
3179
+ unsubscribe();
3180
+ const err = reason instanceof Error ? reason : this.reason;
3181
+ controller.abort(
3182
+ err instanceof AxiosError
3183
+ ? err
3184
+ : new CanceledError(err instanceof Error ? err.message : err)
3185
+ );
3186
+ }
3187
+ };
3157
3188
 
3158
- return signal;
3159
- }
3189
+ let timer =
3190
+ timeout &&
3191
+ setTimeout(() => {
3192
+ timer = null;
3193
+ onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
3194
+ }, timeout);
3195
+
3196
+ const unsubscribe = () => {
3197
+ if (!signals) { return; }
3198
+ timer && clearTimeout(timer);
3199
+ timer = null;
3200
+ signals.forEach((signal) => {
3201
+ signal.unsubscribe
3202
+ ? signal.unsubscribe(onabort)
3203
+ : signal.removeEventListener('abort', onabort);
3204
+ });
3205
+ signals = null;
3206
+ };
3207
+
3208
+ signals.forEach((signal) => signal.addEventListener('abort', onabort));
3209
+
3210
+ const { signal } = controller;
3211
+
3212
+ signal.unsubscribe = () => utils$1.asap(unsubscribe);
3213
+
3214
+ return signal;
3160
3215
  };
3161
3216
 
3162
3217
  const streamChunk = function* (chunk, chunkSize) {
@@ -3350,12 +3405,41 @@ function estimateDataURLDecodedBytes(url) {
3350
3405
  return bytes;
3351
3406
  }
3352
3407
 
3353
- const VERSION = "1.16.0";
3408
+ const VERSION = "1.17.0";
3354
3409
 
3355
3410
  const DEFAULT_CHUNK_SIZE = 64 * 1024;
3356
3411
 
3357
3412
  const { isFunction } = utils$1;
3358
3413
 
3414
+ /**
3415
+ * Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
3416
+ * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
3417
+ *
3418
+ * @param {string} str The string to encode
3419
+ *
3420
+ * @returns {string} UTF-8 bytes as a Latin-1 string
3421
+ */
3422
+ const encodeUTF8 = (str) =>
3423
+ encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
3424
+ String.fromCharCode(parseInt(hex, 16))
3425
+ );
3426
+
3427
+ // Node's WHATWG URL parser returns `username` and `password` percent-encoded.
3428
+ // Decode before composing the `auth` option so credentials such as
3429
+ // `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
3430
+ // original value for malformed input so a bad encoding never throws.
3431
+ const decodeURIComponentSafe = (value) => {
3432
+ if (!utils$1.isString(value)) {
3433
+ return value;
3434
+ }
3435
+
3436
+ try {
3437
+ return decodeURIComponent(value);
3438
+ } catch (error) {
3439
+ return value;
3440
+ }
3441
+ };
3442
+
3359
3443
  const test = (fn, ...args) => {
3360
3444
  try {
3361
3445
  return !!fn(...args);
@@ -3364,8 +3448,20 @@ const test = (fn, ...args) => {
3364
3448
  }
3365
3449
  };
3366
3450
 
3451
+ const maybeWithAuthCredentials = (url) => {
3452
+ const protocolIndex = url.indexOf('://');
3453
+ let urlToCheck = url;
3454
+ if (protocolIndex !== -1) {
3455
+ urlToCheck = urlToCheck.slice(protocolIndex + 3);
3456
+ }
3457
+ return urlToCheck.includes('@') || urlToCheck.includes(':');
3458
+ };
3459
+
3367
3460
  const factory = (env) => {
3368
- const globalObject = utils$1.global ?? globalThis;
3461
+ const globalObject =
3462
+ utils$1.global !== undefined && utils$1.global !== null
3463
+ ? utils$1.global
3464
+ : globalThis;
3369
3465
  const { ReadableStream, TextEncoder } = globalObject;
3370
3466
 
3371
3467
  env = utils$1.merge.call(
@@ -3508,6 +3604,7 @@ const factory = (env) => {
3508
3604
 
3509
3605
  const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
3510
3606
  const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
3607
+ const own = (key) => (utils$1.hasOwnProp(config, key) ? config[key] : undefined);
3511
3608
 
3512
3609
  let _fetch = envFetch || fetch;
3513
3610
 
@@ -3530,6 +3627,46 @@ const factory = (env) => {
3530
3627
  let requestContentLength;
3531
3628
 
3532
3629
  try {
3630
+ // HTTP basic authentication
3631
+ let auth = undefined;
3632
+ const configAuth = own('auth');
3633
+
3634
+ if (configAuth) {
3635
+ const username = configAuth.username || '';
3636
+ const password = configAuth.password || '';
3637
+ auth = {
3638
+ username,
3639
+ password
3640
+ };
3641
+ }
3642
+
3643
+ if (maybeWithAuthCredentials(url)) {
3644
+ const parsedURL = new URL(url, platform.origin);
3645
+
3646
+ if (!auth && (parsedURL.username || parsedURL.password)) {
3647
+ const urlUsername = decodeURIComponentSafe(parsedURL.username);
3648
+ const urlPassword = decodeURIComponentSafe(parsedURL.password);
3649
+ auth = {
3650
+ username: urlUsername,
3651
+ password: urlPassword
3652
+ };
3653
+ }
3654
+
3655
+ if (parsedURL.username || parsedURL.password) {
3656
+ parsedURL.username = '';
3657
+ parsedURL.password = '';
3658
+ url = parsedURL.href;
3659
+ }
3660
+ }
3661
+
3662
+ if (auth) {
3663
+ headers.delete('authorization');
3664
+ headers.set(
3665
+ 'Authorization',
3666
+ 'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || '')))
3667
+ );
3668
+ }
3669
+
3533
3670
  // Enforce maxContentLength for data: URLs up-front so we never materialize
3534
3671
  // an oversized payload. The HTTP adapter applies the same check (see http.js
3535
3672
  // "if (protocol === 'data:')" branch).
@@ -3622,7 +3759,7 @@ const factory = (env) => {
3622
3759
  ...fetchOptions,
3623
3760
  signal: composedSignal,
3624
3761
  method: method.toUpperCase(),
3625
- headers: headers.normalize().toJSON(),
3762
+ headers: toByteStringHeaderObject(headers.normalize()),
3626
3763
  body: data,
3627
3764
  duplex: 'half',
3628
3765
  credentials: isCredentialsSupported ? withCredentials : undefined,
@@ -4211,6 +4348,7 @@ class Axios {
4211
4348
  forcedJSONParsing: validators.transitional(validators.boolean),
4212
4349
  clarifyTimeoutError: validators.transitional(validators.boolean),
4213
4350
  legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
4351
+ advertiseZstdAcceptEncoding: validators.transitional(validators.boolean),
4214
4352
  },
4215
4353
  false
4216
4354
  );