@juspay/neurolink 7.29.0 → 7.29.2
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/CHANGELOG.md +12 -0
- package/dist/cli/commands/config.d.ts +3 -3
- package/dist/cli/commands/mcp.js +25 -0
- package/dist/cli/factories/commandFactory.d.ts +1 -0
- package/dist/cli/factories/commandFactory.js +115 -21
- package/dist/cli/index.js +8 -0
- package/dist/core/factory.js +77 -4
- package/dist/factories/providerFactory.js +3 -0
- package/dist/factories/providerRegistry.js +2 -2
- package/dist/lib/core/factory.js +77 -4
- package/dist/lib/factories/providerFactory.js +3 -0
- package/dist/lib/factories/providerRegistry.js +2 -2
- package/dist/lib/mcp/externalServerManager.js +13 -14
- package/dist/lib/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/lib/mcp/flexibleToolValidator.js +161 -0
- package/dist/lib/mcp/toolRegistry.d.ts +2 -2
- package/dist/lib/mcp/toolRegistry.js +25 -50
- package/dist/lib/neurolink.d.ts +299 -4
- package/dist/lib/neurolink.js +434 -73
- package/dist/lib/providers/amazonBedrock.d.ts +47 -6
- package/dist/lib/providers/amazonBedrock.js +282 -23
- package/dist/lib/providers/aws/credentialProvider.d.ts +58 -0
- package/dist/lib/providers/aws/credentialProvider.js +267 -0
- package/dist/lib/providers/aws/credentialTester.d.ts +49 -0
- package/dist/lib/providers/aws/credentialTester.js +394 -0
- package/dist/lib/providers/googleVertex.js +13 -4
- package/dist/lib/proxy/awsProxyIntegration.d.ts +23 -0
- package/dist/lib/proxy/awsProxyIntegration.js +285 -0
- package/dist/lib/proxy/proxyFetch.d.ts +9 -5
- package/dist/lib/proxy/proxyFetch.js +232 -98
- package/dist/lib/proxy/utils/noProxyUtils.d.ts +39 -0
- package/dist/lib/proxy/utils/noProxyUtils.js +149 -0
- package/dist/lib/types/providers.d.ts +43 -0
- package/dist/lib/utils/providerConfig.d.ts +1 -0
- package/dist/lib/utils/providerConfig.js +2 -1
- package/dist/lib/utils/providerHealth.js +123 -5
- package/dist/mcp/externalServerManager.js +13 -14
- package/dist/mcp/flexibleToolValidator.d.ts +50 -0
- package/dist/mcp/flexibleToolValidator.js +161 -0
- package/dist/mcp/toolRegistry.d.ts +2 -2
- package/dist/mcp/toolRegistry.js +25 -50
- package/dist/neurolink.d.ts +299 -4
- package/dist/neurolink.js +434 -73
- package/dist/providers/amazonBedrock.d.ts +47 -6
- package/dist/providers/amazonBedrock.js +282 -23
- package/dist/providers/aws/credentialProvider.d.ts +58 -0
- package/dist/providers/aws/credentialProvider.js +267 -0
- package/dist/providers/aws/credentialTester.d.ts +49 -0
- package/dist/providers/aws/credentialTester.js +394 -0
- package/dist/providers/googleVertex.js +13 -4
- package/dist/proxy/awsProxyIntegration.d.ts +23 -0
- package/dist/proxy/awsProxyIntegration.js +285 -0
- package/dist/proxy/proxyFetch.d.ts +9 -5
- package/dist/proxy/proxyFetch.js +232 -98
- package/dist/proxy/utils/noProxyUtils.d.ts +39 -0
- package/dist/proxy/utils/noProxyUtils.js +149 -0
- package/dist/types/providers.d.ts +43 -0
- package/dist/utils/providerConfig.d.ts +1 -0
- package/dist/utils/providerConfig.js +2 -1
- package/dist/utils/providerHealth.js +123 -5
- package/package.json +5 -1
package/dist/proxy/proxyFetch.js
CHANGED
|
@@ -1,123 +1,253 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Enhanced proxy-aware fetch implementation for AI SDK providers
|
|
3
|
+
* Supports HTTP/HTTPS, SOCKS4/5, authentication, and NO_PROXY bypass
|
|
4
|
+
* Lightweight implementation extracted from research of major proxy packages
|
|
4
5
|
*/
|
|
5
6
|
import { logger } from "../utils/logger.js";
|
|
7
|
+
import { shouldBypassProxy } from "./utils/noProxyUtils.js";
|
|
6
8
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* Mask credentials in proxy URLs for secure logging
|
|
10
|
+
* Replaces user:password@ with [CREDENTIALS_MASKED]@
|
|
11
|
+
*/
|
|
12
|
+
function maskProxyCredentials(proxyUrl) {
|
|
13
|
+
if (!proxyUrl || proxyUrl === "NOT_SET") {
|
|
14
|
+
return proxyUrl || "NOT_SET";
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
// Handle URLs with credentials: http://user:password@proxy:port
|
|
18
|
+
const credentialPattern = /(:\/\/)([^@:]+):([^@]+)@/;
|
|
19
|
+
if (credentialPattern.test(proxyUrl)) {
|
|
20
|
+
return proxyUrl.replace(credentialPattern, "$1[CREDENTIALS_MASKED]@");
|
|
21
|
+
}
|
|
22
|
+
// Return original URL if no credentials found
|
|
23
|
+
return proxyUrl;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// If URL parsing fails, still mask potential credentials pattern
|
|
27
|
+
return proxyUrl.replace(/(:\/\/)([^@:]+):([^@]+)@/, "$1[CREDENTIALS_MASKED]@");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Mask all proxy credentials in an environment variables object
|
|
32
|
+
*/
|
|
33
|
+
function maskProxyEnvVars(envVars) {
|
|
34
|
+
const masked = {};
|
|
35
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
36
|
+
masked[key] = maskProxyCredentials(value);
|
|
37
|
+
}
|
|
38
|
+
return masked;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse proxy URL with authentication support
|
|
42
|
+
*/
|
|
43
|
+
function parseProxyUrl(proxyUrl) {
|
|
44
|
+
try {
|
|
45
|
+
const url = new URL(proxyUrl);
|
|
46
|
+
const config = {
|
|
47
|
+
protocol: url.protocol,
|
|
48
|
+
hostname: url.hostname,
|
|
49
|
+
port: parseInt(url.port) || getDefaultPort(url.protocol),
|
|
50
|
+
cleanUrl: `${url.protocol}//${url.hostname}:${url.port || getDefaultPort(url.protocol)}`,
|
|
51
|
+
};
|
|
52
|
+
// Extract authentication if present
|
|
53
|
+
if (url.username && url.password) {
|
|
54
|
+
config.auth = {
|
|
55
|
+
username: decodeURIComponent(url.username),
|
|
56
|
+
password: decodeURIComponent(url.password),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
logger.error("[Proxy] Failed to parse proxy URL", {
|
|
63
|
+
proxyUrl: maskProxyCredentials(proxyUrl),
|
|
64
|
+
error,
|
|
65
|
+
});
|
|
66
|
+
throw new Error(`Invalid proxy URL: ${maskProxyCredentials(proxyUrl)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get default port for protocol
|
|
71
|
+
*/
|
|
72
|
+
function getDefaultPort(protocol) {
|
|
73
|
+
switch (protocol) {
|
|
74
|
+
case "http:":
|
|
75
|
+
return 8080;
|
|
76
|
+
case "https:":
|
|
77
|
+
return 8080;
|
|
78
|
+
case "socks4:":
|
|
79
|
+
return 1080;
|
|
80
|
+
case "socks5:":
|
|
81
|
+
return 1080;
|
|
82
|
+
default:
|
|
83
|
+
return 8080;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Select appropriate proxy URL based on target and environment
|
|
88
|
+
*/
|
|
89
|
+
function selectProxyUrl(targetUrl) {
|
|
90
|
+
// Check NO_PROXY bypass first
|
|
91
|
+
if (shouldBypassProxy(targetUrl)) {
|
|
92
|
+
logger.debug("[Proxy] Bypassing proxy due to NO_PROXY", { targetUrl });
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const url = new URL(targetUrl);
|
|
97
|
+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
98
|
+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
99
|
+
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
|
|
100
|
+
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
|
|
101
|
+
// Priority: Protocol-specific > ALL_PROXY > SOCKS_PROXY
|
|
102
|
+
if (url.protocol === "https:" && httpsProxy) {
|
|
103
|
+
return httpsProxy;
|
|
104
|
+
}
|
|
105
|
+
if (url.protocol === "http:" && httpProxy) {
|
|
106
|
+
return httpProxy;
|
|
107
|
+
}
|
|
108
|
+
if (allProxy) {
|
|
109
|
+
return allProxy;
|
|
110
|
+
}
|
|
111
|
+
if (socksProxy) {
|
|
112
|
+
return socksProxy;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logger.warn("[Proxy] Error selecting proxy URL", { targetUrl, error });
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Create appropriate proxy agent based on protocol
|
|
123
|
+
*/
|
|
124
|
+
async function createProxyAgent(proxyUrl) {
|
|
125
|
+
const parsed = parseProxyUrl(proxyUrl);
|
|
126
|
+
logger.debug("[Proxy] Creating proxy agent", {
|
|
127
|
+
protocol: parsed.protocol,
|
|
128
|
+
hostname: parsed.hostname,
|
|
129
|
+
port: parsed.port,
|
|
130
|
+
hasAuth: !!parsed.auth,
|
|
131
|
+
});
|
|
132
|
+
switch (parsed.protocol) {
|
|
133
|
+
case "http:":
|
|
134
|
+
case "https:": {
|
|
135
|
+
// Use existing undici ProxyAgent for HTTP/HTTPS
|
|
136
|
+
const { ProxyAgent } = await import("undici");
|
|
137
|
+
return new ProxyAgent(proxyUrl);
|
|
138
|
+
}
|
|
139
|
+
case "socks4:":
|
|
140
|
+
case "socks5:": {
|
|
141
|
+
// SOCKS proxy support is not included in the build to avoid optional dependencies
|
|
142
|
+
throw new Error(`SOCKS proxy support requires 'proxy-agent' package. ` +
|
|
143
|
+
`Install it with: npm install proxy-agent`);
|
|
144
|
+
}
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Unsupported proxy protocol: ${parsed.protocol}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ==================== ENHANCED PROXY FETCH FUNCTION ====================
|
|
150
|
+
/**
|
|
151
|
+
* Create a proxy-aware fetch function with enhanced capabilities
|
|
152
|
+
* Supports HTTP/HTTPS, SOCKS4/5, authentication, and NO_PROXY bypass
|
|
9
153
|
*/
|
|
10
154
|
export function createProxyFetch() {
|
|
155
|
+
// Detect ALL proxy-related environment variables
|
|
11
156
|
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
12
157
|
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
158
|
+
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
|
|
159
|
+
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
|
|
160
|
+
const noProxy = process.env.NO_PROXY || process.env.no_proxy;
|
|
161
|
+
// ENHANCED LOGGING: Capture ALL enhanced proxy-related environment variables with credential masking
|
|
162
|
+
logger.debug("[Proxy Fetch] 🔍 ENHANCED_PROXY_ENV_DETECTION", {
|
|
163
|
+
// Enhanced proxy environment variables (credentials masked)
|
|
164
|
+
httpProxy: maskProxyCredentials(httpProxy || "NOT_SET"),
|
|
165
|
+
httpsProxy: maskProxyCredentials(httpsProxy || "NOT_SET"),
|
|
166
|
+
allProxy: maskProxyCredentials(allProxy || "NOT_SET"),
|
|
167
|
+
socksProxy: maskProxyCredentials(socksProxy || "NOT_SET"),
|
|
168
|
+
noProxy: noProxy || "NOT_SET", // NO_PROXY doesn't contain credentials
|
|
169
|
+
// Legacy variables for compatibility (credentials masked)
|
|
170
|
+
originalNodejsHttpProxy: maskProxyCredentials(process.env.nodejs_http_proxy || "NOT_SET"),
|
|
171
|
+
originalNodejsHttpsProxy: maskProxyCredentials(process.env.nodejs_https_proxy || "NOT_SET"),
|
|
172
|
+
// All potential proxy-related environment variables (credentials masked)
|
|
173
|
+
allProxyRelatedEnvVars: maskProxyEnvVars(Object.keys(process.env)
|
|
28
174
|
.filter((key) => key.toLowerCase().includes("proxy"))
|
|
29
175
|
.reduce((acc, key) => {
|
|
30
176
|
acc[key] = process.env[key] || "NOT_SET";
|
|
31
177
|
return acc;
|
|
32
|
-
}, {}),
|
|
33
|
-
message: "
|
|
178
|
+
}, {})),
|
|
179
|
+
message: "Enhanced proxy environment detection with SOCKS, authentication, and NO_PROXY support (credentials masked for security)",
|
|
34
180
|
});
|
|
35
181
|
// If no proxy configured, return standard fetch
|
|
36
|
-
if (!httpsProxy && !httpProxy) {
|
|
182
|
+
if (!httpsProxy && !httpProxy && !allProxy && !socksProxy) {
|
|
37
183
|
logger.debug("[Proxy Fetch] No proxy environment variables found - using standard fetch");
|
|
38
184
|
return fetch;
|
|
39
185
|
}
|
|
40
|
-
logger.debug(`[Proxy Fetch] Configuring proxy with
|
|
41
|
-
logger.debug(`[Proxy Fetch] HTTP_PROXY: ${httpProxy || "not set"}`);
|
|
42
|
-
logger.debug(`[Proxy Fetch] HTTPS_PROXY: ${httpsProxy || "not set"}`);
|
|
43
|
-
|
|
186
|
+
logger.debug(`[Proxy Fetch] Configuring enhanced proxy with multiple protocol support`);
|
|
187
|
+
logger.debug(`[Proxy Fetch] HTTP_PROXY: ${maskProxyCredentials(httpProxy || "not set")}`);
|
|
188
|
+
logger.debug(`[Proxy Fetch] HTTPS_PROXY: ${maskProxyCredentials(httpsProxy || "not set")}`);
|
|
189
|
+
logger.debug(`[Proxy Fetch] ALL_PROXY: ${maskProxyCredentials(allProxy || "not set")}`);
|
|
190
|
+
logger.debug(`[Proxy Fetch] SOCKS_PROXY: ${maskProxyCredentials(socksProxy || "not set")}`);
|
|
191
|
+
logger.debug(`[Proxy Fetch] NO_PROXY: ${noProxy || "not set"}`);
|
|
192
|
+
// Return enhanced proxy-aware fetch function
|
|
44
193
|
return async (input, init) => {
|
|
45
|
-
const requestId = `req-${Date.now()}-${Math.random().toString(36).
|
|
46
|
-
|
|
194
|
+
const requestId = `req-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
195
|
+
// Determine target URL
|
|
196
|
+
const targetUrl = typeof input === "string"
|
|
197
|
+
? input
|
|
198
|
+
: input instanceof URL
|
|
199
|
+
? input.href
|
|
200
|
+
: input.url;
|
|
201
|
+
logger.debug(`[Proxy Fetch] 🚀 ENHANCED REQUEST START`, {
|
|
47
202
|
requestId,
|
|
48
|
-
|
|
49
|
-
? input
|
|
50
|
-
: input instanceof URL
|
|
51
|
-
? input.href
|
|
52
|
-
: input.url,
|
|
203
|
+
targetUrl,
|
|
53
204
|
timestamp: new Date().toISOString(),
|
|
54
205
|
httpProxy: httpProxy || "NOT_SET",
|
|
55
206
|
httpsProxy: httpsProxy || "NOT_SET",
|
|
207
|
+
allProxy: allProxy || "NOT_SET",
|
|
208
|
+
socksProxy: socksProxy || "NOT_SET",
|
|
56
209
|
initHeaders: init?.headers || "NO_HEADERS",
|
|
57
210
|
initMethod: init?.method || "GET",
|
|
58
211
|
});
|
|
59
212
|
try {
|
|
60
|
-
//
|
|
61
|
-
const
|
|
62
|
-
const { ProxyAgent } = undici;
|
|
63
|
-
logger.debug(`[Proxy Fetch] 🔧 EXHAUSTIVE UNDICI IMPORT SUCCESS`, {
|
|
64
|
-
requestId,
|
|
65
|
-
hasUndici: !!undici,
|
|
66
|
-
hasProxyAgent: !!ProxyAgent,
|
|
67
|
-
undiciType: typeof undici,
|
|
68
|
-
proxyAgentType: typeof ProxyAgent,
|
|
69
|
-
timestamp: new Date().toISOString(),
|
|
70
|
-
});
|
|
71
|
-
const url = typeof input === "string"
|
|
72
|
-
? new URL(input)
|
|
73
|
-
: input instanceof URL
|
|
74
|
-
? input
|
|
75
|
-
: new URL(input.url);
|
|
76
|
-
const proxyUrl = url.protocol === "https:" ? httpsProxy : httpProxy;
|
|
77
|
-
logger.debug(`[Proxy Fetch] 🔗 EXHAUSTIVE URL ANALYSIS`, {
|
|
78
|
-
requestId,
|
|
79
|
-
urlString: url.href,
|
|
80
|
-
urlHostname: url.hostname,
|
|
81
|
-
urlProtocol: url.protocol,
|
|
82
|
-
urlPort: url.port,
|
|
83
|
-
urlPathname: url.pathname,
|
|
84
|
-
selectedProxyUrl: proxyUrl,
|
|
85
|
-
timestamp: new Date().toISOString(),
|
|
86
|
-
});
|
|
213
|
+
// Enhanced proxy selection with NO_PROXY bypass and multiple protocols
|
|
214
|
+
const proxyUrl = selectProxyUrl(targetUrl);
|
|
87
215
|
if (proxyUrl) {
|
|
88
|
-
|
|
89
|
-
logger.debug(`[Proxy Fetch]
|
|
216
|
+
const url = new URL(targetUrl);
|
|
217
|
+
logger.debug(`[Proxy Fetch] 🔗 ENHANCED URL ANALYSIS`, {
|
|
90
218
|
requestId,
|
|
91
|
-
|
|
219
|
+
targetUrl,
|
|
220
|
+
urlHostname: url.hostname,
|
|
221
|
+
urlProtocol: url.protocol,
|
|
222
|
+
urlPort: url.port,
|
|
223
|
+
selectedProxyUrl: maskProxyCredentials(proxyUrl), // Hide credentials in logs
|
|
224
|
+
timestamp: new Date().toISOString(),
|
|
225
|
+
});
|
|
226
|
+
logger.debug(`[Proxy Fetch] 🎯 ENHANCED PROXY AGENT CREATION`, {
|
|
227
|
+
requestId,
|
|
228
|
+
proxyUrl: maskProxyCredentials(proxyUrl), // Hide credentials
|
|
92
229
|
targetHostname: url.hostname,
|
|
93
230
|
targetProtocol: url.protocol,
|
|
94
231
|
aboutToCreateProxyAgent: true,
|
|
95
232
|
timestamp: new Date().toISOString(),
|
|
96
233
|
});
|
|
97
|
-
// Create
|
|
98
|
-
const
|
|
99
|
-
|
|
234
|
+
// Create/reuse proxy agent (HTTP/HTTPS/SOCKS)
|
|
235
|
+
const agentCache = globalThis.__NL_PROXY_AGENT_CACHE__ ??
|
|
236
|
+
(globalThis.__NL_PROXY_AGENT_CACHE__ = new Map());
|
|
237
|
+
const dispatcher = agentCache.get(proxyUrl) || (await createProxyAgent(proxyUrl));
|
|
238
|
+
agentCache.set(proxyUrl, dispatcher);
|
|
239
|
+
logger.debug(`[Proxy Fetch] ✅ ENHANCED PROXY AGENT CREATED`, {
|
|
100
240
|
requestId,
|
|
101
241
|
hasDispatcher: !!dispatcher,
|
|
102
242
|
dispatcherType: typeof dispatcher,
|
|
103
243
|
dispatcherConstructor: dispatcher?.constructor?.name || "unknown",
|
|
104
244
|
timestamp: new Date().toISOString(),
|
|
105
245
|
});
|
|
106
|
-
logger.debug(`[Proxy Fetch] 🌐 EXHAUSTIVE UNDICI FETCH CALL`, {
|
|
107
|
-
requestId,
|
|
108
|
-
aboutToCallUndici: true,
|
|
109
|
-
inputType: typeof input,
|
|
110
|
-
hasInit: !!init,
|
|
111
|
-
hasDispatcher: !!dispatcher,
|
|
112
|
-
timestamp: new Date().toISOString(),
|
|
113
|
-
});
|
|
114
|
-
// Use undici fetch with dispatcher
|
|
115
246
|
// Handle Request objects by extracting URL and merging properties
|
|
116
247
|
let fetchInput;
|
|
117
248
|
let fetchInit = { ...init };
|
|
118
249
|
if (input instanceof Request) {
|
|
119
250
|
fetchInput = input.url;
|
|
120
|
-
// Merge Request properties into init
|
|
121
251
|
fetchInit = {
|
|
122
252
|
method: input.method,
|
|
123
253
|
headers: input.headers,
|
|
@@ -128,63 +258,67 @@ export function createProxyFetch() {
|
|
|
128
258
|
else {
|
|
129
259
|
fetchInput = input;
|
|
130
260
|
}
|
|
261
|
+
// Use undici fetch with enhanced dispatcher (supports HTTP/HTTPS/SOCKS)
|
|
262
|
+
const undici = await import("undici");
|
|
131
263
|
const response = await undici.fetch(fetchInput, {
|
|
132
264
|
...fetchInit,
|
|
133
265
|
dispatcher: dispatcher,
|
|
134
266
|
});
|
|
135
|
-
logger.debug(`[Proxy Fetch] 🎉
|
|
267
|
+
logger.debug(`[Proxy Fetch] 🎉 ENHANCED PROXY SUCCESS`, {
|
|
136
268
|
requestId,
|
|
137
|
-
hasResponse: !!response,
|
|
138
269
|
responseStatus: response?.status,
|
|
139
|
-
responseStatusText: response?.statusText,
|
|
140
|
-
responseHeaders: response?.headers
|
|
141
|
-
? Object.fromEntries(response.headers.entries())
|
|
142
|
-
: "NO_HEADERS",
|
|
143
270
|
responseOk: response?.ok,
|
|
144
|
-
|
|
145
|
-
responseUrl: response?.url,
|
|
271
|
+
proxyUsed: true,
|
|
146
272
|
timestamp: new Date().toISOString(),
|
|
147
273
|
});
|
|
148
|
-
logger.debug(`[Proxy Fetch] ✅ Request proxied successfully
|
|
149
|
-
return response;
|
|
274
|
+
logger.debug(`[Proxy Fetch] ✅ Request proxied successfully via enhanced proxy`);
|
|
275
|
+
return response;
|
|
150
276
|
}
|
|
151
277
|
}
|
|
152
278
|
catch (error) {
|
|
153
279
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
154
|
-
logger.debug(`[Proxy Fetch] 💥
|
|
280
|
+
logger.debug(`[Proxy Fetch] 💥 ENHANCED ERROR ANALYSIS`, {
|
|
155
281
|
requestId,
|
|
156
282
|
error: errorMessage,
|
|
157
283
|
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
|
158
|
-
|
|
159
|
-
errorCode: error?.code || "NO_CODE",
|
|
160
|
-
errorSyscall: error?.syscall || "NO_SYSCALL",
|
|
161
|
-
errorAddress: error?.address || "NO_ADDRESS",
|
|
162
|
-
errorPort: error?.port || "NO_PORT",
|
|
284
|
+
willFallback: true,
|
|
163
285
|
timestamp: new Date().toISOString(),
|
|
164
286
|
});
|
|
165
|
-
logger.warn(`[Proxy Fetch]
|
|
287
|
+
logger.warn(`[Proxy Fetch] Enhanced proxy failed (${errorMessage}), falling back to direct connection`);
|
|
166
288
|
}
|
|
167
289
|
// Fallback to standard fetch
|
|
168
|
-
logger.debug(`[Proxy Fetch] 🔄
|
|
290
|
+
logger.debug(`[Proxy Fetch] 🔄 ENHANCED FALLBACK TO STANDARD FETCH`, {
|
|
169
291
|
requestId,
|
|
170
|
-
fallbackReason: "
|
|
292
|
+
fallbackReason: "No proxy configured or proxy failed",
|
|
171
293
|
timestamp: new Date().toISOString(),
|
|
172
294
|
});
|
|
173
295
|
return fetch(input, init);
|
|
174
296
|
};
|
|
175
297
|
}
|
|
176
298
|
/**
|
|
177
|
-
* Get proxy status information
|
|
299
|
+
* Get enhanced proxy status information
|
|
178
300
|
*/
|
|
179
301
|
export function getProxyStatus() {
|
|
180
302
|
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
181
303
|
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
304
|
+
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
|
|
305
|
+
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
|
|
182
306
|
const noProxy = process.env.NO_PROXY || process.env.no_proxy;
|
|
183
307
|
return {
|
|
184
|
-
enabled: !!(httpsProxy || httpProxy),
|
|
308
|
+
enabled: !!(httpsProxy || httpProxy || allProxy || socksProxy),
|
|
185
309
|
httpProxy: httpProxy || null,
|
|
186
310
|
httpsProxy: httpsProxy || null,
|
|
311
|
+
allProxy: allProxy || null,
|
|
312
|
+
socksProxy: socksProxy || null,
|
|
187
313
|
noProxy: noProxy || null,
|
|
188
|
-
method: "
|
|
314
|
+
method: "enhanced-proxy-agent",
|
|
315
|
+
capabilities: [
|
|
316
|
+
"HTTP/HTTPS Proxy",
|
|
317
|
+
"SOCKS4/SOCKS5 Proxy",
|
|
318
|
+
"Proxy Authentication",
|
|
319
|
+
"NO_PROXY Bypass",
|
|
320
|
+
"CIDR Range Matching",
|
|
321
|
+
"Wildcard Domain Matching",
|
|
322
|
+
],
|
|
189
323
|
};
|
|
190
324
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared NO_PROXY utility functions
|
|
3
|
+
* Extracted from awsProxyIntegration.ts and proxyFetch.ts to eliminate duplication
|
|
4
|
+
* Supports comprehensive NO_PROXY pattern matching including wildcards, domains, ports, and CIDR
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Comprehensive NO_PROXY bypass check supporting multiple pattern types
|
|
8
|
+
*
|
|
9
|
+
* Supported patterns:
|
|
10
|
+
* - "*" - bypass all requests
|
|
11
|
+
* - "example.com" - exact hostname match
|
|
12
|
+
* - ".example.com" - domain suffix match (matches example.com and subdomains)
|
|
13
|
+
* - "localhost:8080" - hostname with specific port
|
|
14
|
+
* - "192.168.1.0/24" - CIDR notation for IP ranges
|
|
15
|
+
*
|
|
16
|
+
* @param targetUrl - The URL to check for proxy bypass
|
|
17
|
+
* @param noProxyEnv - Optional NO_PROXY environment variable value (if not provided, reads from process.env)
|
|
18
|
+
* @returns true if the URL should bypass proxy, false otherwise
|
|
19
|
+
*/
|
|
20
|
+
export declare function shouldBypassProxy(targetUrl: string, noProxyEnv?: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current NO_PROXY environment variable value
|
|
23
|
+
* Checks both uppercase and lowercase variants
|
|
24
|
+
*/
|
|
25
|
+
export declare function getNoProxyEnv(): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Simple NO_PROXY bypass check with basic pattern support
|
|
28
|
+
* Legacy function for backward compatibility with simpler use cases
|
|
29
|
+
*
|
|
30
|
+
* Supports:
|
|
31
|
+
* - "*" - bypass all
|
|
32
|
+
* - "example.com" - exact match
|
|
33
|
+
* - ".example.com" - domain suffix match
|
|
34
|
+
*
|
|
35
|
+
* @param targetUrl - The URL to check
|
|
36
|
+
* @param noProxyValue - The NO_PROXY value to check against
|
|
37
|
+
* @returns true if should bypass proxy
|
|
38
|
+
*/
|
|
39
|
+
export declare function shouldBypassProxySimple(targetUrl: string, noProxyValue: string): boolean;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared NO_PROXY utility functions
|
|
3
|
+
* Extracted from awsProxyIntegration.ts and proxyFetch.ts to eliminate duplication
|
|
4
|
+
* Supports comprehensive NO_PROXY pattern matching including wildcards, domains, ports, and CIDR
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from "../../utils/logger.js";
|
|
7
|
+
/**
|
|
8
|
+
* Check if an IP address is within a CIDR range
|
|
9
|
+
*/
|
|
10
|
+
function isIpInCIDR(ip, cidr) {
|
|
11
|
+
try {
|
|
12
|
+
const [cidrIp, prefixLength] = cidr.split("/");
|
|
13
|
+
const prefix = parseInt(prefixLength, 10);
|
|
14
|
+
if (isNaN(prefix) || prefix < 0 || prefix > 32) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const ipToNumber = (ipStr) => {
|
|
18
|
+
const parts = ipStr.split(".").map(Number);
|
|
19
|
+
return (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3];
|
|
20
|
+
};
|
|
21
|
+
const ipNum = ipToNumber(ip);
|
|
22
|
+
const cidrIpNum = ipToNumber(cidrIp);
|
|
23
|
+
const mask = (-1 << (32 - prefix)) >>> 0;
|
|
24
|
+
return (ipNum & mask) === (cidrIpNum & mask);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Comprehensive NO_PROXY bypass check supporting multiple pattern types
|
|
32
|
+
*
|
|
33
|
+
* Supported patterns:
|
|
34
|
+
* - "*" - bypass all requests
|
|
35
|
+
* - "example.com" - exact hostname match
|
|
36
|
+
* - ".example.com" - domain suffix match (matches example.com and subdomains)
|
|
37
|
+
* - "localhost:8080" - hostname with specific port
|
|
38
|
+
* - "192.168.1.0/24" - CIDR notation for IP ranges
|
|
39
|
+
*
|
|
40
|
+
* @param targetUrl - The URL to check for proxy bypass
|
|
41
|
+
* @param noProxyEnv - Optional NO_PROXY environment variable value (if not provided, reads from process.env)
|
|
42
|
+
* @returns true if the URL should bypass proxy, false otherwise
|
|
43
|
+
*/
|
|
44
|
+
export function shouldBypassProxy(targetUrl, noProxyEnv) {
|
|
45
|
+
const noProxy = noProxyEnv || process.env.NO_PROXY || process.env.no_proxy;
|
|
46
|
+
if (!noProxy) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const url = new URL(targetUrl);
|
|
51
|
+
const hostname = url.hostname.toLowerCase();
|
|
52
|
+
const port = url.port || (url.protocol === "https:" ? "443" : "80");
|
|
53
|
+
const patterns = noProxy
|
|
54
|
+
.split(",")
|
|
55
|
+
.map((p) => p.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
for (const pattern of patterns) {
|
|
58
|
+
const lowerPattern = pattern.toLowerCase();
|
|
59
|
+
// Wildcard match - bypass all
|
|
60
|
+
if (lowerPattern === "*") {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// Domain suffix match (.example.com)
|
|
64
|
+
if (lowerPattern.startsWith(".")) {
|
|
65
|
+
const suffix = lowerPattern.slice(1);
|
|
66
|
+
if (hostname.endsWith(suffix) || hostname === suffix) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Port-specific match (hostname:port)
|
|
71
|
+
else if (lowerPattern.includes(":")) {
|
|
72
|
+
const [patternHost, patternPort] = lowerPattern.split(":");
|
|
73
|
+
if (hostname === patternHost && port === patternPort) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// CIDR notation (192.168.1.0/24) - only for IP addresses
|
|
78
|
+
else if (lowerPattern.includes("/")) {
|
|
79
|
+
// Only apply CIDR when target is an IP literal
|
|
80
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname) &&
|
|
81
|
+
isIpInCIDR(hostname, lowerPattern)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Exact hostname match
|
|
86
|
+
else if (hostname === lowerPattern) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
logger.warn("[Proxy] Error in NO_PROXY bypass logic", { targetUrl, error });
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the current NO_PROXY environment variable value
|
|
99
|
+
* Checks both uppercase and lowercase variants
|
|
100
|
+
*/
|
|
101
|
+
export function getNoProxyEnv() {
|
|
102
|
+
return process.env.NO_PROXY || process.env.no_proxy;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Simple NO_PROXY bypass check with basic pattern support
|
|
106
|
+
* Legacy function for backward compatibility with simpler use cases
|
|
107
|
+
*
|
|
108
|
+
* Supports:
|
|
109
|
+
* - "*" - bypass all
|
|
110
|
+
* - "example.com" - exact match
|
|
111
|
+
* - ".example.com" - domain suffix match
|
|
112
|
+
*
|
|
113
|
+
* @param targetUrl - The URL to check
|
|
114
|
+
* @param noProxyValue - The NO_PROXY value to check against
|
|
115
|
+
* @returns true if should bypass proxy
|
|
116
|
+
*/
|
|
117
|
+
export function shouldBypassProxySimple(targetUrl, noProxyValue) {
|
|
118
|
+
try {
|
|
119
|
+
const url = new URL(targetUrl);
|
|
120
|
+
const hostname = url.hostname.toLowerCase();
|
|
121
|
+
// Split NO_PROXY by comma and check each pattern
|
|
122
|
+
const patterns = noProxyValue.split(",").map((p) => p.trim().toLowerCase());
|
|
123
|
+
for (const pattern of patterns) {
|
|
124
|
+
if (!pattern) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Exact match
|
|
128
|
+
if (hostname === pattern) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
// Wildcard match (starts with .)
|
|
132
|
+
if (pattern.startsWith(".") && hostname.endsWith(pattern)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
// Simple wildcard
|
|
136
|
+
if (pattern === "*") {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
logger.warn("[Proxy] Error in simple NO_PROXY bypass logic", {
|
|
144
|
+
targetUrl,
|
|
145
|
+
error,
|
|
146
|
+
});
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -41,6 +41,49 @@ export interface AnalyticsData {
|
|
|
41
41
|
context?: JsonValue;
|
|
42
42
|
[key: string]: JsonValue | undefined;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* AWS Credential Configuration for Bedrock provider
|
|
46
|
+
*/
|
|
47
|
+
export interface AWSCredentialConfig {
|
|
48
|
+
region?: string;
|
|
49
|
+
profile?: string;
|
|
50
|
+
roleArn?: string;
|
|
51
|
+
roleSessionName?: string;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
/** @deprecated Prefer maxAttempts to match AWS SDK v3 config */
|
|
54
|
+
maxRetries?: number;
|
|
55
|
+
/** Number of attempts as per AWS SDK v3 ("retry-mode") */
|
|
56
|
+
maxAttempts?: number;
|
|
57
|
+
enableDebugLogging?: boolean;
|
|
58
|
+
/** Optional service endpoint override (e.g., VPC/Gov endpoints) */
|
|
59
|
+
endpoint?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* AWS Credential Validation Result
|
|
63
|
+
*/
|
|
64
|
+
export interface CredentialValidationResult {
|
|
65
|
+
isValid: boolean;
|
|
66
|
+
credentialSource: string;
|
|
67
|
+
region: string;
|
|
68
|
+
hasExpiration: boolean;
|
|
69
|
+
expirationTime?: Date;
|
|
70
|
+
error?: string;
|
|
71
|
+
debugInfo: {
|
|
72
|
+
accessKeyId: string;
|
|
73
|
+
hasSessionToken: boolean;
|
|
74
|
+
providerConfig: Readonly<Required<AWSCredentialConfig>>;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Service Connectivity Test Result
|
|
79
|
+
*/
|
|
80
|
+
export interface ServiceConnectivityResult {
|
|
81
|
+
bedrockAccessible: boolean;
|
|
82
|
+
availableModels: number;
|
|
83
|
+
responseTimeMs: number;
|
|
84
|
+
error?: string;
|
|
85
|
+
sampleModels: string[];
|
|
86
|
+
}
|
|
44
87
|
/**
|
|
45
88
|
* Model Capabilities - Maximally Reusable
|
|
46
89
|
*/
|
|
@@ -109,6 +109,7 @@ export declare function createGoogleAuthConfig(): ProviderConfigOptions;
|
|
|
109
109
|
export declare function createAnthropicBaseConfig(): ProviderConfigOptions;
|
|
110
110
|
/**
|
|
111
111
|
* Gets AWS Region with default fallback
|
|
112
|
+
* Supports both AWS_REGION and AWS_DEFAULT_REGION for broader compatibility
|
|
112
113
|
*/
|
|
113
114
|
export declare function getAWSRegion(): string;
|
|
114
115
|
/**
|