axios 1.6.7 → 1.7.3
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.
Potentially problematic release.
This version of axios might be problematic. Click here for more details.
- package/CHANGELOG.md +875 -763
- package/README.md +65 -17
- package/dist/axios.js +1413 -573
- package/dist/axios.js.map +1 -1
- package/dist/axios.min.js +1 -1
- package/dist/axios.min.js.map +1 -1
- package/dist/browser/axios.cjs +764 -308
- package/dist/browser/axios.cjs.map +1 -1
- package/dist/esm/axios.js +764 -308
- package/dist/esm/axios.js.map +1 -1
- package/dist/esm/axios.min.js +1 -1
- package/dist/esm/axios.min.js.map +1 -1
- package/dist/node/axios.cjs +778 -390
- package/dist/node/axios.cjs.map +1 -1
- package/index.d.cts +5 -2
- package/index.d.ts +5 -2
- package/lib/adapters/adapters.js +3 -1
- package/lib/adapters/fetch.js +229 -0
- package/lib/adapters/http.js +26 -16
- package/lib/adapters/xhr.js +36 -99
- package/lib/core/Axios.js +9 -6
- package/lib/core/AxiosHeaders.js +4 -0
- package/lib/core/mergeConfig.js +1 -1
- package/lib/defaults/index.js +7 -2
- package/lib/env/data.js +1 -1
- package/lib/helpers/AxiosTransformStream.js +3 -51
- package/lib/helpers/composeSignals.js +46 -0
- package/lib/helpers/progressEventReducer.js +44 -0
- package/lib/helpers/resolveConfig.js +57 -0
- package/lib/helpers/throttle.js +30 -19
- package/lib/helpers/trackStream.js +67 -0
- package/lib/platform/common/utils.js +4 -1
- package/lib/utils.js +40 -3
- package/package.json +27 -26
package/dist/node/axios.cjs
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
// Axios v1.
|
1
|
+
// Axios v1.7.3 Copyright (c) 2024 Matt Zabriskie and contributors
|
2
2
|
'use strict';
|
3
3
|
|
4
4
|
const FormData$1 = require('form-data');
|
@@ -10,7 +10,7 @@ const util = require('util');
|
|
10
10
|
const followRedirects = require('follow-redirects');
|
11
11
|
const zlib = require('zlib');
|
12
12
|
const stream = require('stream');
|
13
|
-
const
|
13
|
+
const events = require('events');
|
14
14
|
|
15
15
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
16
16
|
|
@@ -22,7 +22,6 @@ const util__default = /*#__PURE__*/_interopDefaultLegacy(util);
|
|
22
22
|
const followRedirects__default = /*#__PURE__*/_interopDefaultLegacy(followRedirects);
|
23
23
|
const zlib__default = /*#__PURE__*/_interopDefaultLegacy(zlib);
|
24
24
|
const stream__default = /*#__PURE__*/_interopDefaultLegacy(stream);
|
25
|
-
const EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
|
26
25
|
|
27
26
|
function bind(fn, thisArg) {
|
28
27
|
return function wrap() {
|
@@ -237,6 +236,8 @@ const isFormData = (thing) => {
|
|
237
236
|
*/
|
238
237
|
const isURLSearchParams = kindOfTest('URLSearchParams');
|
239
238
|
|
239
|
+
const [isReadableStream, isRequest, isResponse, isHeaders] = ['ReadableStream', 'Request', 'Response', 'Headers'].map(kindOfTest);
|
240
|
+
|
240
241
|
/**
|
241
242
|
* Trim excess whitespace off the beginning and end of a string
|
242
243
|
*
|
@@ -625,8 +626,7 @@ const toObjectSet = (arrayOrString, delimiter) => {
|
|
625
626
|
const noop = () => {};
|
626
627
|
|
627
628
|
const toFiniteNumber = (value, defaultValue) => {
|
628
|
-
value = +value;
|
629
|
-
return Number.isFinite(value) ? value : defaultValue;
|
629
|
+
return value != null && Number.isFinite(value = +value) ? value : defaultValue;
|
630
630
|
};
|
631
631
|
|
632
632
|
const ALPHA = 'abcdefghijklmnopqrstuvwxyz';
|
@@ -696,6 +696,36 @@ const isAsyncFn = kindOfTest('AsyncFunction');
|
|
696
696
|
const isThenable = (thing) =>
|
697
697
|
thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);
|
698
698
|
|
699
|
+
// original code
|
700
|
+
// https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34
|
701
|
+
|
702
|
+
const _setImmediate = ((setImmediateSupported, postMessageSupported) => {
|
703
|
+
if (setImmediateSupported) {
|
704
|
+
return setImmediate;
|
705
|
+
}
|
706
|
+
|
707
|
+
return postMessageSupported ? ((token, callbacks) => {
|
708
|
+
_global.addEventListener("message", ({source, data}) => {
|
709
|
+
if (source === _global && data === token) {
|
710
|
+
callbacks.length && callbacks.shift()();
|
711
|
+
}
|
712
|
+
}, false);
|
713
|
+
|
714
|
+
return (cb) => {
|
715
|
+
callbacks.push(cb);
|
716
|
+
_global.postMessage(token, "*");
|
717
|
+
}
|
718
|
+
})(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb);
|
719
|
+
})(
|
720
|
+
typeof setImmediate === 'function',
|
721
|
+
isFunction(_global.postMessage)
|
722
|
+
);
|
723
|
+
|
724
|
+
const asap = typeof queueMicrotask !== 'undefined' ?
|
725
|
+
queueMicrotask.bind(_global) : ( typeof process !== 'undefined' && process.nextTick || _setImmediate);
|
726
|
+
|
727
|
+
// *********************
|
728
|
+
|
699
729
|
const utils$1 = {
|
700
730
|
isArray,
|
701
731
|
isArrayBuffer,
|
@@ -707,6 +737,10 @@ const utils$1 = {
|
|
707
737
|
isBoolean,
|
708
738
|
isObject,
|
709
739
|
isPlainObject,
|
740
|
+
isReadableStream,
|
741
|
+
isRequest,
|
742
|
+
isResponse,
|
743
|
+
isHeaders,
|
710
744
|
isUndefined,
|
711
745
|
isDate,
|
712
746
|
isFile,
|
@@ -747,7 +781,9 @@ const utils$1 = {
|
|
747
781
|
isSpecCompliantForm,
|
748
782
|
toJSONObject,
|
749
783
|
isAsyncFn,
|
750
|
-
isThenable
|
784
|
+
isThenable,
|
785
|
+
setImmediate: _setImmediate,
|
786
|
+
asap
|
751
787
|
};
|
752
788
|
|
753
789
|
/**
|
@@ -1296,11 +1332,14 @@ const hasStandardBrowserWebWorkerEnv = (() => {
|
|
1296
1332
|
);
|
1297
1333
|
})();
|
1298
1334
|
|
1335
|
+
const origin = hasBrowserEnv && window.location.href || 'http://localhost';
|
1336
|
+
|
1299
1337
|
const utils = /*#__PURE__*/Object.freeze({
|
1300
1338
|
__proto__: null,
|
1301
1339
|
hasBrowserEnv: hasBrowserEnv,
|
1302
1340
|
hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
|
1303
|
-
hasStandardBrowserEnv: hasStandardBrowserEnv
|
1341
|
+
hasStandardBrowserEnv: hasStandardBrowserEnv,
|
1342
|
+
origin: origin
|
1304
1343
|
});
|
1305
1344
|
|
1306
1345
|
const platform = {
|
@@ -1440,7 +1479,7 @@ const defaults = {
|
|
1440
1479
|
|
1441
1480
|
transitional: transitionalDefaults,
|
1442
1481
|
|
1443
|
-
adapter: ['xhr', 'http'],
|
1482
|
+
adapter: ['xhr', 'http', 'fetch'],
|
1444
1483
|
|
1445
1484
|
transformRequest: [function transformRequest(data, headers) {
|
1446
1485
|
const contentType = headers.getContentType() || '';
|
@@ -1461,7 +1500,8 @@ const defaults = {
|
|
1461
1500
|
utils$1.isBuffer(data) ||
|
1462
1501
|
utils$1.isStream(data) ||
|
1463
1502
|
utils$1.isFile(data) ||
|
1464
|
-
utils$1.isBlob(data)
|
1503
|
+
utils$1.isBlob(data) ||
|
1504
|
+
utils$1.isReadableStream(data)
|
1465
1505
|
) {
|
1466
1506
|
return data;
|
1467
1507
|
}
|
@@ -1504,6 +1544,10 @@ const defaults = {
|
|
1504
1544
|
const forcedJSONParsing = transitional && transitional.forcedJSONParsing;
|
1505
1545
|
const JSONRequested = this.responseType === 'json';
|
1506
1546
|
|
1547
|
+
if (utils$1.isResponse(data) || utils$1.isReadableStream(data)) {
|
1548
|
+
return data;
|
1549
|
+
}
|
1550
|
+
|
1507
1551
|
if (data && utils$1.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) {
|
1508
1552
|
const silentJSONParsing = transitional && transitional.silentJSONParsing;
|
1509
1553
|
const strictJSONParsing = !silentJSONParsing && JSONRequested;
|
@@ -1707,6 +1751,10 @@ class AxiosHeaders {
|
|
1707
1751
|
setHeaders(header, valueOrRewrite);
|
1708
1752
|
} else if(utils$1.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {
|
1709
1753
|
setHeaders(parseHeaders(header), valueOrRewrite);
|
1754
|
+
} else if (utils$1.isHeaders(header)) {
|
1755
|
+
for (const [key, value] of header.entries()) {
|
1756
|
+
setHeader(value, key, rewrite);
|
1757
|
+
}
|
1710
1758
|
} else {
|
1711
1759
|
header != null && setHeader(valueOrRewrite, header, rewrite);
|
1712
1760
|
}
|
@@ -2019,7 +2067,7 @@ function buildFullPath(baseURL, requestedURL) {
|
|
2019
2067
|
return requestedURL;
|
2020
2068
|
}
|
2021
2069
|
|
2022
|
-
const VERSION = "1.
|
2070
|
+
const VERSION = "1.7.3";
|
2023
2071
|
|
2024
2072
|
function parseProtocol(url) {
|
2025
2073
|
const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url);
|
@@ -2074,88 +2122,6 @@ function fromDataURI(uri, asBlob, options) {
|
|
2074
2122
|
throw new AxiosError('Unsupported protocol ' + protocol, AxiosError.ERR_NOT_SUPPORT);
|
2075
2123
|
}
|
2076
2124
|
|
2077
|
-
/**
|
2078
|
-
* Throttle decorator
|
2079
|
-
* @param {Function} fn
|
2080
|
-
* @param {Number} freq
|
2081
|
-
* @return {Function}
|
2082
|
-
*/
|
2083
|
-
function throttle(fn, freq) {
|
2084
|
-
let timestamp = 0;
|
2085
|
-
const threshold = 1000 / freq;
|
2086
|
-
let timer = null;
|
2087
|
-
return function throttled(force, args) {
|
2088
|
-
const now = Date.now();
|
2089
|
-
if (force || now - timestamp > threshold) {
|
2090
|
-
if (timer) {
|
2091
|
-
clearTimeout(timer);
|
2092
|
-
timer = null;
|
2093
|
-
}
|
2094
|
-
timestamp = now;
|
2095
|
-
return fn.apply(null, args);
|
2096
|
-
}
|
2097
|
-
if (!timer) {
|
2098
|
-
timer = setTimeout(() => {
|
2099
|
-
timer = null;
|
2100
|
-
timestamp = Date.now();
|
2101
|
-
return fn.apply(null, args);
|
2102
|
-
}, threshold - (now - timestamp));
|
2103
|
-
}
|
2104
|
-
};
|
2105
|
-
}
|
2106
|
-
|
2107
|
-
/**
|
2108
|
-
* Calculate data maxRate
|
2109
|
-
* @param {Number} [samplesCount= 10]
|
2110
|
-
* @param {Number} [min= 1000]
|
2111
|
-
* @returns {Function}
|
2112
|
-
*/
|
2113
|
-
function speedometer(samplesCount, min) {
|
2114
|
-
samplesCount = samplesCount || 10;
|
2115
|
-
const bytes = new Array(samplesCount);
|
2116
|
-
const timestamps = new Array(samplesCount);
|
2117
|
-
let head = 0;
|
2118
|
-
let tail = 0;
|
2119
|
-
let firstSampleTS;
|
2120
|
-
|
2121
|
-
min = min !== undefined ? min : 1000;
|
2122
|
-
|
2123
|
-
return function push(chunkLength) {
|
2124
|
-
const now = Date.now();
|
2125
|
-
|
2126
|
-
const startedAt = timestamps[tail];
|
2127
|
-
|
2128
|
-
if (!firstSampleTS) {
|
2129
|
-
firstSampleTS = now;
|
2130
|
-
}
|
2131
|
-
|
2132
|
-
bytes[head] = chunkLength;
|
2133
|
-
timestamps[head] = now;
|
2134
|
-
|
2135
|
-
let i = tail;
|
2136
|
-
let bytesCount = 0;
|
2137
|
-
|
2138
|
-
while (i !== head) {
|
2139
|
-
bytesCount += bytes[i++];
|
2140
|
-
i = i % samplesCount;
|
2141
|
-
}
|
2142
|
-
|
2143
|
-
head = (head + 1) % samplesCount;
|
2144
|
-
|
2145
|
-
if (head === tail) {
|
2146
|
-
tail = (tail + 1) % samplesCount;
|
2147
|
-
}
|
2148
|
-
|
2149
|
-
if (now - firstSampleTS < min) {
|
2150
|
-
return;
|
2151
|
-
}
|
2152
|
-
|
2153
|
-
const passed = startedAt && now - startedAt;
|
2154
|
-
|
2155
|
-
return passed ? Math.round(bytesCount * 1000 / passed) : undefined;
|
2156
|
-
};
|
2157
|
-
}
|
2158
|
-
|
2159
2125
|
const kInternals = Symbol('internals');
|
2160
2126
|
|
2161
2127
|
class AxiosTransformStream extends stream__default["default"].Transform{
|
@@ -2175,12 +2141,8 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2175
2141
|
readableHighWaterMark: options.chunkSize
|
2176
2142
|
});
|
2177
2143
|
|
2178
|
-
const self = this;
|
2179
|
-
|
2180
2144
|
const internals = this[kInternals] = {
|
2181
|
-
length: options.length,
|
2182
2145
|
timeWindow: options.timeWindow,
|
2183
|
-
ticksRate: options.ticksRate,
|
2184
2146
|
chunkSize: options.chunkSize,
|
2185
2147
|
maxRate: options.maxRate,
|
2186
2148
|
minChunkSize: options.minChunkSize,
|
@@ -2192,8 +2154,6 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2192
2154
|
onReadCallback: null
|
2193
2155
|
};
|
2194
2156
|
|
2195
|
-
const _speedometer = speedometer(internals.ticksRate * options.samplesCount, internals.timeWindow);
|
2196
|
-
|
2197
2157
|
this.on('newListener', event => {
|
2198
2158
|
if (event === 'progress') {
|
2199
2159
|
if (!internals.isCaptured) {
|
@@ -2201,38 +2161,6 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2201
2161
|
}
|
2202
2162
|
}
|
2203
2163
|
});
|
2204
|
-
|
2205
|
-
let bytesNotified = 0;
|
2206
|
-
|
2207
|
-
internals.updateProgress = throttle(function throttledHandler() {
|
2208
|
-
const totalBytes = internals.length;
|
2209
|
-
const bytesTransferred = internals.bytesSeen;
|
2210
|
-
const progressBytes = bytesTransferred - bytesNotified;
|
2211
|
-
if (!progressBytes || self.destroyed) return;
|
2212
|
-
|
2213
|
-
const rate = _speedometer(progressBytes);
|
2214
|
-
|
2215
|
-
bytesNotified = bytesTransferred;
|
2216
|
-
|
2217
|
-
process.nextTick(() => {
|
2218
|
-
self.emit('progress', {
|
2219
|
-
'loaded': bytesTransferred,
|
2220
|
-
'total': totalBytes,
|
2221
|
-
'progress': totalBytes ? (bytesTransferred / totalBytes) : undefined,
|
2222
|
-
'bytes': progressBytes,
|
2223
|
-
'rate': rate ? rate : undefined,
|
2224
|
-
'estimated': rate && totalBytes && bytesTransferred <= totalBytes ?
|
2225
|
-
(totalBytes - bytesTransferred) / rate : undefined
|
2226
|
-
});
|
2227
|
-
});
|
2228
|
-
}, internals.ticksRate);
|
2229
|
-
|
2230
|
-
const onFinish = () => {
|
2231
|
-
internals.updateProgress(true);
|
2232
|
-
};
|
2233
|
-
|
2234
|
-
this.once('end', onFinish);
|
2235
|
-
this.once('error', onFinish);
|
2236
2164
|
}
|
2237
2165
|
|
2238
2166
|
_read(size) {
|
@@ -2246,7 +2174,6 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2246
2174
|
}
|
2247
2175
|
|
2248
2176
|
_transform(chunk, encoding, callback) {
|
2249
|
-
const self = this;
|
2250
2177
|
const internals = this[kInternals];
|
2251
2178
|
const maxRate = internals.maxRate;
|
2252
2179
|
|
@@ -2258,16 +2185,14 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2258
2185
|
const bytesThreshold = (maxRate / divider);
|
2259
2186
|
const minChunkSize = internals.minChunkSize !== false ? Math.max(internals.minChunkSize, bytesThreshold * 0.01) : 0;
|
2260
2187
|
|
2261
|
-
|
2188
|
+
const pushChunk = (_chunk, _callback) => {
|
2262
2189
|
const bytes = Buffer.byteLength(_chunk);
|
2263
2190
|
internals.bytesSeen += bytes;
|
2264
2191
|
internals.bytes += bytes;
|
2265
2192
|
|
2266
|
-
|
2267
|
-
internals.updateProgress();
|
2268
|
-
}
|
2193
|
+
internals.isCaptured && this.emit('progress', internals.bytesSeen);
|
2269
2194
|
|
2270
|
-
if (
|
2195
|
+
if (this.push(_chunk)) {
|
2271
2196
|
process.nextTick(_callback);
|
2272
2197
|
} else {
|
2273
2198
|
internals.onReadCallback = () => {
|
@@ -2275,7 +2200,7 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2275
2200
|
process.nextTick(_callback);
|
2276
2201
|
};
|
2277
2202
|
}
|
2278
|
-
}
|
2203
|
+
};
|
2279
2204
|
|
2280
2205
|
const transformChunk = (_chunk, _callback) => {
|
2281
2206
|
const chunkSize = Buffer.byteLength(_chunk);
|
@@ -2332,11 +2257,6 @@ class AxiosTransformStream extends stream__default["default"].Transform{
|
|
2332
2257
|
}
|
2333
2258
|
});
|
2334
2259
|
}
|
2335
|
-
|
2336
|
-
setLength(length) {
|
2337
|
-
this[kInternals].length = +length;
|
2338
|
-
return this;
|
2339
|
-
}
|
2340
2260
|
}
|
2341
2261
|
|
2342
2262
|
const AxiosTransformStream$1 = AxiosTransformStream;
|
@@ -2504,6 +2424,142 @@ const callbackify = (fn, reducer) => {
|
|
2504
2424
|
|
2505
2425
|
const callbackify$1 = callbackify;
|
2506
2426
|
|
2427
|
+
/**
|
2428
|
+
* Calculate data maxRate
|
2429
|
+
* @param {Number} [samplesCount= 10]
|
2430
|
+
* @param {Number} [min= 1000]
|
2431
|
+
* @returns {Function}
|
2432
|
+
*/
|
2433
|
+
function speedometer(samplesCount, min) {
|
2434
|
+
samplesCount = samplesCount || 10;
|
2435
|
+
const bytes = new Array(samplesCount);
|
2436
|
+
const timestamps = new Array(samplesCount);
|
2437
|
+
let head = 0;
|
2438
|
+
let tail = 0;
|
2439
|
+
let firstSampleTS;
|
2440
|
+
|
2441
|
+
min = min !== undefined ? min : 1000;
|
2442
|
+
|
2443
|
+
return function push(chunkLength) {
|
2444
|
+
const now = Date.now();
|
2445
|
+
|
2446
|
+
const startedAt = timestamps[tail];
|
2447
|
+
|
2448
|
+
if (!firstSampleTS) {
|
2449
|
+
firstSampleTS = now;
|
2450
|
+
}
|
2451
|
+
|
2452
|
+
bytes[head] = chunkLength;
|
2453
|
+
timestamps[head] = now;
|
2454
|
+
|
2455
|
+
let i = tail;
|
2456
|
+
let bytesCount = 0;
|
2457
|
+
|
2458
|
+
while (i !== head) {
|
2459
|
+
bytesCount += bytes[i++];
|
2460
|
+
i = i % samplesCount;
|
2461
|
+
}
|
2462
|
+
|
2463
|
+
head = (head + 1) % samplesCount;
|
2464
|
+
|
2465
|
+
if (head === tail) {
|
2466
|
+
tail = (tail + 1) % samplesCount;
|
2467
|
+
}
|
2468
|
+
|
2469
|
+
if (now - firstSampleTS < min) {
|
2470
|
+
return;
|
2471
|
+
}
|
2472
|
+
|
2473
|
+
const passed = startedAt && now - startedAt;
|
2474
|
+
|
2475
|
+
return passed ? Math.round(bytesCount * 1000 / passed) : undefined;
|
2476
|
+
};
|
2477
|
+
}
|
2478
|
+
|
2479
|
+
/**
|
2480
|
+
* Throttle decorator
|
2481
|
+
* @param {Function} fn
|
2482
|
+
* @param {Number} freq
|
2483
|
+
* @return {Function}
|
2484
|
+
*/
|
2485
|
+
function throttle(fn, freq) {
|
2486
|
+
let timestamp = 0;
|
2487
|
+
let threshold = 1000 / freq;
|
2488
|
+
let lastArgs;
|
2489
|
+
let timer;
|
2490
|
+
|
2491
|
+
const invoke = (args, now = Date.now()) => {
|
2492
|
+
timestamp = now;
|
2493
|
+
lastArgs = null;
|
2494
|
+
if (timer) {
|
2495
|
+
clearTimeout(timer);
|
2496
|
+
timer = null;
|
2497
|
+
}
|
2498
|
+
fn.apply(null, args);
|
2499
|
+
};
|
2500
|
+
|
2501
|
+
const throttled = (...args) => {
|
2502
|
+
const now = Date.now();
|
2503
|
+
const passed = now - timestamp;
|
2504
|
+
if ( passed >= threshold) {
|
2505
|
+
invoke(args, now);
|
2506
|
+
} else {
|
2507
|
+
lastArgs = args;
|
2508
|
+
if (!timer) {
|
2509
|
+
timer = setTimeout(() => {
|
2510
|
+
timer = null;
|
2511
|
+
invoke(lastArgs);
|
2512
|
+
}, threshold - passed);
|
2513
|
+
}
|
2514
|
+
}
|
2515
|
+
};
|
2516
|
+
|
2517
|
+
const flush = () => lastArgs && invoke(lastArgs);
|
2518
|
+
|
2519
|
+
return [throttled, flush];
|
2520
|
+
}
|
2521
|
+
|
2522
|
+
const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
2523
|
+
let bytesNotified = 0;
|
2524
|
+
const _speedometer = speedometer(50, 250);
|
2525
|
+
|
2526
|
+
return throttle(e => {
|
2527
|
+
const loaded = e.loaded;
|
2528
|
+
const total = e.lengthComputable ? e.total : undefined;
|
2529
|
+
const progressBytes = loaded - bytesNotified;
|
2530
|
+
const rate = _speedometer(progressBytes);
|
2531
|
+
const inRange = loaded <= total;
|
2532
|
+
|
2533
|
+
bytesNotified = loaded;
|
2534
|
+
|
2535
|
+
const data = {
|
2536
|
+
loaded,
|
2537
|
+
total,
|
2538
|
+
progress: total ? (loaded / total) : undefined,
|
2539
|
+
bytes: progressBytes,
|
2540
|
+
rate: rate ? rate : undefined,
|
2541
|
+
estimated: rate && total && inRange ? (total - loaded) / rate : undefined,
|
2542
|
+
event: e,
|
2543
|
+
lengthComputable: total != null,
|
2544
|
+
[isDownloadStream ? 'download' : 'upload']: true
|
2545
|
+
};
|
2546
|
+
|
2547
|
+
listener(data);
|
2548
|
+
}, freq);
|
2549
|
+
};
|
2550
|
+
|
2551
|
+
const progressEventDecorator = (total, throttled) => {
|
2552
|
+
const lengthComputable = total != null;
|
2553
|
+
|
2554
|
+
return [(loaded) => throttled[0]({
|
2555
|
+
lengthComputable,
|
2556
|
+
total,
|
2557
|
+
loaded
|
2558
|
+
}), throttled[1]];
|
2559
|
+
};
|
2560
|
+
|
2561
|
+
const asyncDecorator = (fn) => (...args) => utils$1.asap(() => fn(...args));
|
2562
|
+
|
2507
2563
|
const zlibOptions = {
|
2508
2564
|
flush: zlib__default["default"].constants.Z_SYNC_FLUSH,
|
2509
2565
|
finishFlush: zlib__default["default"].constants.Z_SYNC_FLUSH
|
@@ -2524,6 +2580,14 @@ const supportedProtocols = platform.protocols.map(protocol => {
|
|
2524
2580
|
return protocol + ':';
|
2525
2581
|
});
|
2526
2582
|
|
2583
|
+
const flushOnFinish = (stream, [throttled, flush]) => {
|
2584
|
+
stream
|
2585
|
+
.on('end', flush)
|
2586
|
+
.on('error', flush);
|
2587
|
+
|
2588
|
+
return throttled;
|
2589
|
+
};
|
2590
|
+
|
2527
2591
|
/**
|
2528
2592
|
* If the proxy or config beforeRedirects functions are defined, call them with the options
|
2529
2593
|
* object.
|
@@ -2662,7 +2726,7 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
2662
2726
|
}
|
2663
2727
|
|
2664
2728
|
// temporary internal emitter until the AxiosRequest class will be implemented
|
2665
|
-
const emitter = new
|
2729
|
+
const emitter = new events.EventEmitter();
|
2666
2730
|
|
2667
2731
|
const onFinished = () => {
|
2668
2732
|
if (config.cancelToken) {
|
@@ -2757,8 +2821,7 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
2757
2821
|
// Only set header if it hasn't been set in config
|
2758
2822
|
headers.set('User-Agent', 'axios/' + VERSION, false);
|
2759
2823
|
|
2760
|
-
const onDownloadProgress = config
|
2761
|
-
const onUploadProgress = config.onUploadProgress;
|
2824
|
+
const {onUploadProgress, onDownloadProgress} = config;
|
2762
2825
|
const maxRate = config.maxRate;
|
2763
2826
|
let maxUploadRate = undefined;
|
2764
2827
|
let maxDownloadRate = undefined;
|
@@ -2829,15 +2892,16 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
2829
2892
|
}
|
2830
2893
|
|
2831
2894
|
data = stream__default["default"].pipeline([data, new AxiosTransformStream$1({
|
2832
|
-
length: contentLength,
|
2833
2895
|
maxRate: utils$1.toFiniteNumber(maxUploadRate)
|
2834
2896
|
})], utils$1.noop);
|
2835
2897
|
|
2836
|
-
onUploadProgress && data.on('progress',
|
2837
|
-
|
2838
|
-
|
2839
|
-
|
2840
|
-
|
2898
|
+
onUploadProgress && data.on('progress', flushOnFinish(
|
2899
|
+
data,
|
2900
|
+
progressEventDecorator(
|
2901
|
+
contentLength,
|
2902
|
+
progressEventReducer(asyncDecorator(onUploadProgress), false, 3)
|
2903
|
+
)
|
2904
|
+
));
|
2841
2905
|
}
|
2842
2906
|
|
2843
2907
|
// HTTP basic authentication
|
@@ -2936,17 +3000,18 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
2936
3000
|
|
2937
3001
|
const responseLength = +res.headers['content-length'];
|
2938
3002
|
|
2939
|
-
if (onDownloadProgress) {
|
3003
|
+
if (onDownloadProgress || maxDownloadRate) {
|
2940
3004
|
const transformStream = new AxiosTransformStream$1({
|
2941
|
-
length: utils$1.toFiniteNumber(responseLength),
|
2942
3005
|
maxRate: utils$1.toFiniteNumber(maxDownloadRate)
|
2943
3006
|
});
|
2944
3007
|
|
2945
|
-
onDownloadProgress && transformStream.on('progress',
|
2946
|
-
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
3008
|
+
onDownloadProgress && transformStream.on('progress', flushOnFinish(
|
3009
|
+
transformStream,
|
3010
|
+
progressEventDecorator(
|
3011
|
+
responseLength,
|
3012
|
+
progressEventReducer(asyncDecorator(onDownloadProgress), true, 3)
|
3013
|
+
)
|
3014
|
+
));
|
2950
3015
|
|
2951
3016
|
streams.push(transformStream);
|
2952
3017
|
}
|
@@ -3159,45 +3224,6 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
3159
3224
|
});
|
3160
3225
|
};
|
3161
3226
|
|
3162
|
-
const cookies = platform.hasStandardBrowserEnv ?
|
3163
|
-
|
3164
|
-
// Standard browser envs support document.cookie
|
3165
|
-
{
|
3166
|
-
write(name, value, expires, path, domain, secure) {
|
3167
|
-
const cookie = [name + '=' + encodeURIComponent(value)];
|
3168
|
-
|
3169
|
-
utils$1.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString());
|
3170
|
-
|
3171
|
-
utils$1.isString(path) && cookie.push('path=' + path);
|
3172
|
-
|
3173
|
-
utils$1.isString(domain) && cookie.push('domain=' + domain);
|
3174
|
-
|
3175
|
-
secure === true && cookie.push('secure');
|
3176
|
-
|
3177
|
-
document.cookie = cookie.join('; ');
|
3178
|
-
},
|
3179
|
-
|
3180
|
-
read(name) {
|
3181
|
-
const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
|
3182
|
-
return (match ? decodeURIComponent(match[3]) : null);
|
3183
|
-
},
|
3184
|
-
|
3185
|
-
remove(name) {
|
3186
|
-
this.write(name, '', Date.now() - 86400000);
|
3187
|
-
}
|
3188
|
-
}
|
3189
|
-
|
3190
|
-
:
|
3191
|
-
|
3192
|
-
// Non-standard browser env (web workers, react-native) lack needed support.
|
3193
|
-
{
|
3194
|
-
write() {},
|
3195
|
-
read() {
|
3196
|
-
return null;
|
3197
|
-
},
|
3198
|
-
remove() {}
|
3199
|
-
};
|
3200
|
-
|
3201
3227
|
const isURLSameOrigin = platform.hasStandardBrowserEnv ?
|
3202
3228
|
|
3203
3229
|
// Standard browser envs have full support of the APIs needed to test
|
@@ -3261,80 +3287,222 @@ const isURLSameOrigin = platform.hasStandardBrowserEnv ?
|
|
3261
3287
|
};
|
3262
3288
|
})();
|
3263
3289
|
|
3264
|
-
|
3265
|
-
let bytesNotified = 0;
|
3266
|
-
const _speedometer = speedometer(50, 250);
|
3290
|
+
const cookies = platform.hasStandardBrowserEnv ?
|
3267
3291
|
|
3268
|
-
|
3269
|
-
|
3270
|
-
|
3271
|
-
|
3272
|
-
const rate = _speedometer(progressBytes);
|
3273
|
-
const inRange = loaded <= total;
|
3292
|
+
// Standard browser envs support document.cookie
|
3293
|
+
{
|
3294
|
+
write(name, value, expires, path, domain, secure) {
|
3295
|
+
const cookie = [name + '=' + encodeURIComponent(value)];
|
3274
3296
|
|
3275
|
-
|
3297
|
+
utils$1.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString());
|
3276
3298
|
|
3277
|
-
|
3278
|
-
loaded,
|
3279
|
-
total,
|
3280
|
-
progress: total ? (loaded / total) : undefined,
|
3281
|
-
bytes: progressBytes,
|
3282
|
-
rate: rate ? rate : undefined,
|
3283
|
-
estimated: rate && total && inRange ? (total - loaded) / rate : undefined,
|
3284
|
-
event: e
|
3285
|
-
};
|
3299
|
+
utils$1.isString(path) && cookie.push('path=' + path);
|
3286
3300
|
|
3287
|
-
|
3301
|
+
utils$1.isString(domain) && cookie.push('domain=' + domain);
|
3288
3302
|
|
3289
|
-
|
3303
|
+
secure === true && cookie.push('secure');
|
3304
|
+
|
3305
|
+
document.cookie = cookie.join('; ');
|
3306
|
+
},
|
3307
|
+
|
3308
|
+
read(name) {
|
3309
|
+
const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
|
3310
|
+
return (match ? decodeURIComponent(match[3]) : null);
|
3311
|
+
},
|
3312
|
+
|
3313
|
+
remove(name) {
|
3314
|
+
this.write(name, '', Date.now() - 86400000);
|
3315
|
+
}
|
3316
|
+
}
|
3317
|
+
|
3318
|
+
:
|
3319
|
+
|
3320
|
+
// Non-standard browser env (web workers, react-native) lack needed support.
|
3321
|
+
{
|
3322
|
+
write() {},
|
3323
|
+
read() {
|
3324
|
+
return null;
|
3325
|
+
},
|
3326
|
+
remove() {}
|
3290
3327
|
};
|
3328
|
+
|
3329
|
+
const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? { ...thing } : thing;
|
3330
|
+
|
3331
|
+
/**
|
3332
|
+
* Config-specific merge-function which creates a new config-object
|
3333
|
+
* by merging two configuration objects together.
|
3334
|
+
*
|
3335
|
+
* @param {Object} config1
|
3336
|
+
* @param {Object} config2
|
3337
|
+
*
|
3338
|
+
* @returns {Object} New object resulting from merging config2 to config1
|
3339
|
+
*/
|
3340
|
+
function mergeConfig(config1, config2) {
|
3341
|
+
// eslint-disable-next-line no-param-reassign
|
3342
|
+
config2 = config2 || {};
|
3343
|
+
const config = {};
|
3344
|
+
|
3345
|
+
function getMergedValue(target, source, caseless) {
|
3346
|
+
if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) {
|
3347
|
+
return utils$1.merge.call({caseless}, target, source);
|
3348
|
+
} else if (utils$1.isPlainObject(source)) {
|
3349
|
+
return utils$1.merge({}, source);
|
3350
|
+
} else if (utils$1.isArray(source)) {
|
3351
|
+
return source.slice();
|
3352
|
+
}
|
3353
|
+
return source;
|
3354
|
+
}
|
3355
|
+
|
3356
|
+
// eslint-disable-next-line consistent-return
|
3357
|
+
function mergeDeepProperties(a, b, caseless) {
|
3358
|
+
if (!utils$1.isUndefined(b)) {
|
3359
|
+
return getMergedValue(a, b, caseless);
|
3360
|
+
} else if (!utils$1.isUndefined(a)) {
|
3361
|
+
return getMergedValue(undefined, a, caseless);
|
3362
|
+
}
|
3363
|
+
}
|
3364
|
+
|
3365
|
+
// eslint-disable-next-line consistent-return
|
3366
|
+
function valueFromConfig2(a, b) {
|
3367
|
+
if (!utils$1.isUndefined(b)) {
|
3368
|
+
return getMergedValue(undefined, b);
|
3369
|
+
}
|
3370
|
+
}
|
3371
|
+
|
3372
|
+
// eslint-disable-next-line consistent-return
|
3373
|
+
function defaultToConfig2(a, b) {
|
3374
|
+
if (!utils$1.isUndefined(b)) {
|
3375
|
+
return getMergedValue(undefined, b);
|
3376
|
+
} else if (!utils$1.isUndefined(a)) {
|
3377
|
+
return getMergedValue(undefined, a);
|
3378
|
+
}
|
3379
|
+
}
|
3380
|
+
|
3381
|
+
// eslint-disable-next-line consistent-return
|
3382
|
+
function mergeDirectKeys(a, b, prop) {
|
3383
|
+
if (prop in config2) {
|
3384
|
+
return getMergedValue(a, b);
|
3385
|
+
} else if (prop in config1) {
|
3386
|
+
return getMergedValue(undefined, a);
|
3387
|
+
}
|
3388
|
+
}
|
3389
|
+
|
3390
|
+
const mergeMap = {
|
3391
|
+
url: valueFromConfig2,
|
3392
|
+
method: valueFromConfig2,
|
3393
|
+
data: valueFromConfig2,
|
3394
|
+
baseURL: defaultToConfig2,
|
3395
|
+
transformRequest: defaultToConfig2,
|
3396
|
+
transformResponse: defaultToConfig2,
|
3397
|
+
paramsSerializer: defaultToConfig2,
|
3398
|
+
timeout: defaultToConfig2,
|
3399
|
+
timeoutMessage: defaultToConfig2,
|
3400
|
+
withCredentials: defaultToConfig2,
|
3401
|
+
withXSRFToken: defaultToConfig2,
|
3402
|
+
adapter: defaultToConfig2,
|
3403
|
+
responseType: defaultToConfig2,
|
3404
|
+
xsrfCookieName: defaultToConfig2,
|
3405
|
+
xsrfHeaderName: defaultToConfig2,
|
3406
|
+
onUploadProgress: defaultToConfig2,
|
3407
|
+
onDownloadProgress: defaultToConfig2,
|
3408
|
+
decompress: defaultToConfig2,
|
3409
|
+
maxContentLength: defaultToConfig2,
|
3410
|
+
maxBodyLength: defaultToConfig2,
|
3411
|
+
beforeRedirect: defaultToConfig2,
|
3412
|
+
transport: defaultToConfig2,
|
3413
|
+
httpAgent: defaultToConfig2,
|
3414
|
+
httpsAgent: defaultToConfig2,
|
3415
|
+
cancelToken: defaultToConfig2,
|
3416
|
+
socketPath: defaultToConfig2,
|
3417
|
+
responseEncoding: defaultToConfig2,
|
3418
|
+
validateStatus: mergeDirectKeys,
|
3419
|
+
headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true)
|
3420
|
+
};
|
3421
|
+
|
3422
|
+
utils$1.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) {
|
3423
|
+
const merge = mergeMap[prop] || mergeDeepProperties;
|
3424
|
+
const configValue = merge(config1[prop], config2[prop], prop);
|
3425
|
+
(utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
3426
|
+
});
|
3427
|
+
|
3428
|
+
return config;
|
3291
3429
|
}
|
3292
3430
|
|
3293
|
-
const
|
3431
|
+
const resolveConfig = (config) => {
|
3432
|
+
const newConfig = mergeConfig({}, config);
|
3294
3433
|
|
3295
|
-
|
3296
|
-
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
3297
|
-
let requestData = config.data;
|
3298
|
-
const requestHeaders = AxiosHeaders$1.from(config.headers).normalize();
|
3299
|
-
let {responseType, withXSRFToken} = config;
|
3300
|
-
let onCanceled;
|
3301
|
-
function done() {
|
3302
|
-
if (config.cancelToken) {
|
3303
|
-
config.cancelToken.unsubscribe(onCanceled);
|
3304
|
-
}
|
3434
|
+
let {data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth} = newConfig;
|
3305
3435
|
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3436
|
+
newConfig.headers = headers = AxiosHeaders$1.from(headers);
|
3437
|
+
|
3438
|
+
newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url), config.params, config.paramsSerializer);
|
3439
|
+
|
3440
|
+
// HTTP basic authentication
|
3441
|
+
if (auth) {
|
3442
|
+
headers.set('Authorization', 'Basic ' +
|
3443
|
+
btoa((auth.username || '') + ':' + (auth.password ? unescape(encodeURIComponent(auth.password)) : ''))
|
3444
|
+
);
|
3445
|
+
}
|
3446
|
+
|
3447
|
+
let contentType;
|
3448
|
+
|
3449
|
+
if (utils$1.isFormData(data)) {
|
3450
|
+
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {
|
3451
|
+
headers.setContentType(undefined); // Let the browser set it
|
3452
|
+
} else if ((contentType = headers.getContentType()) !== false) {
|
3453
|
+
// fix semicolon duplication issue for ReactNative FormData implementation
|
3454
|
+
const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : [];
|
3455
|
+
headers.setContentType([type || 'multipart/form-data', ...tokens].join('; '));
|
3309
3456
|
}
|
3457
|
+
}
|
3458
|
+
|
3459
|
+
// Add xsrf header
|
3460
|
+
// This is only done if running in a standard browser environment.
|
3461
|
+
// Specifically not if we're in a web worker, or react-native.
|
3310
3462
|
|
3311
|
-
|
3463
|
+
if (platform.hasStandardBrowserEnv) {
|
3464
|
+
withXSRFToken && utils$1.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(newConfig));
|
3312
3465
|
|
3313
|
-
if (
|
3314
|
-
|
3315
|
-
|
3316
|
-
|
3317
|
-
|
3318
|
-
|
3319
|
-
requestHeaders.setContentType([type || 'multipart/form-data', ...tokens].join('; '));
|
3466
|
+
if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(newConfig.url))) {
|
3467
|
+
// Add xsrf header
|
3468
|
+
const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);
|
3469
|
+
|
3470
|
+
if (xsrfValue) {
|
3471
|
+
headers.set(xsrfHeaderName, xsrfValue);
|
3320
3472
|
}
|
3321
3473
|
}
|
3474
|
+
}
|
3322
3475
|
|
3323
|
-
|
3476
|
+
return newConfig;
|
3477
|
+
};
|
3324
3478
|
|
3325
|
-
|
3326
|
-
|
3327
|
-
|
3328
|
-
|
3329
|
-
|
3479
|
+
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
|
3480
|
+
|
3481
|
+
const xhrAdapter = isXHRAdapterSupported && function (config) {
|
3482
|
+
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
3483
|
+
const _config = resolveConfig(config);
|
3484
|
+
let requestData = _config.data;
|
3485
|
+
const requestHeaders = AxiosHeaders$1.from(_config.headers).normalize();
|
3486
|
+
let {responseType, onUploadProgress, onDownloadProgress} = _config;
|
3487
|
+
let onCanceled;
|
3488
|
+
let uploadThrottled, downloadThrottled;
|
3489
|
+
let flushUpload, flushDownload;
|
3490
|
+
|
3491
|
+
function done() {
|
3492
|
+
flushUpload && flushUpload(); // flush events
|
3493
|
+
flushDownload && flushDownload(); // flush events
|
3494
|
+
|
3495
|
+
_config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);
|
3496
|
+
|
3497
|
+
_config.signal && _config.signal.removeEventListener('abort', onCanceled);
|
3330
3498
|
}
|
3331
3499
|
|
3332
|
-
|
3500
|
+
let request = new XMLHttpRequest();
|
3333
3501
|
|
3334
|
-
request.open(
|
3502
|
+
request.open(_config.method.toUpperCase(), _config.url, true);
|
3335
3503
|
|
3336
3504
|
// Set the request timeout in MS
|
3337
|
-
request.timeout =
|
3505
|
+
request.timeout = _config.timeout;
|
3338
3506
|
|
3339
3507
|
function onloadend() {
|
3340
3508
|
if (!request) {
|
@@ -3414,10 +3582,10 @@ const xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
3414
3582
|
|
3415
3583
|
// Handle timeout
|
3416
3584
|
request.ontimeout = function handleTimeout() {
|
3417
|
-
let timeoutErrorMessage =
|
3418
|
-
const transitional =
|
3419
|
-
if (
|
3420
|
-
timeoutErrorMessage =
|
3585
|
+
let timeoutErrorMessage = _config.timeout ? 'timeout of ' + _config.timeout + 'ms exceeded' : 'timeout exceeded';
|
3586
|
+
const transitional = _config.transitional || transitionalDefaults;
|
3587
|
+
if (_config.timeoutErrorMessage) {
|
3588
|
+
timeoutErrorMessage = _config.timeoutErrorMessage;
|
3421
3589
|
}
|
3422
3590
|
reject(new AxiosError(
|
3423
3591
|
timeoutErrorMessage,
|
@@ -3429,22 +3597,6 @@ const xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
3429
3597
|
request = null;
|
3430
3598
|
};
|
3431
3599
|
|
3432
|
-
// Add xsrf header
|
3433
|
-
// This is only done if running in a standard browser environment.
|
3434
|
-
// Specifically not if we're in a web worker, or react-native.
|
3435
|
-
if(platform.hasStandardBrowserEnv) {
|
3436
|
-
withXSRFToken && utils$1.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config));
|
3437
|
-
|
3438
|
-
if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {
|
3439
|
-
// Add xsrf header
|
3440
|
-
const xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName);
|
3441
|
-
|
3442
|
-
if (xsrfValue) {
|
3443
|
-
requestHeaders.set(config.xsrfHeaderName, xsrfValue);
|
3444
|
-
}
|
3445
|
-
}
|
3446
|
-
}
|
3447
|
-
|
3448
3600
|
// Remove Content-Type if data is undefined
|
3449
3601
|
requestData === undefined && requestHeaders.setContentType(null);
|
3450
3602
|
|
@@ -3456,26 +3608,31 @@ const xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
3456
3608
|
}
|
3457
3609
|
|
3458
3610
|
// Add withCredentials to request if needed
|
3459
|
-
if (!utils$1.isUndefined(
|
3460
|
-
request.withCredentials = !!
|
3611
|
+
if (!utils$1.isUndefined(_config.withCredentials)) {
|
3612
|
+
request.withCredentials = !!_config.withCredentials;
|
3461
3613
|
}
|
3462
3614
|
|
3463
3615
|
// Add responseType to request if needed
|
3464
3616
|
if (responseType && responseType !== 'json') {
|
3465
|
-
request.responseType =
|
3617
|
+
request.responseType = _config.responseType;
|
3466
3618
|
}
|
3467
3619
|
|
3468
3620
|
// Handle progress if needed
|
3469
|
-
if (
|
3470
|
-
|
3621
|
+
if (onDownloadProgress) {
|
3622
|
+
([downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true));
|
3623
|
+
request.addEventListener('progress', downloadThrottled);
|
3471
3624
|
}
|
3472
3625
|
|
3473
3626
|
// Not all browsers support upload events
|
3474
|
-
if (
|
3475
|
-
|
3627
|
+
if (onUploadProgress && request.upload) {
|
3628
|
+
([uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress));
|
3629
|
+
|
3630
|
+
request.upload.addEventListener('progress', uploadThrottled);
|
3631
|
+
|
3632
|
+
request.upload.addEventListener('loadend', flushUpload);
|
3476
3633
|
}
|
3477
3634
|
|
3478
|
-
if (
|
3635
|
+
if (_config.cancelToken || _config.signal) {
|
3479
3636
|
// Handle cancellation
|
3480
3637
|
// eslint-disable-next-line func-names
|
3481
3638
|
onCanceled = cancel => {
|
@@ -3487,13 +3644,13 @@ const xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
3487
3644
|
request = null;
|
3488
3645
|
};
|
3489
3646
|
|
3490
|
-
|
3491
|
-
if (
|
3492
|
-
|
3647
|
+
_config.cancelToken && _config.cancelToken.subscribe(onCanceled);
|
3648
|
+
if (_config.signal) {
|
3649
|
+
_config.signal.aborted ? onCanceled() : _config.signal.addEventListener('abort', onCanceled);
|
3493
3650
|
}
|
3494
3651
|
}
|
3495
3652
|
|
3496
|
-
const protocol = parseProtocol(
|
3653
|
+
const protocol = parseProtocol(_config.url);
|
3497
3654
|
|
3498
3655
|
if (protocol && platform.protocols.indexOf(protocol) === -1) {
|
3499
3656
|
reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));
|
@@ -3506,9 +3663,339 @@ const xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
3506
3663
|
});
|
3507
3664
|
};
|
3508
3665
|
|
3666
|
+
const composeSignals = (signals, timeout) => {
|
3667
|
+
let controller = new AbortController();
|
3668
|
+
|
3669
|
+
let aborted;
|
3670
|
+
|
3671
|
+
const onabort = function (cancel) {
|
3672
|
+
if (!aborted) {
|
3673
|
+
aborted = true;
|
3674
|
+
unsubscribe();
|
3675
|
+
const err = cancel instanceof Error ? cancel : this.reason;
|
3676
|
+
controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));
|
3677
|
+
}
|
3678
|
+
};
|
3679
|
+
|
3680
|
+
let timer = timeout && setTimeout(() => {
|
3681
|
+
onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT));
|
3682
|
+
}, timeout);
|
3683
|
+
|
3684
|
+
const unsubscribe = () => {
|
3685
|
+
if (signals) {
|
3686
|
+
timer && clearTimeout(timer);
|
3687
|
+
timer = null;
|
3688
|
+
signals.forEach(signal => {
|
3689
|
+
signal &&
|
3690
|
+
(signal.removeEventListener ? signal.removeEventListener('abort', onabort) : signal.unsubscribe(onabort));
|
3691
|
+
});
|
3692
|
+
signals = null;
|
3693
|
+
}
|
3694
|
+
};
|
3695
|
+
|
3696
|
+
signals.forEach((signal) => signal && signal.addEventListener && signal.addEventListener('abort', onabort));
|
3697
|
+
|
3698
|
+
const {signal} = controller;
|
3699
|
+
|
3700
|
+
signal.unsubscribe = unsubscribe;
|
3701
|
+
|
3702
|
+
return [signal, () => {
|
3703
|
+
timer && clearTimeout(timer);
|
3704
|
+
timer = null;
|
3705
|
+
}];
|
3706
|
+
};
|
3707
|
+
|
3708
|
+
const composeSignals$1 = composeSignals;
|
3709
|
+
|
3710
|
+
const streamChunk = function* (chunk, chunkSize) {
|
3711
|
+
let len = chunk.byteLength;
|
3712
|
+
|
3713
|
+
if (!chunkSize || len < chunkSize) {
|
3714
|
+
yield chunk;
|
3715
|
+
return;
|
3716
|
+
}
|
3717
|
+
|
3718
|
+
let pos = 0;
|
3719
|
+
let end;
|
3720
|
+
|
3721
|
+
while (pos < len) {
|
3722
|
+
end = pos + chunkSize;
|
3723
|
+
yield chunk.slice(pos, end);
|
3724
|
+
pos = end;
|
3725
|
+
}
|
3726
|
+
};
|
3727
|
+
|
3728
|
+
const readBytes = async function* (iterable, chunkSize, encode) {
|
3729
|
+
for await (const chunk of iterable) {
|
3730
|
+
yield* streamChunk(ArrayBuffer.isView(chunk) ? chunk : (await encode(String(chunk))), chunkSize);
|
3731
|
+
}
|
3732
|
+
};
|
3733
|
+
|
3734
|
+
const trackStream = (stream, chunkSize, onProgress, onFinish, encode) => {
|
3735
|
+
const iterator = readBytes(stream, chunkSize, encode);
|
3736
|
+
|
3737
|
+
let bytes = 0;
|
3738
|
+
let done;
|
3739
|
+
let _onFinish = (e) => {
|
3740
|
+
if (!done) {
|
3741
|
+
done = true;
|
3742
|
+
onFinish && onFinish(e);
|
3743
|
+
}
|
3744
|
+
};
|
3745
|
+
|
3746
|
+
return new ReadableStream({
|
3747
|
+
async pull(controller) {
|
3748
|
+
try {
|
3749
|
+
const {done, value} = await iterator.next();
|
3750
|
+
|
3751
|
+
if (done) {
|
3752
|
+
_onFinish();
|
3753
|
+
controller.close();
|
3754
|
+
return;
|
3755
|
+
}
|
3756
|
+
|
3757
|
+
let len = value.byteLength;
|
3758
|
+
if (onProgress) {
|
3759
|
+
let loadedBytes = bytes += len;
|
3760
|
+
onProgress(loadedBytes);
|
3761
|
+
}
|
3762
|
+
controller.enqueue(new Uint8Array(value));
|
3763
|
+
} catch (err) {
|
3764
|
+
_onFinish(err);
|
3765
|
+
throw err;
|
3766
|
+
}
|
3767
|
+
},
|
3768
|
+
cancel(reason) {
|
3769
|
+
_onFinish(reason);
|
3770
|
+
return iterator.return();
|
3771
|
+
}
|
3772
|
+
}, {
|
3773
|
+
highWaterMark: 2
|
3774
|
+
})
|
3775
|
+
};
|
3776
|
+
|
3777
|
+
const isFetchSupported = typeof fetch === 'function' && typeof Request === 'function' && typeof Response === 'function';
|
3778
|
+
const isReadableStreamSupported = isFetchSupported && typeof ReadableStream === 'function';
|
3779
|
+
|
3780
|
+
// used only inside the fetch adapter
|
3781
|
+
const encodeText = isFetchSupported && (typeof TextEncoder === 'function' ?
|
3782
|
+
((encoder) => (str) => encoder.encode(str))(new TextEncoder()) :
|
3783
|
+
async (str) => new Uint8Array(await new Response(str).arrayBuffer())
|
3784
|
+
);
|
3785
|
+
|
3786
|
+
const test = (fn, ...args) => {
|
3787
|
+
try {
|
3788
|
+
return !!fn(...args);
|
3789
|
+
} catch (e) {
|
3790
|
+
return false
|
3791
|
+
}
|
3792
|
+
};
|
3793
|
+
|
3794
|
+
const supportsRequestStream = isReadableStreamSupported && test(() => {
|
3795
|
+
let duplexAccessed = false;
|
3796
|
+
|
3797
|
+
const hasContentType = new Request(platform.origin, {
|
3798
|
+
body: new ReadableStream(),
|
3799
|
+
method: 'POST',
|
3800
|
+
get duplex() {
|
3801
|
+
duplexAccessed = true;
|
3802
|
+
return 'half';
|
3803
|
+
},
|
3804
|
+
}).headers.has('Content-Type');
|
3805
|
+
|
3806
|
+
return duplexAccessed && !hasContentType;
|
3807
|
+
});
|
3808
|
+
|
3809
|
+
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
3810
|
+
|
3811
|
+
const supportsResponseStream = isReadableStreamSupported &&
|
3812
|
+
test(() => utils$1.isReadableStream(new Response('').body));
|
3813
|
+
|
3814
|
+
|
3815
|
+
const resolvers = {
|
3816
|
+
stream: supportsResponseStream && ((res) => res.body)
|
3817
|
+
};
|
3818
|
+
|
3819
|
+
isFetchSupported && (((res) => {
|
3820
|
+
['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => {
|
3821
|
+
!resolvers[type] && (resolvers[type] = utils$1.isFunction(res[type]) ? (res) => res[type]() :
|
3822
|
+
(_, config) => {
|
3823
|
+
throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config);
|
3824
|
+
});
|
3825
|
+
});
|
3826
|
+
})(new Response));
|
3827
|
+
|
3828
|
+
const getBodyLength = async (body) => {
|
3829
|
+
if (body == null) {
|
3830
|
+
return 0;
|
3831
|
+
}
|
3832
|
+
|
3833
|
+
if(utils$1.isBlob(body)) {
|
3834
|
+
return body.size;
|
3835
|
+
}
|
3836
|
+
|
3837
|
+
if(utils$1.isSpecCompliantForm(body)) {
|
3838
|
+
return (await new Request(body).arrayBuffer()).byteLength;
|
3839
|
+
}
|
3840
|
+
|
3841
|
+
if(utils$1.isArrayBufferView(body) || utils$1.isArrayBuffer(body)) {
|
3842
|
+
return body.byteLength;
|
3843
|
+
}
|
3844
|
+
|
3845
|
+
if(utils$1.isURLSearchParams(body)) {
|
3846
|
+
body = body + '';
|
3847
|
+
}
|
3848
|
+
|
3849
|
+
if(utils$1.isString(body)) {
|
3850
|
+
return (await encodeText(body)).byteLength;
|
3851
|
+
}
|
3852
|
+
};
|
3853
|
+
|
3854
|
+
const resolveBodyLength = async (headers, body) => {
|
3855
|
+
const length = utils$1.toFiniteNumber(headers.getContentLength());
|
3856
|
+
|
3857
|
+
return length == null ? getBodyLength(body) : length;
|
3858
|
+
};
|
3859
|
+
|
3860
|
+
const fetchAdapter = isFetchSupported && (async (config) => {
|
3861
|
+
let {
|
3862
|
+
url,
|
3863
|
+
method,
|
3864
|
+
data,
|
3865
|
+
signal,
|
3866
|
+
cancelToken,
|
3867
|
+
timeout,
|
3868
|
+
onDownloadProgress,
|
3869
|
+
onUploadProgress,
|
3870
|
+
responseType,
|
3871
|
+
headers,
|
3872
|
+
withCredentials = 'same-origin',
|
3873
|
+
fetchOptions
|
3874
|
+
} = resolveConfig(config);
|
3875
|
+
|
3876
|
+
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
|
3877
|
+
|
3878
|
+
let [composedSignal, stopTimeout] = (signal || cancelToken || timeout) ?
|
3879
|
+
composeSignals$1([signal, cancelToken], timeout) : [];
|
3880
|
+
|
3881
|
+
let finished, request;
|
3882
|
+
|
3883
|
+
const onFinish = () => {
|
3884
|
+
!finished && setTimeout(() => {
|
3885
|
+
composedSignal && composedSignal.unsubscribe();
|
3886
|
+
});
|
3887
|
+
|
3888
|
+
finished = true;
|
3889
|
+
};
|
3890
|
+
|
3891
|
+
let requestContentLength;
|
3892
|
+
|
3893
|
+
try {
|
3894
|
+
if (
|
3895
|
+
onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' &&
|
3896
|
+
(requestContentLength = await resolveBodyLength(headers, data)) !== 0
|
3897
|
+
) {
|
3898
|
+
let _request = new Request(url, {
|
3899
|
+
method: 'POST',
|
3900
|
+
body: data,
|
3901
|
+
duplex: "half"
|
3902
|
+
});
|
3903
|
+
|
3904
|
+
let contentTypeHeader;
|
3905
|
+
|
3906
|
+
if (utils$1.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
|
3907
|
+
headers.setContentType(contentTypeHeader);
|
3908
|
+
}
|
3909
|
+
|
3910
|
+
if (_request.body) {
|
3911
|
+
const [onProgress, flush] = progressEventDecorator(
|
3912
|
+
requestContentLength,
|
3913
|
+
progressEventReducer(asyncDecorator(onUploadProgress))
|
3914
|
+
);
|
3915
|
+
|
3916
|
+
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush, encodeText);
|
3917
|
+
}
|
3918
|
+
}
|
3919
|
+
|
3920
|
+
if (!utils$1.isString(withCredentials)) {
|
3921
|
+
withCredentials = withCredentials ? 'include' : 'omit';
|
3922
|
+
}
|
3923
|
+
|
3924
|
+
request = new Request(url, {
|
3925
|
+
...fetchOptions,
|
3926
|
+
signal: composedSignal,
|
3927
|
+
method: method.toUpperCase(),
|
3928
|
+
headers: headers.normalize().toJSON(),
|
3929
|
+
body: data,
|
3930
|
+
duplex: "half",
|
3931
|
+
credentials: withCredentials
|
3932
|
+
});
|
3933
|
+
|
3934
|
+
let response = await fetch(request);
|
3935
|
+
|
3936
|
+
const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');
|
3937
|
+
|
3938
|
+
if (supportsResponseStream && (onDownloadProgress || isStreamResponse)) {
|
3939
|
+
const options = {};
|
3940
|
+
|
3941
|
+
['status', 'statusText', 'headers'].forEach(prop => {
|
3942
|
+
options[prop] = response[prop];
|
3943
|
+
});
|
3944
|
+
|
3945
|
+
const responseContentLength = utils$1.toFiniteNumber(response.headers.get('content-length'));
|
3946
|
+
|
3947
|
+
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
|
3948
|
+
responseContentLength,
|
3949
|
+
progressEventReducer(asyncDecorator(onDownloadProgress), true)
|
3950
|
+
) || [];
|
3951
|
+
|
3952
|
+
response = new Response(
|
3953
|
+
trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
|
3954
|
+
flush && flush();
|
3955
|
+
isStreamResponse && onFinish();
|
3956
|
+
}, encodeText),
|
3957
|
+
options
|
3958
|
+
);
|
3959
|
+
}
|
3960
|
+
|
3961
|
+
responseType = responseType || 'text';
|
3962
|
+
|
3963
|
+
let responseData = await resolvers[utils$1.findKey(resolvers, responseType) || 'text'](response, config);
|
3964
|
+
|
3965
|
+
!isStreamResponse && onFinish();
|
3966
|
+
|
3967
|
+
stopTimeout && stopTimeout();
|
3968
|
+
|
3969
|
+
return await new Promise((resolve, reject) => {
|
3970
|
+
settle(resolve, reject, {
|
3971
|
+
data: responseData,
|
3972
|
+
headers: AxiosHeaders$1.from(response.headers),
|
3973
|
+
status: response.status,
|
3974
|
+
statusText: response.statusText,
|
3975
|
+
config,
|
3976
|
+
request
|
3977
|
+
});
|
3978
|
+
})
|
3979
|
+
} catch (err) {
|
3980
|
+
onFinish();
|
3981
|
+
|
3982
|
+
if (err && err.name === 'TypeError' && /fetch/i.test(err.message)) {
|
3983
|
+
throw Object.assign(
|
3984
|
+
new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request),
|
3985
|
+
{
|
3986
|
+
cause: err.cause || err
|
3987
|
+
}
|
3988
|
+
)
|
3989
|
+
}
|
3990
|
+
|
3991
|
+
throw AxiosError.from(err, err && err.code, config, request);
|
3992
|
+
}
|
3993
|
+
});
|
3994
|
+
|
3509
3995
|
const knownAdapters = {
|
3510
3996
|
http: httpAdapter,
|
3511
|
-
xhr: xhrAdapter
|
3997
|
+
xhr: xhrAdapter,
|
3998
|
+
fetch: fetchAdapter
|
3512
3999
|
};
|
3513
4000
|
|
3514
4001
|
utils$1.forEach(knownAdapters, (fn, value) => {
|
@@ -3652,108 +4139,6 @@ function dispatchRequest(config) {
|
|
3652
4139
|
});
|
3653
4140
|
}
|
3654
4141
|
|
3655
|
-
const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? thing.toJSON() : thing;
|
3656
|
-
|
3657
|
-
/**
|
3658
|
-
* Config-specific merge-function which creates a new config-object
|
3659
|
-
* by merging two configuration objects together.
|
3660
|
-
*
|
3661
|
-
* @param {Object} config1
|
3662
|
-
* @param {Object} config2
|
3663
|
-
*
|
3664
|
-
* @returns {Object} New object resulting from merging config2 to config1
|
3665
|
-
*/
|
3666
|
-
function mergeConfig(config1, config2) {
|
3667
|
-
// eslint-disable-next-line no-param-reassign
|
3668
|
-
config2 = config2 || {};
|
3669
|
-
const config = {};
|
3670
|
-
|
3671
|
-
function getMergedValue(target, source, caseless) {
|
3672
|
-
if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) {
|
3673
|
-
return utils$1.merge.call({caseless}, target, source);
|
3674
|
-
} else if (utils$1.isPlainObject(source)) {
|
3675
|
-
return utils$1.merge({}, source);
|
3676
|
-
} else if (utils$1.isArray(source)) {
|
3677
|
-
return source.slice();
|
3678
|
-
}
|
3679
|
-
return source;
|
3680
|
-
}
|
3681
|
-
|
3682
|
-
// eslint-disable-next-line consistent-return
|
3683
|
-
function mergeDeepProperties(a, b, caseless) {
|
3684
|
-
if (!utils$1.isUndefined(b)) {
|
3685
|
-
return getMergedValue(a, b, caseless);
|
3686
|
-
} else if (!utils$1.isUndefined(a)) {
|
3687
|
-
return getMergedValue(undefined, a, caseless);
|
3688
|
-
}
|
3689
|
-
}
|
3690
|
-
|
3691
|
-
// eslint-disable-next-line consistent-return
|
3692
|
-
function valueFromConfig2(a, b) {
|
3693
|
-
if (!utils$1.isUndefined(b)) {
|
3694
|
-
return getMergedValue(undefined, b);
|
3695
|
-
}
|
3696
|
-
}
|
3697
|
-
|
3698
|
-
// eslint-disable-next-line consistent-return
|
3699
|
-
function defaultToConfig2(a, b) {
|
3700
|
-
if (!utils$1.isUndefined(b)) {
|
3701
|
-
return getMergedValue(undefined, b);
|
3702
|
-
} else if (!utils$1.isUndefined(a)) {
|
3703
|
-
return getMergedValue(undefined, a);
|
3704
|
-
}
|
3705
|
-
}
|
3706
|
-
|
3707
|
-
// eslint-disable-next-line consistent-return
|
3708
|
-
function mergeDirectKeys(a, b, prop) {
|
3709
|
-
if (prop in config2) {
|
3710
|
-
return getMergedValue(a, b);
|
3711
|
-
} else if (prop in config1) {
|
3712
|
-
return getMergedValue(undefined, a);
|
3713
|
-
}
|
3714
|
-
}
|
3715
|
-
|
3716
|
-
const mergeMap = {
|
3717
|
-
url: valueFromConfig2,
|
3718
|
-
method: valueFromConfig2,
|
3719
|
-
data: valueFromConfig2,
|
3720
|
-
baseURL: defaultToConfig2,
|
3721
|
-
transformRequest: defaultToConfig2,
|
3722
|
-
transformResponse: defaultToConfig2,
|
3723
|
-
paramsSerializer: defaultToConfig2,
|
3724
|
-
timeout: defaultToConfig2,
|
3725
|
-
timeoutMessage: defaultToConfig2,
|
3726
|
-
withCredentials: defaultToConfig2,
|
3727
|
-
withXSRFToken: defaultToConfig2,
|
3728
|
-
adapter: defaultToConfig2,
|
3729
|
-
responseType: defaultToConfig2,
|
3730
|
-
xsrfCookieName: defaultToConfig2,
|
3731
|
-
xsrfHeaderName: defaultToConfig2,
|
3732
|
-
onUploadProgress: defaultToConfig2,
|
3733
|
-
onDownloadProgress: defaultToConfig2,
|
3734
|
-
decompress: defaultToConfig2,
|
3735
|
-
maxContentLength: defaultToConfig2,
|
3736
|
-
maxBodyLength: defaultToConfig2,
|
3737
|
-
beforeRedirect: defaultToConfig2,
|
3738
|
-
transport: defaultToConfig2,
|
3739
|
-
httpAgent: defaultToConfig2,
|
3740
|
-
httpsAgent: defaultToConfig2,
|
3741
|
-
cancelToken: defaultToConfig2,
|
3742
|
-
socketPath: defaultToConfig2,
|
3743
|
-
responseEncoding: defaultToConfig2,
|
3744
|
-
validateStatus: mergeDirectKeys,
|
3745
|
-
headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true)
|
3746
|
-
};
|
3747
|
-
|
3748
|
-
utils$1.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) {
|
3749
|
-
const merge = mergeMap[prop] || mergeDeepProperties;
|
3750
|
-
const configValue = merge(config1[prop], config2[prop], prop);
|
3751
|
-
(utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
3752
|
-
});
|
3753
|
-
|
3754
|
-
return config;
|
3755
|
-
}
|
3756
|
-
|
3757
4142
|
const validators$1 = {};
|
3758
4143
|
|
3759
4144
|
// eslint-disable-next-line func-names
|
@@ -3878,12 +4263,15 @@ class Axios {
|
|
3878
4263
|
|
3879
4264
|
// slice off the Error: ... line
|
3880
4265
|
const stack = dummy.stack ? dummy.stack.replace(/^.+\n/, '') : '';
|
3881
|
-
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3885
|
-
|
3886
|
-
|
4266
|
+
try {
|
4267
|
+
if (!err.stack) {
|
4268
|
+
err.stack = stack;
|
4269
|
+
// match without the 2 top stack lines
|
4270
|
+
} else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\n.+\n/, ''))) {
|
4271
|
+
err.stack += '\n' + stack;
|
4272
|
+
}
|
4273
|
+
} catch (e) {
|
4274
|
+
// ignore the case where "stack" is an un-writable property
|
3887
4275
|
}
|
3888
4276
|
}
|
3889
4277
|
|