groove-dev 0.27.144 → 0.27.145
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/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/conversations.js +18 -48
- package/node_modules/@groove-dev/daemon/src/routes/agents.js +6 -83
- package/node_modules/@groove-dev/gui/dist/assets/{index-BcoF6_eF.js → index-Bxc0gU06.js} +232 -238
- package/node_modules/@groove-dev/gui/dist/assets/index-C0pztKBn.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +80 -95
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -70
- package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +68 -66
- package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +4 -8
- package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +39 -31
- package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +66 -65
- package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +17 -14
- package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +126 -127
- package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +10 -8
- package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +8 -8
- package/node_modules/@groove-dev/gui/src/lib/status.js +1 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +17 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +8 -1
- package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +13 -14
- package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +41 -10
- package/node_modules/@groove-dev/gui/src/views/models.jsx +57 -36
- package/node_modules/axios/CHANGELOG.md +260 -0
- package/node_modules/axios/README.md +595 -223
- package/node_modules/axios/dist/axios.js +1460 -1090
- package/node_modules/axios/dist/axios.js.map +1 -1
- 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 +1560 -1132
- package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/node_modules/axios/dist/esm/axios.js +1557 -1128
- package/node_modules/axios/dist/esm/axios.js.map +1 -1
- 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 +1594 -1057
- package/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/node_modules/axios/index.d.cts +40 -41
- package/node_modules/axios/index.d.ts +151 -227
- package/node_modules/axios/index.js +2 -0
- package/node_modules/axios/lib/adapters/adapters.js +4 -2
- package/node_modules/axios/lib/adapters/fetch.js +147 -16
- package/node_modules/axios/lib/adapters/http.js +306 -58
- package/node_modules/axios/lib/adapters/xhr.js +6 -2
- package/node_modules/axios/lib/core/Axios.js +7 -3
- package/node_modules/axios/lib/core/AxiosError.js +120 -34
- package/node_modules/axios/lib/core/AxiosHeaders.js +27 -25
- package/node_modules/axios/lib/core/buildFullPath.js +1 -1
- package/node_modules/axios/lib/core/dispatchRequest.js +19 -7
- package/node_modules/axios/lib/core/mergeConfig.js +21 -4
- package/node_modules/axios/lib/core/settle.js +7 -11
- package/node_modules/axios/lib/defaults/index.js +14 -9
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -2
- package/node_modules/axios/lib/helpers/buildURL.js +1 -1
- package/node_modules/axios/lib/helpers/cookies.js +14 -2
- package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +28 -1
- package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -1
- package/node_modules/axios/lib/helpers/formDataToStream.js +3 -2
- package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
- package/node_modules/axios/lib/helpers/progressEventReducer.js +5 -5
- package/node_modules/axios/lib/helpers/resolveConfig.js +54 -18
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +74 -2
- package/node_modules/axios/lib/helpers/toFormData.js +10 -2
- package/node_modules/axios/lib/helpers/validator.js +3 -1
- package/node_modules/axios/lib/utils.js +33 -21
- package/node_modules/axios/package.json +17 -24
- package/node_modules/follow-redirects/README.md +7 -5
- package/node_modules/follow-redirects/index.js +24 -1
- package/node_modules/follow-redirects/package.json +1 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/conversations.js +18 -48
- package/packages/daemon/src/routes/agents.js +6 -83
- package/packages/gui/dist/assets/{index-BcoF6_eF.js → index-Bxc0gU06.js} +232 -238
- package/packages/gui/dist/assets/index-C0pztKBn.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-feed.jsx +80 -95
- package/packages/gui/src/components/agents/agent-panel.jsx +2 -70
- package/packages/gui/src/components/chat/chat-header.jsx +2 -0
- package/packages/gui/src/components/chat/chat-input.jsx +68 -66
- package/packages/gui/src/components/chat/chat-view.jsx +4 -8
- package/packages/gui/src/components/lab/chat-playground.jsx +39 -31
- package/packages/gui/src/components/lab/parameter-panel.jsx +66 -65
- package/packages/gui/src/components/lab/preset-manager.jsx +17 -14
- package/packages/gui/src/components/lab/runtime-config.jsx +126 -127
- package/packages/gui/src/components/lab/system-prompt-editor.jsx +10 -8
- package/packages/gui/src/components/ui/slider.jsx +8 -8
- package/packages/gui/src/lib/status.js +1 -0
- package/packages/gui/src/stores/groove.js +17 -0
- package/packages/gui/src/stores/slices/agents-slice.js +8 -1
- package/packages/gui/src/stores/slices/chat-slice.js +13 -14
- package/packages/gui/src/views/model-lab.jsx +41 -10
- package/packages/gui/src/views/models.jsx +57 -36
- package/node_modules/@groove-dev/gui/dist/assets/index-Dd7qhiEd.css +0 -1
- package/packages/gui/dist/assets/index-Dd7qhiEd.css +0 -1
|
@@ -7,6 +7,7 @@ import http from 'http';
|
|
|
7
7
|
import https from 'https';
|
|
8
8
|
import http2 from 'http2';
|
|
9
9
|
import util from 'util';
|
|
10
|
+
import { resolve as resolvePath } from 'path';
|
|
10
11
|
import followRedirects from 'follow-redirects';
|
|
11
12
|
import zlib from 'zlib';
|
|
12
13
|
import { VERSION } from '../env/data.js';
|
|
@@ -46,11 +47,46 @@ const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
|
|
|
46
47
|
const { http: httpFollow, https: httpsFollow } = followRedirects;
|
|
47
48
|
|
|
48
49
|
const isHttps = /https:?/;
|
|
50
|
+
const FORM_DATA_CONTENT_HEADERS = ['content-type', 'content-length'];
|
|
51
|
+
|
|
52
|
+
function setFormDataHeaders(headers, formHeaders, policy) {
|
|
53
|
+
if (policy !== 'content-only') {
|
|
54
|
+
headers.set(formHeaders);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Object.entries(formHeaders).forEach(([key, val]) => {
|
|
59
|
+
if (FORM_DATA_CONTENT_HEADERS.includes(key.toLowerCase())) {
|
|
60
|
+
headers.set(key, val);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Symbols used to bind a single 'error' listener to a pooled socket and track
|
|
66
|
+
// the request currently owning that socket across keep-alive reuse (issue #10780).
|
|
67
|
+
const kAxiosSocketListener = Symbol('axios.http.socketListener');
|
|
68
|
+
const kAxiosCurrentReq = Symbol('axios.http.currentReq');
|
|
49
69
|
|
|
50
70
|
const supportedProtocols = platform.protocols.map((protocol) => {
|
|
51
71
|
return protocol + ':';
|
|
52
72
|
});
|
|
53
73
|
|
|
74
|
+
// Node's WHATWG URL parser returns `username` and `password` percent-encoded.
|
|
75
|
+
// Decode before composing the `auth` option so credentials such as
|
|
76
|
+
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
77
|
+
// original value for malformed input so a bad encoding never throws.
|
|
78
|
+
const decodeURIComponentSafe = (value) => {
|
|
79
|
+
if (!utils.isString(value)) {
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
return decodeURIComponent(value);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
54
90
|
const flushOnFinish = (stream, [throttled, flush]) => {
|
|
55
91
|
stream.on('end', flush).on('error', flush);
|
|
56
92
|
|
|
@@ -170,12 +206,12 @@ const http2Sessions = new Http2Sessions();
|
|
|
170
206
|
*
|
|
171
207
|
* @returns {Object<string, any>}
|
|
172
208
|
*/
|
|
173
|
-
function dispatchBeforeRedirect(options, responseDetails) {
|
|
209
|
+
function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
|
|
174
210
|
if (options.beforeRedirects.proxy) {
|
|
175
211
|
options.beforeRedirects.proxy(options);
|
|
176
212
|
}
|
|
177
213
|
if (options.beforeRedirects.config) {
|
|
178
|
-
options.beforeRedirects.config(options, responseDetails);
|
|
214
|
+
options.beforeRedirects.config(options, responseDetails, requestDetails);
|
|
179
215
|
}
|
|
180
216
|
}
|
|
181
217
|
|
|
@@ -188,7 +224,7 @@ function dispatchBeforeRedirect(options, responseDetails) {
|
|
|
188
224
|
*
|
|
189
225
|
* @returns {http.ClientRequestArgs}
|
|
190
226
|
*/
|
|
191
|
-
function setProxy(options, configProxy, location) {
|
|
227
|
+
function setProxy(options, configProxy, location, isRedirect) {
|
|
192
228
|
let proxy = configProxy;
|
|
193
229
|
if (!proxy && proxy !== false) {
|
|
194
230
|
const proxyUrl = getProxyForUrl(location);
|
|
@@ -198,43 +234,87 @@ function setProxy(options, configProxy, location) {
|
|
|
198
234
|
}
|
|
199
235
|
}
|
|
200
236
|
}
|
|
237
|
+
// On redirect re-invocation, strip any stale Proxy-Authorization header carried
|
|
238
|
+
// over from the prior request (e.g. new target no longer uses a proxy, or uses
|
|
239
|
+
// a different proxy). Skip on the initial request so user-supplied headers are
|
|
240
|
+
// preserved. Header names are case-insensitive, so remove every case variant.
|
|
241
|
+
if (isRedirect && options.headers) {
|
|
242
|
+
for (const name of Object.keys(options.headers)) {
|
|
243
|
+
if (name.toLowerCase() === 'proxy-authorization') {
|
|
244
|
+
delete options.headers[name];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
201
248
|
if (proxy) {
|
|
249
|
+
// Read proxy fields without traversing the prototype chain. URL instances expose
|
|
250
|
+
// username/password/hostname/host/port/protocol via getters on URL.prototype (so
|
|
251
|
+
// direct reads are shielded), but plain object proxies — and the `auth` field
|
|
252
|
+
// (which URL does not expose) — must be guarded so a polluted Object.prototype
|
|
253
|
+
// (e.g. Object.prototype.auth = { username, password }) cannot inject
|
|
254
|
+
// attacker-controlled credentials into the Proxy-Authorization header or
|
|
255
|
+
// redirect proxying to an attacker-controlled host.
|
|
256
|
+
const isProxyURL = proxy instanceof URL;
|
|
257
|
+
const readProxyField = (key) =>
|
|
258
|
+
isProxyURL || utils.hasOwnProp(proxy, key) ? proxy[key] : undefined;
|
|
259
|
+
|
|
260
|
+
const proxyUsername = readProxyField('username');
|
|
261
|
+
const proxyPassword = readProxyField('password');
|
|
262
|
+
let proxyAuth = utils.hasOwnProp(proxy, 'auth') ? proxy.auth : undefined;
|
|
263
|
+
|
|
202
264
|
// Basic proxy authorization
|
|
203
|
-
if (
|
|
204
|
-
|
|
265
|
+
if (proxyUsername) {
|
|
266
|
+
proxyAuth = (proxyUsername || '') + ':' + (proxyPassword || '');
|
|
205
267
|
}
|
|
206
268
|
|
|
207
|
-
if (
|
|
208
|
-
// Support proxy auth object form
|
|
209
|
-
|
|
269
|
+
if (proxyAuth) {
|
|
270
|
+
// Support proxy auth object form. Read sub-fields via own-prop checks so a
|
|
271
|
+
// plain object inheriting from polluted Object.prototype cannot leak creds.
|
|
272
|
+
const authIsObject = typeof proxyAuth === 'object';
|
|
273
|
+
const authUsername =
|
|
274
|
+
authIsObject && utils.hasOwnProp(proxyAuth, 'username') ? proxyAuth.username : undefined;
|
|
275
|
+
const authPassword =
|
|
276
|
+
authIsObject && utils.hasOwnProp(proxyAuth, 'password') ? proxyAuth.password : undefined;
|
|
277
|
+
const validProxyAuth = Boolean(authUsername || authPassword);
|
|
210
278
|
|
|
211
279
|
if (validProxyAuth) {
|
|
212
|
-
|
|
213
|
-
} else if (
|
|
280
|
+
proxyAuth = (authUsername || '') + ':' + (authPassword || '');
|
|
281
|
+
} else if (authIsObject) {
|
|
214
282
|
throw new AxiosError('Invalid proxy authorization', AxiosError.ERR_BAD_OPTION, { proxy });
|
|
215
283
|
}
|
|
216
284
|
|
|
217
|
-
const base64 = Buffer.from(
|
|
285
|
+
const base64 = Buffer.from(proxyAuth, 'utf8').toString('base64');
|
|
218
286
|
|
|
219
287
|
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
|
220
288
|
}
|
|
221
289
|
|
|
222
|
-
|
|
223
|
-
|
|
290
|
+
// Preserve a user-supplied Host header (case-insensitive) so callers can override
|
|
291
|
+
// the value forwarded to the proxy; otherwise default to the request URL's host.
|
|
292
|
+
let hasUserHostHeader = false;
|
|
293
|
+
for (const name of Object.keys(options.headers)) {
|
|
294
|
+
if (name.toLowerCase() === 'host') {
|
|
295
|
+
hasUserHostHeader = true;
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!hasUserHostHeader) {
|
|
300
|
+
options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
|
|
301
|
+
}
|
|
302
|
+
const proxyHost = readProxyField('hostname') || readProxyField('host');
|
|
224
303
|
options.hostname = proxyHost;
|
|
225
304
|
// Replace 'host' since options is not a URL object
|
|
226
305
|
options.host = proxyHost;
|
|
227
|
-
options.port =
|
|
306
|
+
options.port = readProxyField('port');
|
|
228
307
|
options.path = location;
|
|
229
|
-
|
|
230
|
-
|
|
308
|
+
const proxyProtocol = readProxyField('protocol');
|
|
309
|
+
if (proxyProtocol) {
|
|
310
|
+
options.protocol = proxyProtocol.includes(':') ? proxyProtocol : `${proxyProtocol}:`;
|
|
231
311
|
}
|
|
232
312
|
}
|
|
233
313
|
|
|
234
314
|
options.beforeRedirects.proxy = function beforeRedirect(redirectOptions) {
|
|
235
315
|
// Configure proxy for redirected request, passing the original config proxy to apply
|
|
236
316
|
// the exact same logic as if the redirected request was performed by axios directly.
|
|
237
|
-
setProxy(redirectOptions, configProxy, redirectOptions.href);
|
|
317
|
+
setProxy(redirectOptions, configProxy, redirectOptions.href, true);
|
|
238
318
|
};
|
|
239
319
|
}
|
|
240
320
|
|
|
@@ -333,12 +413,20 @@ const http2Transport = {
|
|
|
333
413
|
export default isHttpAdapterSupported &&
|
|
334
414
|
function httpAdapter(config) {
|
|
335
415
|
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
|
|
336
|
-
|
|
337
|
-
|
|
416
|
+
const own = (key) => (utils.hasOwnProp(config, key) ? config[key] : undefined);
|
|
417
|
+
let data = own('data');
|
|
418
|
+
let lookup = own('lookup');
|
|
419
|
+
let family = own('family');
|
|
420
|
+
let httpVersion = own('httpVersion');
|
|
421
|
+
if (httpVersion === undefined) httpVersion = 1;
|
|
422
|
+
let http2Options = own('http2Options');
|
|
423
|
+
const responseType = own('responseType');
|
|
424
|
+
const responseEncoding = own('responseEncoding');
|
|
338
425
|
const method = config.method.toUpperCase();
|
|
339
426
|
let isDone;
|
|
340
427
|
let rejected = false;
|
|
341
428
|
let req;
|
|
429
|
+
let connectPhaseTimer;
|
|
342
430
|
|
|
343
431
|
httpVersion = +httpVersion;
|
|
344
432
|
|
|
@@ -383,9 +471,34 @@ export default isHttpAdapterSupported &&
|
|
|
383
471
|
}
|
|
384
472
|
}
|
|
385
473
|
|
|
474
|
+
function clearConnectPhaseTimer() {
|
|
475
|
+
if (connectPhaseTimer) {
|
|
476
|
+
clearTimeout(connectPhaseTimer);
|
|
477
|
+
connectPhaseTimer = null;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function createTimeoutError() {
|
|
482
|
+
let timeoutErrorMessage = config.timeout
|
|
483
|
+
? 'timeout of ' + config.timeout + 'ms exceeded'
|
|
484
|
+
: 'timeout exceeded';
|
|
485
|
+
const transitional = config.transitional || transitionalDefaults;
|
|
486
|
+
if (config.timeoutErrorMessage) {
|
|
487
|
+
timeoutErrorMessage = config.timeoutErrorMessage;
|
|
488
|
+
}
|
|
489
|
+
return new AxiosError(
|
|
490
|
+
timeoutErrorMessage,
|
|
491
|
+
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
|
|
492
|
+
config,
|
|
493
|
+
req
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
386
497
|
abortEmitter.once('abort', reject);
|
|
387
498
|
|
|
388
499
|
const onFinished = () => {
|
|
500
|
+
clearConnectPhaseTimer();
|
|
501
|
+
|
|
389
502
|
if (config.cancelToken) {
|
|
390
503
|
config.cancelToken.unsubscribe(abort);
|
|
391
504
|
}
|
|
@@ -406,6 +519,7 @@ export default isHttpAdapterSupported &&
|
|
|
406
519
|
|
|
407
520
|
onDone((response, isRejected) => {
|
|
408
521
|
isDone = true;
|
|
522
|
+
clearConnectPhaseTimer();
|
|
409
523
|
|
|
410
524
|
if (isRejected) {
|
|
411
525
|
rejected = true;
|
|
@@ -520,8 +634,12 @@ export default isHttpAdapterSupported &&
|
|
|
520
634
|
}
|
|
521
635
|
);
|
|
522
636
|
// support for https://www.npmjs.com/package/form-data api
|
|
523
|
-
} else if (
|
|
524
|
-
|
|
637
|
+
} else if (
|
|
638
|
+
utils.isFormData(data) &&
|
|
639
|
+
utils.isFunction(data.getHeaders) &&
|
|
640
|
+
data.getHeaders !== Object.prototype.getHeaders
|
|
641
|
+
) {
|
|
642
|
+
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
|
|
525
643
|
|
|
526
644
|
if (!headers.hasContentLength()) {
|
|
527
645
|
try {
|
|
@@ -606,15 +724,16 @@ export default isHttpAdapterSupported &&
|
|
|
606
724
|
|
|
607
725
|
// HTTP basic authentication
|
|
608
726
|
let auth = undefined;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const
|
|
727
|
+
const configAuth = own('auth');
|
|
728
|
+
if (configAuth) {
|
|
729
|
+
const username = configAuth.username || '';
|
|
730
|
+
const password = configAuth.password || '';
|
|
612
731
|
auth = username + ':' + password;
|
|
613
732
|
}
|
|
614
733
|
|
|
615
734
|
if (!auth && parsed.username) {
|
|
616
|
-
const urlUsername = parsed.username;
|
|
617
|
-
const urlPassword = parsed.password;
|
|
735
|
+
const urlUsername = decodeURIComponentSafe(parsed.username);
|
|
736
|
+
const urlPassword = decodeURIComponentSafe(parsed.password);
|
|
618
737
|
auth = urlUsername + ':' + urlPassword;
|
|
619
738
|
}
|
|
620
739
|
|
|
@@ -642,7 +761,9 @@ export default isHttpAdapterSupported &&
|
|
|
642
761
|
false
|
|
643
762
|
);
|
|
644
763
|
|
|
645
|
-
|
|
764
|
+
// Null-prototype to block prototype pollution gadgets on properties read
|
|
765
|
+
// directly by Node's http.request (e.g. insecureHTTPParser, lookup).
|
|
766
|
+
const options = Object.assign(Object.create(null), {
|
|
646
767
|
path,
|
|
647
768
|
method: method,
|
|
648
769
|
headers: headers.toJSON(),
|
|
@@ -651,14 +772,41 @@ export default isHttpAdapterSupported &&
|
|
|
651
772
|
protocol,
|
|
652
773
|
family,
|
|
653
774
|
beforeRedirect: dispatchBeforeRedirect,
|
|
654
|
-
beforeRedirects:
|
|
775
|
+
beforeRedirects: Object.create(null),
|
|
655
776
|
http2Options,
|
|
656
|
-
};
|
|
777
|
+
});
|
|
657
778
|
|
|
658
779
|
// cacheable-lookup integration hotfix
|
|
659
780
|
!utils.isUndefined(lookup) && (options.lookup = lookup);
|
|
660
781
|
|
|
661
782
|
if (config.socketPath) {
|
|
783
|
+
if (typeof config.socketPath !== 'string') {
|
|
784
|
+
return reject(
|
|
785
|
+
new AxiosError('socketPath must be a string', AxiosError.ERR_BAD_OPTION_VALUE, config)
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (config.allowedSocketPaths != null) {
|
|
790
|
+
const allowed = Array.isArray(config.allowedSocketPaths)
|
|
791
|
+
? config.allowedSocketPaths
|
|
792
|
+
: [config.allowedSocketPaths];
|
|
793
|
+
|
|
794
|
+
const resolvedSocket = resolvePath(config.socketPath);
|
|
795
|
+
const isAllowed = allowed.some(
|
|
796
|
+
(entry) => typeof entry === 'string' && resolvePath(entry) === resolvedSocket
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
if (!isAllowed) {
|
|
800
|
+
return reject(
|
|
801
|
+
new AxiosError(
|
|
802
|
+
`socketPath "${config.socketPath}" is not permitted by allowedSocketPaths`,
|
|
803
|
+
AxiosError.ERR_BAD_OPTION_VALUE,
|
|
804
|
+
config
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
662
810
|
options.socketPath = config.socketPath;
|
|
663
811
|
} else {
|
|
664
812
|
options.hostname = parsed.hostname.startsWith('[')
|
|
@@ -672,22 +820,26 @@ export default isHttpAdapterSupported &&
|
|
|
672
820
|
);
|
|
673
821
|
}
|
|
674
822
|
let transport;
|
|
823
|
+
let isNativeTransport = false;
|
|
675
824
|
const isHttpsRequest = isHttps.test(options.protocol);
|
|
676
825
|
options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
|
677
826
|
|
|
678
827
|
if (isHttp2) {
|
|
679
828
|
transport = http2Transport;
|
|
680
829
|
} else {
|
|
681
|
-
|
|
682
|
-
|
|
830
|
+
const configTransport = own('transport');
|
|
831
|
+
if (configTransport) {
|
|
832
|
+
transport = configTransport;
|
|
683
833
|
} else if (config.maxRedirects === 0) {
|
|
684
834
|
transport = isHttpsRequest ? https : http;
|
|
835
|
+
isNativeTransport = true;
|
|
685
836
|
} else {
|
|
686
837
|
if (config.maxRedirects) {
|
|
687
838
|
options.maxRedirects = config.maxRedirects;
|
|
688
839
|
}
|
|
689
|
-
|
|
690
|
-
|
|
840
|
+
const configBeforeRedirect = own('beforeRedirect');
|
|
841
|
+
if (configBeforeRedirect) {
|
|
842
|
+
options.beforeRedirects.config = configBeforeRedirect;
|
|
691
843
|
}
|
|
692
844
|
transport = isHttpsRequest ? httpsFollow : httpFollow;
|
|
693
845
|
}
|
|
@@ -700,12 +852,15 @@ export default isHttpAdapterSupported &&
|
|
|
700
852
|
options.maxBodyLength = Infinity;
|
|
701
853
|
}
|
|
702
854
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
855
|
+
// Always set an explicit own value so a polluted
|
|
856
|
+
// Object.prototype.insecureHTTPParser cannot enable the lenient parser
|
|
857
|
+
// through Node's internal options copy
|
|
858
|
+
options.insecureHTTPParser = Boolean(own('insecureHTTPParser'));
|
|
706
859
|
|
|
707
860
|
// Create the request
|
|
708
861
|
req = transport.request(options, function handleResponse(res) {
|
|
862
|
+
clearConnectPhaseTimer();
|
|
863
|
+
|
|
709
864
|
if (req.destroyed) return;
|
|
710
865
|
|
|
711
866
|
const streams = [res];
|
|
@@ -786,6 +941,30 @@ export default isHttpAdapterSupported &&
|
|
|
786
941
|
};
|
|
787
942
|
|
|
788
943
|
if (responseType === 'stream') {
|
|
944
|
+
// Enforce maxContentLength on streamed responses; previously this
|
|
945
|
+
// was applied only to buffered responses.
|
|
946
|
+
if (config.maxContentLength > -1) {
|
|
947
|
+
const limit = config.maxContentLength;
|
|
948
|
+
const source = responseStream;
|
|
949
|
+
async function* enforceMaxContentLength() {
|
|
950
|
+
let totalResponseBytes = 0;
|
|
951
|
+
for await (const chunk of source) {
|
|
952
|
+
totalResponseBytes += chunk.length;
|
|
953
|
+
if (totalResponseBytes > limit) {
|
|
954
|
+
throw new AxiosError(
|
|
955
|
+
'maxContentLength size of ' + limit + ' exceeded',
|
|
956
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
957
|
+
config,
|
|
958
|
+
lastRequest
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
yield chunk;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
responseStream = stream.Readable.from(enforceMaxContentLength(), {
|
|
965
|
+
objectMode: false,
|
|
966
|
+
});
|
|
967
|
+
}
|
|
789
968
|
response.data = responseStream;
|
|
790
969
|
settle(resolve, reject, response);
|
|
791
970
|
} else {
|
|
@@ -821,15 +1000,16 @@ export default isHttpAdapterSupported &&
|
|
|
821
1000
|
'stream has been aborted',
|
|
822
1001
|
AxiosError.ERR_BAD_RESPONSE,
|
|
823
1002
|
config,
|
|
824
|
-
lastRequest
|
|
1003
|
+
lastRequest,
|
|
1004
|
+
response
|
|
825
1005
|
);
|
|
826
1006
|
responseStream.destroy(err);
|
|
827
1007
|
reject(err);
|
|
828
1008
|
});
|
|
829
1009
|
|
|
830
1010
|
responseStream.on('error', function handleStreamError(err) {
|
|
831
|
-
if (
|
|
832
|
-
reject(AxiosError.from(err, null, config, lastRequest));
|
|
1011
|
+
if (rejected) return;
|
|
1012
|
+
reject(AxiosError.from(err, null, config, lastRequest, response));
|
|
833
1013
|
});
|
|
834
1014
|
|
|
835
1015
|
responseStream.on('end', function handleStreamEnd() {
|
|
@@ -872,9 +1052,48 @@ export default isHttpAdapterSupported &&
|
|
|
872
1052
|
});
|
|
873
1053
|
|
|
874
1054
|
// set tcp keep alive to prevent drop connection by peer
|
|
1055
|
+
// Track every socket bound to this outer RedirectableRequest so a single
|
|
1056
|
+
// 'close' listener can release ownership on all of them. follow-redirects
|
|
1057
|
+
// re-emits the 'socket' event for each hop's native request onto the same
|
|
1058
|
+
// outer request, so attaching per-request listeners inside this handler
|
|
1059
|
+
// would accumulate across hops and trigger MaxListenersExceededWarning at
|
|
1060
|
+
// >= 11 redirects. Clearing only the last-bound socket would leave stale
|
|
1061
|
+
// kAxiosCurrentReq refs on earlier hop sockets returned to the keep-alive
|
|
1062
|
+
// pool, causing an idle-pool 'error' to be attributed to a closed req.
|
|
1063
|
+
const boundSockets = new Set();
|
|
1064
|
+
|
|
875
1065
|
req.on('socket', function handleRequestSocket(socket) {
|
|
876
1066
|
// default interval of sending ack packet is 1 minute
|
|
877
1067
|
socket.setKeepAlive(true, 1000 * 60);
|
|
1068
|
+
|
|
1069
|
+
// Install a single 'error' listener per socket (not per request) to avoid
|
|
1070
|
+
// accumulating listeners on pooled keep-alive sockets that get reassigned
|
|
1071
|
+
// to new requests before the previous request's 'close' fires (issue #10780).
|
|
1072
|
+
// The listener is bound to the socket's currently-active request via a
|
|
1073
|
+
// symbol, which is swapped as the socket is reassigned.
|
|
1074
|
+
if (!socket[kAxiosSocketListener]) {
|
|
1075
|
+
socket.on('error', function handleSocketError(err) {
|
|
1076
|
+
const current = socket[kAxiosCurrentReq];
|
|
1077
|
+
if (current && !current.destroyed) {
|
|
1078
|
+
current.destroy(err);
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
socket[kAxiosSocketListener] = true;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
socket[kAxiosCurrentReq] = req;
|
|
1085
|
+
boundSockets.add(socket);
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
req.once('close', function clearCurrentReq() {
|
|
1089
|
+
clearConnectPhaseTimer();
|
|
1090
|
+
|
|
1091
|
+
for (const socket of boundSockets) {
|
|
1092
|
+
if (socket[kAxiosCurrentReq] === req) {
|
|
1093
|
+
socket[kAxiosCurrentReq] = null;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
boundSockets.clear();
|
|
878
1097
|
});
|
|
879
1098
|
|
|
880
1099
|
// Handle request timeout
|
|
@@ -895,29 +1114,24 @@ export default isHttpAdapterSupported &&
|
|
|
895
1114
|
return;
|
|
896
1115
|
}
|
|
897
1116
|
|
|
1117
|
+
const handleTimeout = function handleTimeout() {
|
|
1118
|
+
if (isDone) return;
|
|
1119
|
+
abort(createTimeoutError());
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
if (isNativeTransport && timeout > 0) {
|
|
1123
|
+
// Native ClientRequest#setTimeout starts from the socket lifecycle and
|
|
1124
|
+
// may not fire while TCP connect is still pending. Mirror the
|
|
1125
|
+
// follow-redirects wall-clock timer for the maxRedirects === 0 path.
|
|
1126
|
+
connectPhaseTimer = setTimeout(handleTimeout, timeout);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
898
1129
|
// Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
|
|
899
1130
|
// And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
|
|
900
1131
|
// At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up.
|
|
901
1132
|
// And then these socket which be hang up will devouring CPU little by little.
|
|
902
1133
|
// ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
|
|
903
|
-
req.setTimeout(timeout,
|
|
904
|
-
if (isDone) return;
|
|
905
|
-
let timeoutErrorMessage = config.timeout
|
|
906
|
-
? 'timeout of ' + config.timeout + 'ms exceeded'
|
|
907
|
-
: 'timeout exceeded';
|
|
908
|
-
const transitional = config.transitional || transitionalDefaults;
|
|
909
|
-
if (config.timeoutErrorMessage) {
|
|
910
|
-
timeoutErrorMessage = config.timeoutErrorMessage;
|
|
911
|
-
}
|
|
912
|
-
abort(
|
|
913
|
-
new AxiosError(
|
|
914
|
-
timeoutErrorMessage,
|
|
915
|
-
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
|
|
916
|
-
config,
|
|
917
|
-
req
|
|
918
|
-
)
|
|
919
|
-
);
|
|
920
|
-
});
|
|
1134
|
+
req.setTimeout(timeout, handleTimeout);
|
|
921
1135
|
} else {
|
|
922
1136
|
// explicitly reset the socket timeout value for a possible `keep-alive` request
|
|
923
1137
|
req.setTimeout(0);
|
|
@@ -943,7 +1157,41 @@ export default isHttpAdapterSupported &&
|
|
|
943
1157
|
}
|
|
944
1158
|
});
|
|
945
1159
|
|
|
946
|
-
|
|
1160
|
+
// Enforce maxBodyLength for streamed uploads on the native http/https
|
|
1161
|
+
// transport (maxRedirects === 0); follow-redirects enforces it on the
|
|
1162
|
+
// other path.
|
|
1163
|
+
let uploadStream = data;
|
|
1164
|
+
if (config.maxBodyLength > -1 && config.maxRedirects === 0) {
|
|
1165
|
+
const limit = config.maxBodyLength;
|
|
1166
|
+
let bytesSent = 0;
|
|
1167
|
+
uploadStream = stream.pipeline(
|
|
1168
|
+
[
|
|
1169
|
+
data,
|
|
1170
|
+
new stream.Transform({
|
|
1171
|
+
transform(chunk, _enc, cb) {
|
|
1172
|
+
bytesSent += chunk.length;
|
|
1173
|
+
if (bytesSent > limit) {
|
|
1174
|
+
return cb(
|
|
1175
|
+
new AxiosError(
|
|
1176
|
+
'Request body larger than maxBodyLength limit',
|
|
1177
|
+
AxiosError.ERR_BAD_REQUEST,
|
|
1178
|
+
config,
|
|
1179
|
+
req
|
|
1180
|
+
)
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
cb(null, chunk);
|
|
1184
|
+
},
|
|
1185
|
+
}),
|
|
1186
|
+
],
|
|
1187
|
+
utils.noop
|
|
1188
|
+
);
|
|
1189
|
+
uploadStream.on('error', (err) => {
|
|
1190
|
+
if (!req.destroyed) req.destroy(err);
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
uploadStream.pipe(req);
|
|
947
1195
|
} else {
|
|
948
1196
|
data && req.write(data);
|
|
949
1197
|
req.end();
|
|
@@ -91,7 +91,7 @@ export default isXHRAdapterSupported &&
|
|
|
91
91
|
// will return status as 0 even though it's a successful request
|
|
92
92
|
if (
|
|
93
93
|
request.status === 0 &&
|
|
94
|
-
!(request.responseURL && request.responseURL.
|
|
94
|
+
!(request.responseURL && request.responseURL.startsWith('file:'))
|
|
95
95
|
) {
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
@@ -108,6 +108,7 @@ export default isXHRAdapterSupported &&
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));
|
|
111
|
+
done();
|
|
111
112
|
|
|
112
113
|
// Clean up request
|
|
113
114
|
request = null;
|
|
@@ -123,6 +124,7 @@ export default isXHRAdapterSupported &&
|
|
|
123
124
|
// attach the underlying event for consumers who want details
|
|
124
125
|
err.event = event || null;
|
|
125
126
|
reject(err);
|
|
127
|
+
done();
|
|
126
128
|
request = null;
|
|
127
129
|
};
|
|
128
130
|
|
|
@@ -143,6 +145,7 @@ export default isXHRAdapterSupported &&
|
|
|
143
145
|
request
|
|
144
146
|
)
|
|
145
147
|
);
|
|
148
|
+
done();
|
|
146
149
|
|
|
147
150
|
// Clean up request
|
|
148
151
|
request = null;
|
|
@@ -192,6 +195,7 @@ export default isXHRAdapterSupported &&
|
|
|
192
195
|
}
|
|
193
196
|
reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);
|
|
194
197
|
request.abort();
|
|
198
|
+
done();
|
|
195
199
|
request = null;
|
|
196
200
|
};
|
|
197
201
|
|
|
@@ -205,7 +209,7 @@ export default isXHRAdapterSupported &&
|
|
|
205
209
|
|
|
206
210
|
const protocol = parseProtocol(_config.url);
|
|
207
211
|
|
|
208
|
-
if (protocol && platform.protocols.
|
|
212
|
+
if (protocol && !platform.protocols.includes(protocol)) {
|
|
209
213
|
reject(
|
|
210
214
|
new AxiosError(
|
|
211
215
|
'Unsupported protocol ' + protocol + ':',
|
|
@@ -148,7 +148,7 @@ class Axios {
|
|
|
148
148
|
let contextHeaders = headers && utils.merge(headers.common, headers[config.method]);
|
|
149
149
|
|
|
150
150
|
headers &&
|
|
151
|
-
utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], (method) => {
|
|
151
|
+
utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'query', 'common'], (method) => {
|
|
152
152
|
delete headers[method];
|
|
153
153
|
});
|
|
154
154
|
|
|
@@ -251,7 +251,7 @@ utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData
|
|
|
251
251
|
};
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
-
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
|
|
254
|
+
utils.forEach(['post', 'put', 'patch', 'query'], function forEachMethodWithData(method) {
|
|
255
255
|
function generateHTTPMethod(isForm) {
|
|
256
256
|
return function httpMethod(url, data, config) {
|
|
257
257
|
return this.request(
|
|
@@ -271,7 +271,11 @@ utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
|
|
|
271
271
|
|
|
272
272
|
Axios.prototype[method] = generateHTTPMethod();
|
|
273
273
|
|
|
274
|
-
|
|
274
|
+
// QUERY is a safe/idempotent read method; multipart form bodies don't fit
|
|
275
|
+
// its semantics, so no queryForm shorthand is generated.
|
|
276
|
+
if (method !== 'query') {
|
|
277
|
+
Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
|
|
278
|
+
}
|
|
275
279
|
});
|
|
276
280
|
|
|
277
281
|
export default Axios;
|