@zuplo/cli 6.70.70 → 6.71.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.
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/http2.d.ts +1 -0
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-GEVKFSKR.js → chunk-AZIRK6TC.js} +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-GEVKFSKR.js.map → chunk-AZIRK6TC.js.map} +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-MJPI3GFA.js → chunk-E7U425SB.js} +72 -72
- package/node_modules/@zuplo/runtime/out/esm/chunk-E7U425SB.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/index.js.map +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +7 -7
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js.map +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +61 -0
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/acorn/CHANGELOG.md +14 -0
- package/node_modules/acorn/README.md +3 -0
- package/node_modules/acorn/dist/acorn.d.mts +6 -0
- package/node_modules/acorn/dist/acorn.d.ts +6 -0
- package/node_modules/acorn/dist/acorn.js +87 -49
- package/node_modules/acorn/dist/acorn.mjs +87 -49
- package/node_modules/acorn/package.json +2 -2
- package/node_modules/axios/CHANGELOG.md +52 -1
- package/node_modules/axios/README.md +30 -2
- package/node_modules/axios/dist/axios.js +350 -134
- package/node_modules/axios/dist/axios.min.js +3 -3
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +355 -90
- package/node_modules/axios/dist/esm/axios.js +355 -90
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +399 -104
- package/node_modules/axios/index.d.cts +2 -0
- package/node_modules/axios/index.d.ts +2 -0
- package/node_modules/axios/lib/adapters/fetch.js +113 -37
- package/node_modules/axios/lib/adapters/http.js +132 -43
- package/node_modules/axios/lib/core/Axios.js +3 -2
- package/node_modules/axios/lib/core/AxiosHeaders.js +10 -7
- package/node_modules/axios/lib/core/buildFullPath.js +29 -1
- package/node_modules/axios/lib/core/mergeConfig.js +34 -0
- package/node_modules/axios/lib/defaults/transitional.js +1 -0
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/buildURL.js +5 -3
- package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +16 -11
- package/node_modules/axios/lib/helpers/formDataToJSON.js +25 -3
- package/node_modules/axios/lib/helpers/resolveConfig.js +5 -3
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +33 -1
- package/node_modules/axios/lib/helpers/toFormData.js +40 -10
- package/node_modules/axios/lib/utils.js +75 -11
- package/node_modules/axios/package.json +1 -1
- package/node_modules/form-data/CHANGELOG.md +29 -2
- package/node_modules/form-data/README.md +4 -4
- package/node_modules/form-data/lib/form_data.js +14 -2
- package/node_modules/form-data/package.json +7 -7
- package/node_modules/protobufjs/dist/light/protobuf.js +145 -188
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +33 -76
- package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.js +165 -208
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/index.d.ts +0 -8
- package/node_modules/protobufjs/package.json +2 -3
- package/node_modules/protobufjs/src/util/minimal.js +0 -3
- package/package.json +6 -6
- package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
- package/node_modules/@protobufjs/inquire/LICENSE +0 -26
- package/node_modules/@protobufjs/inquire/README.md +0 -13
- package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
- package/node_modules/@protobufjs/inquire/index.js +0 -38
- package/node_modules/@protobufjs/inquire/package.json +0 -21
- package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
- package/node_modules/@zuplo/runtime/out/esm/chunk-MJPI3GFA.js.map +0 -1
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-MJPI3GFA.js.LEGAL.txt → chunk-E7U425SB.js.LEGAL.txt} +0 -0
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
import AxiosError from './AxiosError.js';
|
|
3
4
|
import isAbsoluteURL from '../helpers/isAbsoluteURL.js';
|
|
4
5
|
import combineURLs from '../helpers/combineURLs.js';
|
|
5
6
|
|
|
7
|
+
const malformedHttpProtocol = /^https?:(?!\/\/)/i;
|
|
8
|
+
const httpProtocolControlCharacters = /[\t\n\r]/g;
|
|
9
|
+
|
|
10
|
+
function stripLeadingC0ControlOrSpace(url) {
|
|
11
|
+
let i = 0;
|
|
12
|
+
while (i < url.length && url.charCodeAt(i) <= 0x20) {
|
|
13
|
+
i++;
|
|
14
|
+
}
|
|
15
|
+
return url.slice(i);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function normalizeURLForProtocolCheck(url) {
|
|
19
|
+
return stripLeadingC0ControlOrSpace(url).replace(httpProtocolControlCharacters, '');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function assertValidHttpProtocolURL(url, config) {
|
|
23
|
+
if (typeof url === 'string' && malformedHttpProtocol.test(normalizeURLForProtocolCheck(url))) {
|
|
24
|
+
throw new AxiosError(
|
|
25
|
+
'Invalid URL: missing "//" after protocol',
|
|
26
|
+
AxiosError.ERR_INVALID_URL,
|
|
27
|
+
config
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
6
32
|
/**
|
|
7
33
|
* Creates a new URL by combining the baseURL with the requestedURL,
|
|
8
34
|
* only when the requestedURL is not already an absolute URL.
|
|
@@ -13,9 +39,11 @@ import combineURLs from '../helpers/combineURLs.js';
|
|
|
13
39
|
*
|
|
14
40
|
* @returns {string} The combined full path
|
|
15
41
|
*/
|
|
16
|
-
export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
|
42
|
+
export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls, config) {
|
|
43
|
+
assertValidHttpProtocolURL(requestedURL, config);
|
|
17
44
|
let isRelativeUrl = !isAbsoluteURL(requestedURL);
|
|
18
45
|
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
|
46
|
+
assertValidHttpProtocolURL(baseURL, config);
|
|
19
47
|
return combineURLs(baseURL, requestedURL);
|
|
20
48
|
}
|
|
21
49
|
return requestedURL;
|
|
@@ -68,6 +68,28 @@ export default function mergeConfig(config1, config2) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function getMergedTransitionalOption(prop) {
|
|
72
|
+
const transitional2 = utils.hasOwnProp(config2, 'transitional') ? config2.transitional : undefined;
|
|
73
|
+
|
|
74
|
+
if (!utils.isUndefined(transitional2)) {
|
|
75
|
+
if (utils.isPlainObject(transitional2)) {
|
|
76
|
+
if (utils.hasOwnProp(transitional2, prop)) {
|
|
77
|
+
return transitional2[prop];
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const transitional1 = utils.hasOwnProp(config1, 'transitional') ? config1.transitional : undefined;
|
|
85
|
+
|
|
86
|
+
if (utils.isPlainObject(transitional1) && utils.hasOwnProp(transitional1, prop)) {
|
|
87
|
+
return transitional1[prop];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
71
93
|
// eslint-disable-next-line consistent-return
|
|
72
94
|
function mergeDirectKeys(a, b, prop) {
|
|
73
95
|
if (utils.hasOwnProp(config2, prop)) {
|
|
@@ -120,5 +142,17 @@ export default function mergeConfig(config1, config2) {
|
|
|
120
142
|
(utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
|
121
143
|
});
|
|
122
144
|
|
|
145
|
+
if (
|
|
146
|
+
utils.hasOwnProp(config2, 'validateStatus') &&
|
|
147
|
+
utils.isUndefined(config2.validateStatus) &&
|
|
148
|
+
getMergedTransitionalOption('validateStatusUndefinedResolves') === false
|
|
149
|
+
) {
|
|
150
|
+
if (utils.hasOwnProp(config1, 'validateStatus')) {
|
|
151
|
+
config.validateStatus = getMergedValue(undefined, config1.validateStatus);
|
|
152
|
+
} else {
|
|
153
|
+
delete config.validateStatus;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
123
157
|
return config;
|
|
124
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "1.
|
|
1
|
+
export const VERSION = "1.18.0";
|
|
@@ -33,15 +33,17 @@ export default function buildURL(url, params, options) {
|
|
|
33
33
|
return url;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const _encode = (options && options.encode) || encode;
|
|
37
|
-
|
|
38
36
|
const _options = utils.isFunction(options)
|
|
39
37
|
? {
|
|
40
38
|
serialize: options,
|
|
41
39
|
}
|
|
42
40
|
: options;
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
// Read serializer options pollution-safely: own properties and methods on a
|
|
43
|
+
// class/template prototype are honored, but values injected onto a polluted
|
|
44
|
+
// Object.prototype are ignored.
|
|
45
|
+
const _encode = utils.getSafeProp(_options, 'encode') || encode;
|
|
46
|
+
const serializeFn = utils.getSafeProp(_options, 'serialize');
|
|
45
47
|
|
|
46
48
|
let serializedParams;
|
|
47
49
|
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
* Estimate decoded byte length of a data:// URL *without* allocating large buffers.
|
|
3
3
|
* - For base64: compute exact decoded size using length and padding;
|
|
4
4
|
* handle %XX at the character-count level (no string allocation).
|
|
5
|
-
* - For non-base64:
|
|
5
|
+
* - For non-base64: compute the exact percent-decoded UTF-8 byte length.
|
|
6
6
|
*
|
|
7
7
|
* @param {string} url
|
|
8
8
|
* @returns {number}
|
|
9
9
|
*/
|
|
10
|
+
const isHexDigit = (charCode) =>
|
|
11
|
+
(charCode >= 48 && charCode <= 57) ||
|
|
12
|
+
(charCode >= 65 && charCode <= 70) ||
|
|
13
|
+
(charCode >= 97 && charCode <= 102);
|
|
14
|
+
|
|
15
|
+
const isPercentEncodedByte = (str, i, len) =>
|
|
16
|
+
i + 2 < len && isHexDigit(str.charCodeAt(i + 1)) && isHexDigit(str.charCodeAt(i + 2));
|
|
17
|
+
|
|
10
18
|
export default function estimateDataURLDecodedBytes(url) {
|
|
11
19
|
if (!url || typeof url !== 'string') return 0;
|
|
12
20
|
if (!url.startsWith('data:')) return 0;
|
|
@@ -26,9 +34,7 @@ export default function estimateDataURLDecodedBytes(url) {
|
|
|
26
34
|
if (body.charCodeAt(i) === 37 /* '%' */ && i + 2 < len) {
|
|
27
35
|
const a = body.charCodeAt(i + 1);
|
|
28
36
|
const b = body.charCodeAt(i + 2);
|
|
29
|
-
const isHex =
|
|
30
|
-
((a >= 48 && a <= 57) || (a >= 65 && a <= 70) || (a >= 97 && a <= 102)) &&
|
|
31
|
-
((b >= 48 && b <= 57) || (b >= 65 && b <= 70) || (b >= 97 && b <= 102));
|
|
37
|
+
const isHex = isHexDigit(a) && isHexDigit(b);
|
|
32
38
|
|
|
33
39
|
if (isHex) {
|
|
34
40
|
effectiveLen -= 2;
|
|
@@ -69,18 +75,17 @@ export default function estimateDataURLDecodedBytes(url) {
|
|
|
69
75
|
return bytes > 0 ? bytes : 0;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
if (typeof Buffer !== 'undefined' && typeof Buffer.byteLength === 'function') {
|
|
73
|
-
return Buffer.byteLength(body, 'utf8');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
78
|
// Compute UTF-8 byte length directly from UTF-16 code units without allocating
|
|
77
79
|
// a byte buffer (TextEncoder.encode would defeat the DoS guard on large bodies).
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
+
// Valid %XX triplets count as one decoded byte; this matches the bytes that
|
|
81
|
+
// decodeURIComponent(body) would produce before Buffer re-encodes the string.
|
|
80
82
|
let bytes = 0;
|
|
81
83
|
for (let i = 0, len = body.length; i < len; i++) {
|
|
82
84
|
const c = body.charCodeAt(i);
|
|
83
|
-
if (c
|
|
85
|
+
if (c === 37 /* '%' */ && isPercentEncodedByte(body, i, len)) {
|
|
86
|
+
bytes += 1;
|
|
87
|
+
i += 2;
|
|
88
|
+
} else if (c < 0x80) {
|
|
84
89
|
bytes += 1;
|
|
85
90
|
} else if (c < 0x800) {
|
|
86
91
|
bytes += 2;
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import utils from '../utils.js';
|
|
4
|
+
import AxiosError from '../core/AxiosError.js';
|
|
5
|
+
import { DEFAULT_FORM_DATA_MAX_DEPTH } from './toFormData.js';
|
|
6
|
+
|
|
7
|
+
const MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
8
|
+
|
|
9
|
+
function throwIfDepthExceeded(index) {
|
|
10
|
+
if (index > MAX_DEPTH) {
|
|
11
|
+
throw new AxiosError(
|
|
12
|
+
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH,
|
|
13
|
+
AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
/**
|
|
6
19
|
* It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z']
|
|
@@ -14,9 +27,16 @@ function parsePropPath(name) {
|
|
|
14
27
|
// foo.x.y.z
|
|
15
28
|
// foo-x-y-z
|
|
16
29
|
// foo x y z
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
const path = [];
|
|
31
|
+
const pattern = /\w+|\[(\w*)]/g;
|
|
32
|
+
let match;
|
|
33
|
+
|
|
34
|
+
while ((match = pattern.exec(name)) !== null) {
|
|
35
|
+
throwIfDepthExceeded(path.length);
|
|
36
|
+
path.push(match[0] === '[]' ? '' : match[1] || match[0]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return path;
|
|
20
40
|
}
|
|
21
41
|
|
|
22
42
|
/**
|
|
@@ -48,6 +68,8 @@ function arrayToObject(arr) {
|
|
|
48
68
|
*/
|
|
49
69
|
function formDataToJSON(formData) {
|
|
50
70
|
function buildPath(path, value, target, index) {
|
|
71
|
+
throwIfDepthExceeded(index);
|
|
72
|
+
|
|
51
73
|
let name = path[index++];
|
|
52
74
|
|
|
53
75
|
if (name === '__proto__') return true;
|
|
@@ -55,17 +55,19 @@ function resolveConfig(config) {
|
|
|
55
55
|
newConfig.headers = headers = AxiosHeaders.from(headers);
|
|
56
56
|
|
|
57
57
|
newConfig.url = buildURL(
|
|
58
|
-
buildFullPath(baseURL, url, allowAbsoluteUrls),
|
|
58
|
+
buildFullPath(baseURL, url, allowAbsoluteUrls, newConfig),
|
|
59
59
|
own('params'),
|
|
60
60
|
own('paramsSerializer')
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
// HTTP basic authentication
|
|
64
64
|
if (auth) {
|
|
65
|
+
const username = utils.getSafeProp(auth, 'username') || '';
|
|
66
|
+
const password = utils.getSafeProp(auth, 'password') || '';
|
|
67
|
+
|
|
65
68
|
headers.set(
|
|
66
69
|
'Authorization',
|
|
67
|
-
'Basic ' +
|
|
68
|
-
btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : ''))
|
|
70
|
+
'Basic ' + btoa(username + ':' + (password ? encodeUTF8(password) : ''))
|
|
69
71
|
);
|
|
70
72
|
}
|
|
71
73
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const LOOPBACK_HOSTNAMES = new Set(['localhost']);
|
|
1
|
+
const LOOPBACK_HOSTNAMES = new Set(['localhost', '0.0.0.0']);
|
|
2
2
|
|
|
3
3
|
const isIPv4Loopback = (host) => {
|
|
4
4
|
const parts = host.split('.');
|
|
@@ -7,6 +7,37 @@ const isIPv4Loopback = (host) => {
|
|
|
7
7
|
return parts.every((p) => /^\d+$/.test(p) && Number(p) >= 0 && Number(p) <= 255);
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
const isIPv6ZeroGroup = (group) => /^0{1,4}$/.test(group);
|
|
11
|
+
|
|
12
|
+
// The unspecified address (IPv4 0.0.0.0 / IPv6 ::) resolves to the local host
|
|
13
|
+
// for outbound connections, so treat it as loopback-equivalent for NO_PROXY
|
|
14
|
+
// matching. 0.0.0.0 is covered by LOOPBACK_HOSTNAMES; this handles compressed
|
|
15
|
+
// and full IPv6 all-zero forms so both families bypass symmetrically.
|
|
16
|
+
const isIPv6Unspecified = (host) => {
|
|
17
|
+
if (host === '::') return true;
|
|
18
|
+
|
|
19
|
+
const compressionIndex = host.indexOf('::');
|
|
20
|
+
|
|
21
|
+
if (compressionIndex !== -1) {
|
|
22
|
+
if (compressionIndex !== host.lastIndexOf('::')) return false;
|
|
23
|
+
|
|
24
|
+
const left = host.slice(0, compressionIndex);
|
|
25
|
+
const right = host.slice(compressionIndex + 2);
|
|
26
|
+
const leftGroups = left ? left.split(':') : [];
|
|
27
|
+
const rightGroups = right ? right.split(':') : [];
|
|
28
|
+
const explicitGroups = leftGroups.length + rightGroups.length;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
explicitGroups < 8 &&
|
|
32
|
+
leftGroups.every(isIPv6ZeroGroup) &&
|
|
33
|
+
rightGroups.every(isIPv6ZeroGroup)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const groups = host.split(':');
|
|
38
|
+
return groups.length === 8 && groups.every(isIPv6ZeroGroup);
|
|
39
|
+
};
|
|
40
|
+
|
|
10
41
|
const isIPv6Loopback = (host) => {
|
|
11
42
|
// Collapse all-zero groups: any form of ::1 / 0:0:...:0:1
|
|
12
43
|
// First, strip any leading "::" by normalising with Set lookup of common forms,
|
|
@@ -42,6 +73,7 @@ const isLoopback = (host) => {
|
|
|
42
73
|
if (!host) return false;
|
|
43
74
|
if (LOOPBACK_HOSTNAMES.has(host)) return true;
|
|
44
75
|
if (isIPv4Loopback(host)) return true;
|
|
76
|
+
if (isIPv6Unspecified(host)) return true;
|
|
45
77
|
return isIPv6Loopback(host);
|
|
46
78
|
};
|
|
47
79
|
|
|
@@ -5,6 +5,10 @@ import AxiosError from '../core/AxiosError.js';
|
|
|
5
5
|
// temporary hotfix to avoid circular references until AxiosURLSearchParams is refactored
|
|
6
6
|
import PlatformFormData from '../platform/node/classes/FormData.js';
|
|
7
7
|
|
|
8
|
+
// Default nesting limit shared with the inverse transform (formDataToJSON) so
|
|
9
|
+
// the FormData <-> JSON round-trip stays symmetric.
|
|
10
|
+
export const DEFAULT_FORM_DATA_MAX_DEPTH = 100;
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* Determines if the given thing is a array or js object.
|
|
10
14
|
*
|
|
@@ -115,8 +119,9 @@ function toFormData(obj, formData, options) {
|
|
|
115
119
|
const dots = options.dots;
|
|
116
120
|
const indexes = options.indexes;
|
|
117
121
|
const _Blob = options.Blob || (typeof Blob !== 'undefined' && Blob);
|
|
118
|
-
const maxDepth = options.maxDepth === undefined ?
|
|
122
|
+
const maxDepth = options.maxDepth === undefined ? DEFAULT_FORM_DATA_MAX_DEPTH : options.maxDepth;
|
|
119
123
|
const useBlob = _Blob && utils.isSpecCompliantForm(formData);
|
|
124
|
+
const stack = [];
|
|
120
125
|
|
|
121
126
|
if (!utils.isFunction(visitor)) {
|
|
122
127
|
throw new TypeError('visitor must be a function');
|
|
@@ -144,6 +149,38 @@ function toFormData(obj, formData, options) {
|
|
|
144
149
|
return value;
|
|
145
150
|
}
|
|
146
151
|
|
|
152
|
+
function throwIfMaxDepthExceeded(depth) {
|
|
153
|
+
if (depth > maxDepth) {
|
|
154
|
+
throw new AxiosError(
|
|
155
|
+
'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth,
|
|
156
|
+
AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function stringifyWithDepthLimit(value, depth) {
|
|
162
|
+
if (maxDepth === Infinity) {
|
|
163
|
+
return JSON.stringify(value);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const ancestors = [];
|
|
167
|
+
|
|
168
|
+
return JSON.stringify(value, function limitDepth(_key, currentValue) {
|
|
169
|
+
if (!utils.isObject(currentValue)) {
|
|
170
|
+
return currentValue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
while (ancestors.length && ancestors[ancestors.length - 1] !== this) {
|
|
174
|
+
ancestors.pop();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
ancestors.push(currentValue);
|
|
178
|
+
throwIfMaxDepthExceeded(depth + ancestors.length - 1);
|
|
179
|
+
|
|
180
|
+
return currentValue;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
147
184
|
/**
|
|
148
185
|
* Default visitor.
|
|
149
186
|
*
|
|
@@ -167,7 +204,7 @@ function toFormData(obj, formData, options) {
|
|
|
167
204
|
// eslint-disable-next-line no-param-reassign
|
|
168
205
|
key = metaTokens ? key : key.slice(0, -2);
|
|
169
206
|
// eslint-disable-next-line no-param-reassign
|
|
170
|
-
value =
|
|
207
|
+
value = stringifyWithDepthLimit(value, 1);
|
|
171
208
|
} else if (
|
|
172
209
|
(utils.isArray(value) && isFlatArray(value)) ||
|
|
173
210
|
((utils.isFileList(value) || utils.endsWith(key, '[]')) && (arr = utils.toArray(value)))
|
|
@@ -200,8 +237,6 @@ function toFormData(obj, formData, options) {
|
|
|
200
237
|
return false;
|
|
201
238
|
}
|
|
202
239
|
|
|
203
|
-
const stack = [];
|
|
204
|
-
|
|
205
240
|
const exposedHelpers = Object.assign(predicates, {
|
|
206
241
|
defaultVisitor,
|
|
207
242
|
convertValue,
|
|
@@ -211,12 +246,7 @@ function toFormData(obj, formData, options) {
|
|
|
211
246
|
function build(value, path, depth = 0) {
|
|
212
247
|
if (utils.isUndefined(value)) return;
|
|
213
248
|
|
|
214
|
-
|
|
215
|
-
throw new AxiosError(
|
|
216
|
-
'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth,
|
|
217
|
-
AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
218
|
-
);
|
|
219
|
-
}
|
|
249
|
+
throwIfMaxDepthExceeded(depth);
|
|
220
250
|
|
|
221
251
|
if (stack.indexOf(value) !== -1) {
|
|
222
252
|
throw new Error('Circular reference detected in ' + path.join('.'));
|
|
@@ -8,6 +8,57 @@ const { toString } = Object.prototype;
|
|
|
8
8
|
const { getPrototypeOf } = Object;
|
|
9
9
|
const { iterator, toStringTag } = Symbol;
|
|
10
10
|
|
|
11
|
+
/* Creating a function that will check if an object has a property. */
|
|
12
|
+
const hasOwnProperty = (
|
|
13
|
+
({ hasOwnProperty }) =>
|
|
14
|
+
(obj, prop) =>
|
|
15
|
+
hasOwnProperty.call(obj, prop)
|
|
16
|
+
)(Object.prototype);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Walk the prototype chain (excluding the shared Object.prototype) looking for
|
|
20
|
+
* an own `prop`. This distinguishes genuine own/inherited members — including
|
|
21
|
+
* class accessors and template prototypes — from members injected via
|
|
22
|
+
* Object.prototype pollution (e.g. `Object.prototype.username = '...'`), which
|
|
23
|
+
* live on Object.prototype itself and are therefore never matched.
|
|
24
|
+
*
|
|
25
|
+
* @param {*} thing The value whose chain to inspect
|
|
26
|
+
* @param {string|symbol} prop The property key to look for
|
|
27
|
+
*
|
|
28
|
+
* @returns {boolean} True when `prop` is owned below Object.prototype
|
|
29
|
+
*/
|
|
30
|
+
const hasOwnInPrototypeChain = (thing, prop) => {
|
|
31
|
+
let obj = thing;
|
|
32
|
+
const seen = [];
|
|
33
|
+
|
|
34
|
+
while (obj != null && obj !== Object.prototype) {
|
|
35
|
+
if (seen.indexOf(obj) !== -1) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
seen.push(obj);
|
|
39
|
+
|
|
40
|
+
if (hasOwnProperty(obj, prop)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
obj = getPrototypeOf(obj);
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Read `obj[prop]` only when it is safe from Object.prototype pollution. Own
|
|
50
|
+
* properties and members inherited from a non-Object.prototype source (a class
|
|
51
|
+
* instance or template object) are honored; a value reachable only through a
|
|
52
|
+
* polluted Object.prototype is ignored and `undefined` is returned.
|
|
53
|
+
*
|
|
54
|
+
* @param {*} obj The source object
|
|
55
|
+
* @param {string|symbol} prop The property key to read
|
|
56
|
+
*
|
|
57
|
+
* @returns {*} The resolved value, or undefined when unsafe/absent
|
|
58
|
+
*/
|
|
59
|
+
const getSafeProp = (obj, prop) =>
|
|
60
|
+
obj != null && hasOwnInPrototypeChain(obj, prop) ? obj[prop] : undefined;
|
|
61
|
+
|
|
11
62
|
const kindOf = ((cache) => (thing) => {
|
|
12
63
|
const str = toString.call(thing);
|
|
13
64
|
return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
|
|
@@ -133,7 +184,7 @@ const isBoolean = (thing) => thing === true || thing === false;
|
|
|
133
184
|
* @returns {boolean} True if value is a plain Object, otherwise false
|
|
134
185
|
*/
|
|
135
186
|
const isPlainObject = (val) => {
|
|
136
|
-
if (
|
|
187
|
+
if (!isObject(val)) {
|
|
137
188
|
return false;
|
|
138
189
|
}
|
|
139
190
|
|
|
@@ -141,9 +192,12 @@ const isPlainObject = (val) => {
|
|
|
141
192
|
return (
|
|
142
193
|
(prototype === null ||
|
|
143
194
|
prototype === Object.prototype ||
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
195
|
+
getPrototypeOf(prototype) === null) &&
|
|
196
|
+
// Treat any genuine (non-Object.prototype-polluted) Symbol.toStringTag or
|
|
197
|
+
// Symbol.iterator as evidence the value is a tagged/iterable type rather
|
|
198
|
+
// than a plain object, while ignoring keys injected onto Object.prototype.
|
|
199
|
+
!hasOwnInPrototypeChain(val, toStringTag) &&
|
|
200
|
+
!hasOwnInPrototypeChain(val, iterator)
|
|
147
201
|
);
|
|
148
202
|
};
|
|
149
203
|
|
|
@@ -670,13 +724,6 @@ const toCamelCase = (str) => {
|
|
|
670
724
|
});
|
|
671
725
|
};
|
|
672
726
|
|
|
673
|
-
/* Creating a function that will check if an object has a property. */
|
|
674
|
-
const hasOwnProperty = (
|
|
675
|
-
({ hasOwnProperty }) =>
|
|
676
|
-
(obj, prop) =>
|
|
677
|
-
hasOwnProperty.call(obj, prop)
|
|
678
|
-
)(Object.prototype);
|
|
679
|
-
|
|
680
727
|
const { propertyIsEnumerable } = Object.prototype;
|
|
681
728
|
|
|
682
729
|
/**
|
|
@@ -890,6 +937,20 @@ const asap =
|
|
|
890
937
|
|
|
891
938
|
const isIterable = (thing) => thing != null && isFunction(thing[iterator]);
|
|
892
939
|
|
|
940
|
+
/**
|
|
941
|
+
* Determine if a value is iterable via an iterator that is NOT sourced solely
|
|
942
|
+
* from a polluted Object.prototype. Use this instead of `isIterable` whenever
|
|
943
|
+
* the iterable comes from untrusted input (e.g. user-supplied header sources),
|
|
944
|
+
* so `Object.prototype[Symbol.iterator] = ...` cannot turn an ordinary object
|
|
945
|
+
* into an attacker-controlled entries iterator.
|
|
946
|
+
*
|
|
947
|
+
* @param {*} thing The value to test
|
|
948
|
+
*
|
|
949
|
+
* @returns {boolean} True if value has a non-polluted iterator
|
|
950
|
+
*/
|
|
951
|
+
const isSafeIterable = (thing) =>
|
|
952
|
+
thing != null && hasOwnInPrototypeChain(thing, iterator) && isIterable(thing);
|
|
953
|
+
|
|
893
954
|
export default {
|
|
894
955
|
isArray,
|
|
895
956
|
isArrayBuffer,
|
|
@@ -934,6 +995,8 @@ export default {
|
|
|
934
995
|
isHTMLForm,
|
|
935
996
|
hasOwnProperty,
|
|
936
997
|
hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection
|
|
998
|
+
hasOwnInPrototypeChain,
|
|
999
|
+
getSafeProp,
|
|
937
1000
|
reduceDescriptors,
|
|
938
1001
|
freezeMethods,
|
|
939
1002
|
toObjectSet,
|
|
@@ -950,4 +1013,5 @@ export default {
|
|
|
950
1013
|
setImmediate: _setImmediate,
|
|
951
1014
|
asap,
|
|
952
1015
|
isIterable,
|
|
1016
|
+
isSafeIterable,
|
|
953
1017
|
};
|
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [v4.0.6](https://github.com/form-data/form-data/compare/v4.0.5...v4.0.6) - 2026-06-12
|
|
9
|
+
|
|
10
|
+
### Commits
|
|
11
|
+
|
|
12
|
+
- [Fix] escape CR, LF, and `"` in field names and filenames [`8dff42c`](https://github.com/form-data/form-data/commit/8dff42c6da654ed4e7ad4acb7f8ccd3831217c99)
|
|
13
|
+
- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `tape` [`f31d21e`](https://github.com/form-data/form-data/commit/f31d21ef10bf46e46344c3ee4f99acbef6be43e1)
|
|
14
|
+
- [Deps] update `hasown`, `mime-types` [`92ae0eb`](https://github.com/form-data/form-data/commit/92ae0eb5da94d6f01925d5f4fcffb2a1e50ed7cd)
|
|
15
|
+
- [Dev Deps] update `js-randomness-predictor` [`67b0f65`](https://github.com/form-data/form-data/commit/67b0f65c2e0b065a511d42227d35e4d367644e97)
|
|
16
|
+
|
|
8
17
|
## [v4.0.5](https://github.com/form-data/form-data/compare/v4.0.4...v4.0.5) - 2025-11-17
|
|
9
18
|
|
|
10
19
|
### Commits
|
|
@@ -94,7 +103,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
94
103
|
- fix (npmignore): ignore temporary build files [`335ad19`](https://github.com/form-data/form-data/commit/335ad19c6e17dc2d7298ffe0e9b37ba63600e94b)
|
|
95
104
|
- fix: move util.isArray to Array.isArray [`440d3be`](https://github.com/form-data/form-data/commit/440d3bed752ac2f9213b4c2229dbccefe140e5fa)
|
|
96
105
|
|
|
97
|
-
## [v4.0.0](https://github.com/form-data/form-data/compare/v3.0.
|
|
106
|
+
## [v4.0.0](https://github.com/form-data/form-data/compare/v3.0.5...v4.0.0) - 2021-02-15
|
|
98
107
|
|
|
99
108
|
### Merged
|
|
100
109
|
|
|
@@ -105,6 +114,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
105
114
|
- Fix typo [`e705c0a`](https://github.com/form-data/form-data/commit/e705c0a1fdaf90d21501f56460b93e43a18bd435)
|
|
106
115
|
- Update README for custom stream behavior [`6dd8624`](https://github.com/form-data/form-data/commit/6dd8624b2999e32768d62752c9aae5845a803b0d)
|
|
107
116
|
|
|
117
|
+
## [v3.0.5](https://github.com/form-data/form-data/compare/v3.0.4...v3.0.5) - 2026-06-12
|
|
118
|
+
|
|
119
|
+
### Commits
|
|
120
|
+
|
|
121
|
+
- [Fix] escape CR, LF, and `"` in field names and filenames [`8777e67`](https://github.com/form-data/form-data/commit/8777e67fbd0282d3dcba81f974fbdd91062c5b23)
|
|
122
|
+
- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `eslint`, `tape` [`27c61a5`](https://github.com/form-data/form-data/commit/27c61a5deed84798be105c96605cb8bd00502dcd)
|
|
123
|
+
- [Deps] update `hasown` [`6a8a1c6`](https://github.com/form-data/form-data/commit/6a8a1c6d04da36e15c80b16ecc4c0265082b3213)
|
|
124
|
+
|
|
108
125
|
## [v3.0.4](https://github.com/form-data/form-data/compare/v3.0.3...v3.0.4) - 2025-07-16
|
|
109
126
|
|
|
110
127
|
### Fixed
|
|
@@ -166,7 +183,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
166
183
|
|
|
167
184
|
- feat: add setBoundary method [`55d90ce`](https://github.com/form-data/form-data/commit/55d90ce4a4c22b0ea0647991d85cb946dfb7395b)
|
|
168
185
|
|
|
169
|
-
## [v3.0.0](https://github.com/form-data/form-data/compare/v2.5.
|
|
186
|
+
## [v3.0.0](https://github.com/form-data/form-data/compare/v2.5.6...v3.0.0) - 2019-11-05
|
|
170
187
|
|
|
171
188
|
### Merged
|
|
172
189
|
|
|
@@ -190,6 +207,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
190
207
|
- Pass options to constructor if not used with new [`4bde68e`](https://github.com/form-data/form-data/commit/4bde68e12de1ba90fefad2e7e643f6375b902763)
|
|
191
208
|
- Make userHeaders optional [`2b4e478`](https://github.com/form-data/form-data/commit/2b4e4787031490942f2d1ee55c56b85a250875a7)
|
|
192
209
|
|
|
210
|
+
## [v2.5.6](https://github.com/form-data/form-data/compare/v2.5.5...v2.5.6) - 2026-06-12
|
|
211
|
+
|
|
212
|
+
### Commits
|
|
213
|
+
|
|
214
|
+
- [Fix] escape CR, LF, and `"` in field names and filenames [`b620316`](https://github.com/form-data/form-data/commit/b62031603c2d7c329b2a369b49466790f0ba6314)
|
|
215
|
+
- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `eslint`, `tape` [`12be578`](https://github.com/form-data/form-data/commit/12be578e936fd77eee75e2e656955f5343c4b80f)
|
|
216
|
+
- [Dev Deps] update `js-randomness-predictor` [`46cfd23`](https://github.com/form-data/form-data/commit/46cfd23bd40be14cfa0391e1c5357c4d74098f23)
|
|
217
|
+
- [Tests] use `safe-buffer` so the header-injection test runs on node < 4 [`633044a`](https://github.com/form-data/form-data/commit/633044a57a7b19f41cec2271ffd24afa2f6280af)
|
|
218
|
+
- [Deps] update `hasown` [`e3b96ee`](https://github.com/form-data/form-data/commit/e3b96eef1661bca8ea4297de057b78bf2734e900)
|
|
219
|
+
|
|
193
220
|
## [v2.5.5](https://github.com/form-data/form-data/compare/v2.5.4...v2.5.5) - 2025-07-18
|
|
194
221
|
|
|
195
222
|
### Commits
|
|
@@ -6,11 +6,11 @@ The API of this library is inspired by the [XMLHttpRequest-2 FormData Interface]
|
|
|
6
6
|
|
|
7
7
|
[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
|
|
8
8
|
|
|
9
|
-
[](https://travis-ci.org/form-data/form-data)
|
|
10
|
+
[](https://travis-ci.org/form-data/form-data)
|
|
11
|
+
[](https://travis-ci.org/form-data/form-data)
|
|
12
12
|
|
|
13
|
-
[](https://coveralls.io/github/form-data/form-data?branch=master)
|
|
14
14
|
[](https://david-dm.org/form-data/form-data)
|
|
15
15
|
|
|
16
16
|
## Install
|
|
@@ -15,6 +15,18 @@ var setToStringTag = require('es-set-tostringtag');
|
|
|
15
15
|
var hasOwn = require('hasown');
|
|
16
16
|
var populate = require('./populate.js');
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Escape CR, LF, and `"` in a multipart `name`/`filename` parameter, so a field
|
|
20
|
+
* name or filename can not break out of its header line to inject headers or
|
|
21
|
+
* smuggle additional parts. Matches the WHATWG HTML multipart/form-data encoding.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} str - the parameter value to escape
|
|
24
|
+
* @returns {string} the escaped value
|
|
25
|
+
*/
|
|
26
|
+
function escapeHeaderParam(str) {
|
|
27
|
+
return String(str).replace(/\r/g, '%0D').replace(/\n/g, '%0A').replace(/"/g, '%22');
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
/**
|
|
19
31
|
* Create readable "multipart/form-data" streams.
|
|
20
32
|
* Can be used to submit forms
|
|
@@ -180,7 +192,7 @@ FormData.prototype._multiPartHeader = function (field, value, options) {
|
|
|
180
192
|
var contents = '';
|
|
181
193
|
var headers = {
|
|
182
194
|
// add custom disposition as third element or keep it two elements if not
|
|
183
|
-
'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || []),
|
|
195
|
+
'Content-Disposition': ['form-data', 'name="' + escapeHeaderParam(field) + '"'].concat(contentDisposition || []),
|
|
184
196
|
// if no content type. allow it to be empty array
|
|
185
197
|
'Content-Type': [].concat(contentType || [])
|
|
186
198
|
};
|
|
@@ -234,7 +246,7 @@ FormData.prototype._getContentDisposition = function (value, options) { // eslin
|
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
if (filename) {
|
|
237
|
-
return 'filename="' + filename + '"';
|
|
249
|
+
return 'filename="' + escapeHeaderParam(filename) + '"';
|
|
238
250
|
}
|
|
239
251
|
};
|
|
240
252
|
|