@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
666 lines • 25.7 kB
JavaScript
/**
* Enhanced proxy-aware fetch implementation for AI SDK providers
* Supports HTTP/HTTPS, SOCKS4/5, authentication, and NO_PROXY bypass
* Lightweight implementation extracted from research of major proxy packages
*/
import { logger } from "../utils/logger.js";
import { SpanStatusCode, propagation, context } from "@opentelemetry/api";
import { tracers } from "../telemetry/tracers.js";
import { shouldBypassProxy } from "./utils/noProxyUtils.js";
import { createHash } from "node:crypto";
async function getLangfuseContext() {
try {
// Dynamic import to avoid hard dependency — getLangfuseContext is only
// available when the observability module is loaded.
const mod = await import("../services/server/ai/observability/instrumentation.js");
return mod.getLangfuseContext?.();
}
catch {
return undefined;
}
}
/**
* Inject OTel trace context (traceparent/tracestate) and NeuroLink session context
* into outgoing request headers. This enables:
* - The NeuroLink proxy to link proxy spans as children of the calling SDK's trace
* - Conversation-level session/user attribution on proxy spans
*/
function mergeTraceHeaders(input, init) {
const existingHeaders = new Headers(input instanceof Request ? input.headers : undefined);
if (init?.headers) {
const initHeaders = new Headers(init.headers);
for (const [key, value] of initHeaders.entries()) {
existingHeaders.set(key, value);
}
}
return existingHeaders;
}
async function injectTraceContext(input, init) {
const carrier = {};
propagation.inject(context.active(), carrier);
// Also inject NeuroLink session context from Langfuse AsyncLocalStorage
const langfuseContext = await getLangfuseContext();
if (langfuseContext?.sessionId) {
carrier["x-neurolink-session-id"] = langfuseContext.sessionId;
}
if (langfuseContext?.userId) {
carrier["x-neurolink-user-id"] = langfuseContext.userId;
}
if (langfuseContext?.conversationId) {
carrier["x-neurolink-conversation-id"] = langfuseContext.conversationId;
}
if (Object.keys(carrier).length === 0) {
return init ?? {};
}
const existingHeaders = mergeTraceHeaders(input, init);
for (const [key, value] of Object.entries(carrier)) {
if (!existingHeaders.has(key)) {
existingHeaders.set(key, value);
}
}
return { ...init, headers: existingHeaders };
}
const fetchTracer = tracers.http;
/**
* Extract hostname from a URL string for safe logging (no auth tokens or paths).
* Returns "[unknown]" if parsing fails.
*/
function extractHostname(url) {
try {
const urlStr = typeof url === "string"
? url
: url instanceof URL
? url.href
: url.url;
const parsed = new URL(urlStr);
return parsed.hostname;
}
catch {
return "[unknown]";
}
}
/**
* Retry-aware fetch wrapper for transient network errors (ECONNRESET, ETIMEDOUT, socket hang up).
* Protects all LLM API calls and token refreshes that go through createProxyFetch().
* Instrumented with OpenTelemetry spans for retry visibility.
*/
async function fetchWithRetry(url, init, maxRetries = 3, baseDelay = 500) {
const hostname = extractHostname(url);
return fetchTracer.startActiveSpan("neurolink.http.fetchWithRetry", async (span) => {
span.setAttribute("http.request.max_retries", maxRetries);
span.setAttribute("http.request.hostname", hostname);
span.setAttribute("http.request.method", init?.method || "GET");
// eslint-disable-next-line no-useless-assignment
let totalAttempts = 0;
try {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
totalAttempts = attempt + 1;
try {
const response = await fetch(url, init);
// Record success attributes
span.setAttribute("http.request.total_attempts", totalAttempts);
span.setAttribute("http.response.status_code", response.status);
span.setStatus({ code: SpanStatusCode.OK });
return response;
}
catch (error) {
const err = error;
const isRetryable = err?.code === "ECONNRESET" ||
err?.code === "ETIMEDOUT" ||
err?.message?.includes("socket hang up") ||
err?.message?.includes("network socket disconnected");
if (!isRetryable || attempt === maxRetries) {
// Final failure — record on span and rethrow
span.setAttribute("http.request.total_attempts", totalAttempts);
span.setStatus({
code: SpanStatusCode.ERROR,
message: err?.message || err?.code || "fetchWithRetry final failure",
});
span.recordException(error instanceof Error ? error : new Error(String(error)));
throw error;
}
// Transient error — add retry event and continue loop
const delay = baseDelay * Math.pow(2, attempt);
span.addEvent("http.request.retry", {
"retry.attempt": attempt + 1,
"retry.delay_ms": delay,
"retry.error": (err?.code || err?.message || String(error)).slice(0, 256),
});
logger.debug(`[fetchWithRetry] Transient error (${err?.code || err?.message}), retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`);
await new Promise((r) => setTimeout(r, delay));
}
}
throw new Error("fetchWithRetry exhausted"); // unreachable
}
finally {
span.end();
}
});
}
/**
* Parse request body to readable format for debug logging
*/
function parseBody(body) {
if (!body) {
return { parsed: null, size: 0, type: "empty" };
}
if (typeof body === "string") {
try {
return { parsed: JSON.parse(body), size: body.length, type: "json" };
}
catch {
return { parsed: body, size: body.length, type: "text" };
}
}
if (body instanceof ArrayBuffer) {
return {
parsed: "[ArrayBuffer]",
size: body.byteLength,
type: "arraybuffer",
};
}
if (body instanceof Uint8Array) {
return { parsed: "[Uint8Array]", size: body.length, type: "uint8array" };
}
return { parsed: "[Stream]", size: -1, type: "stream" };
}
/**
* Sensitive header names whose values should be redacted in logs
*/
const SENSITIVE_HEADERS = new Set([
"authorization",
"x-api-key",
"api-key",
"x-goog-api-key",
"proxy-authorization",
"cookie",
"set-cookie",
]);
/**
* Clone response and read body + headers for debug logging
*/
async function readResponseBody(response) {
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = SENSITIVE_HEADERS.has(key.toLowerCase())
? `${value.substring(0, 4)}***`
: value;
});
try {
const cloned = response.clone();
const text = await cloned.text();
try {
return {
parsed: JSON.parse(text),
size: text.length,
type: "json",
headers,
};
}
catch {
return { parsed: text, size: text.length, type: "text", headers };
}
}
catch {
return {
parsed: "[unable to read body]",
size: -1,
type: "error",
headers,
};
}
}
// ==================== LIGHTWEIGHT PROXY IMPLEMENTATIONS ====================
// ParsedProxyConfig interface moved to ../types/utilities.js
/**
* Parse proxy URL with authentication support
*/
function parseProxyUrl(proxyUrl) {
try {
const url = new URL(proxyUrl);
const config = {
protocol: url.protocol,
hostname: url.hostname,
port: parseInt(url.port) || getDefaultPort(url.protocol),
cleanUrl: `${url.protocol}//${url.hostname}:${url.port || getDefaultPort(url.protocol)}`,
};
// Extract authentication if present
if (url.username && url.password) {
config.auth = {
username: decodeURIComponent(url.username),
password: decodeURIComponent(url.password),
};
}
return config;
}
catch (error) {
// Sanitize proxy URL to avoid leaking credentials in logs/errors
let safeUrl;
try {
const u = new URL(proxyUrl);
u.username = "";
u.password = "";
safeUrl = u.toString();
}
catch {
safeUrl = "[invalid-url]";
}
logger.error("[Proxy] Failed to parse proxy URL", {
proxyUrl: safeUrl,
error,
});
throw new Error(`Invalid proxy URL: ${safeUrl}`, { cause: error });
}
}
/**
* Get default port for protocol
*/
function getDefaultPort(protocol) {
switch (protocol) {
case "http:":
return 8080;
case "https:":
return 8080;
case "socks4:":
return 1080;
case "socks5:":
return 1080;
default:
return 8080;
}
}
/**
* Select appropriate proxy URL based on target and environment
*/
function selectProxyUrl(targetUrl) {
// Check NO_PROXY bypass first
if (shouldBypassProxy(targetUrl)) {
logger.debug("[Proxy] Bypassing proxy due to NO_PROXY", { targetUrl });
return null;
}
try {
const url = new URL(targetUrl);
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
// Priority: Protocol-specific > ALL_PROXY > SOCKS_PROXY
if (url.protocol === "https:" && httpsProxy) {
return httpsProxy;
}
if (url.protocol === "http:" && httpProxy) {
return httpProxy;
}
if (allProxy) {
return allProxy;
}
if (socksProxy) {
return socksProxy;
}
return null;
}
catch (error) {
logger.warn("[Proxy] Error selecting proxy URL", { targetUrl, error });
return null;
}
}
/**
* Create appropriate proxy agent based on protocol
*/
async function createProxyAgent(proxyUrl) {
const parsed = parseProxyUrl(proxyUrl);
logger.debug("[Proxy] Creating proxy agent", {
protocol: parsed.protocol,
hostname: parsed.hostname,
port: parsed.port,
hasAuth: !!parsed.auth,
});
switch (parsed.protocol) {
case "http:":
case "https:": {
// Use existing undici ProxyAgent for HTTP/HTTPS
const { ProxyAgent } = await import("undici");
return new ProxyAgent(proxyUrl);
}
case "socks4:":
case "socks5:": {
// SOCKS proxy support is not included in the build to avoid optional dependencies
throw new Error(`SOCKS proxy support requires 'proxy-agent' package. ` +
`Install it with: npm install proxy-agent`);
}
default:
throw new Error(`Unsupported proxy protocol: ${parsed.protocol}`);
}
}
function sanitizeProxyUrl(url) {
return maskProxyUrl(url) ?? "NOT_SET";
}
function getTargetUrl(input) {
return typeof input === "string"
? input
: input instanceof URL
? input.href
: input.url;
}
function createDirectFetchHandler() {
return async (input, init) => {
const enrichedInit = await injectTraceContext(input, init);
const reqId = `req-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
const startTs = Date.now();
const url = getTargetUrl(input);
if (logger.shouldLog("debug")) {
const { size: bodySize, type: bodyType } = parseBody(enrichedInit?.body);
logger.debug("[Observability] HTTP request to LLM provider", {
requestId: reqId,
url,
method: enrichedInit?.method || "POST",
bodySize,
bodyType,
});
}
try {
const response = await fetchWithRetry(input, enrichedInit);
if (logger.shouldLog("debug")) {
const { parsed: responseBody, size: responseSize, type: responseType, headers: responseHeaders, } = await readResponseBody(response);
logger.debug("[Observability] HTTP response from LLM provider", {
requestId: reqId,
url,
status: response.status,
statusText: response.statusText,
durationMs: Date.now() - startTs,
contentLength: responseSize,
hasContent: !!responseBody,
bodyType: responseType,
responseHeaders,
});
}
return response;
}
catch (error) {
logger.debug("[Observability] HTTP request failed", {
requestId: reqId,
url,
error: error instanceof Error ? error.message : String(error),
durationMs: Date.now() - startTs,
});
throw error;
}
};
}
async function executeProxiedFetch(input, init, proxyEnv) {
const { httpsProxy, httpProxy, allProxy, socksProxy, noProxy } = proxyEnv;
init = await injectTraceContext(input, init);
const requestId = `req-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
const requestStartTime = Date.now();
const targetUrl = getTargetUrl(input);
if (logger.shouldLog("debug")) {
const { size: bodySize, type: bodyType } = parseBody(init?.body);
logger.debug("[Observability] HTTP request to LLM provider", {
requestId,
url: targetUrl,
method: init?.method || "POST",
bodySize,
bodyType,
});
}
logger.debug(`[Proxy Fetch] ENHANCED REQUEST START`, {
requestId,
targetUrl,
timestamp: new Date().toISOString(),
httpProxy: sanitizeProxyUrl(httpProxy),
httpsProxy: sanitizeProxyUrl(httpsProxy),
allProxy: sanitizeProxyUrl(allProxy),
socksProxy: sanitizeProxyUrl(socksProxy),
noProxy: noProxy || "NOT_SET",
initMethod: init?.method || "GET",
});
// Clone the request before any proxy attempt so that if the proxy path
// consumes the body stream and then fails, the fallback still has an intact
// body to send.
const requestClone = input instanceof Request ? input.clone() : null;
try {
const proxyUrl = selectProxyUrl(targetUrl);
if (proxyUrl) {
const url = new URL(targetUrl);
logger.debug(`[Proxy Fetch] 🔗 ENHANCED URL ANALYSIS`, {
requestId,
targetUrl,
urlHostname: url.hostname,
urlProtocol: url.protocol,
urlPort: url.port,
selectedProxyUrl: sanitizeProxyUrl(proxyUrl),
timestamp: new Date().toISOString(),
});
logger.debug(`[Proxy Fetch] 🎯 ENHANCED PROXY AGENT CREATION`, {
requestId,
proxyUrl: sanitizeProxyUrl(proxyUrl),
targetHostname: url.hostname,
targetProtocol: url.protocol,
aboutToCreateProxyAgent: true,
timestamp: new Date().toISOString(),
});
const globalWithCache = globalThis;
if (!globalWithCache.__NL_PROXY_AGENT_CACHE__) {
globalWithCache.__NL_PROXY_AGENT_CACHE__ = new Map();
}
const agentCache = globalWithCache.__NL_PROXY_AGENT_CACHE__;
const cacheKey = createHash("sha256")
.update(maskProxyUrl(proxyUrl) ?? proxyUrl)
.digest("hex");
const dispatcher = agentCache.get(cacheKey) || (await createProxyAgent(proxyUrl));
agentCache.set(cacheKey, dispatcher);
logger.debug(`[Proxy Fetch] ✅ ENHANCED PROXY AGENT CREATED`, {
requestId,
hasDispatcher: !!dispatcher,
dispatcherType: typeof dispatcher,
dispatcherConstructor: dispatcher?.constructor?.name || "unknown",
timestamp: new Date().toISOString(),
});
let fetchInput;
let fetchInit = { ...init };
if (input instanceof Request) {
fetchInput = input.url;
fetchInit = {
method: input.method,
headers: input.headers,
body: input.body,
...init,
};
}
else {
fetchInput = input;
}
const undici = await import("undici");
const response = await undici.fetch(fetchInput, {
...fetchInit,
dispatcher,
});
if (logger.shouldLog("debug")) {
const { parsed: responseBody, size: responseSize, type: responseType, headers: responseHeaders, } = await readResponseBody(response);
logger.debug("[Observability] HTTP response from LLM provider", {
requestId,
url: targetUrl,
status: response?.status,
statusText: response?.statusText,
durationMs: Date.now() - requestStartTime,
contentLength: responseSize,
hasContent: !!responseBody,
bodyType: responseType,
proxied: true,
responseHeaders,
});
}
logger.debug(`[Proxy Fetch] ENHANCED PROXY SUCCESS`, {
requestId,
responseStatus: response?.status,
responseOk: response?.ok,
proxyUsed: true,
timestamp: new Date().toISOString(),
});
return response;
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug("[Observability] HTTP request failed", {
requestId,
url: targetUrl,
error: errorMessage,
durationMs: Date.now() - requestStartTime,
});
logger.debug(`[Proxy Fetch] ENHANCED ERROR ANALYSIS`, {
requestId,
error: errorMessage,
errorType: error instanceof Error ? error.constructor.name : typeof error,
willFallback: true,
timestamp: new Date().toISOString(),
});
logger.warn(`[Proxy Fetch] Enhanced proxy failed (${errorMessage}), falling back to direct connection`);
}
logger.debug(`[Proxy Fetch] ENHANCED FALLBACK TO STANDARD FETCH`, {
requestId,
fallbackReason: "No proxy configured or proxy failed",
timestamp: new Date().toISOString(),
});
// Use the cloned request for the fallback so that the body stream is not
// already consumed from the proxy attempt above.
const fallbackInput = (input instanceof Request ? (requestClone ?? input) : input);
try {
const response = await fetchWithRetry(fallbackInput, init);
if (logger.shouldLog("debug")) {
const { parsed: responseBody, size: responseSize, type: responseType, headers: responseHeaders, } = await readResponseBody(response);
logger.debug("[Observability] HTTP response from LLM provider", {
requestId,
url: targetUrl,
status: response.status,
statusText: response.statusText,
durationMs: Date.now() - requestStartTime,
contentLength: responseSize,
hasContent: !!responseBody,
bodyType: responseType,
proxied: false,
responseHeaders,
});
}
return response;
}
catch (fallbackError) {
const fallbackMessage = fallbackError instanceof Error
? fallbackError.message
: String(fallbackError);
logger.debug("[Observability] HTTP request failed", {
requestId,
url: targetUrl,
error: fallbackMessage,
durationMs: Date.now() - requestStartTime,
});
throw fallbackError;
}
}
function createProxiedFetchHandler(proxyEnv) {
return async (input, init) => executeProxiedFetch(input, init, proxyEnv);
}
// ==================== ENHANCED PROXY FETCH FUNCTION ====================
/**
* Create a proxy-aware fetch function with enhanced capabilities
* Supports HTTP/HTTPS, SOCKS4/5, authentication, and NO_PROXY bypass
*/
export function createProxyFetch() {
// Detect ALL proxy-related environment variables
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
const noProxy = process.env.NO_PROXY || process.env.no_proxy;
const proxyEnv = {
httpsProxy,
httpProxy,
allProxy,
socksProxy,
noProxy,
};
// ENHANCED LOGGING: Capture ALL proxy-related environment variables — credentials redacted
if (logger.shouldLog("debug")) {
const allProxyRelatedEnvVars = Object.keys(process.env)
.filter((key) => key.toLowerCase().includes("proxy"))
.reduce((acc, key) => {
const val = process.env[key] || "NOT_SET";
acc[key] =
key.toLowerCase() === "no_proxy" ? val : sanitizeProxyUrl(val);
return acc;
}, {});
logger.debug("[Proxy Fetch] ENHANCED_PROXY_ENV_DETECTION", {
httpProxy: sanitizeProxyUrl(httpProxy),
httpsProxy: sanitizeProxyUrl(httpsProxy),
allProxy: sanitizeProxyUrl(allProxy),
socksProxy: sanitizeProxyUrl(socksProxy),
noProxy: noProxy || "NOT_SET",
allProxyRelatedEnvVars,
message: "Enhanced proxy environment detection — credentials redacted",
});
}
// If no proxy configured, return instrumented standard fetch
if (!httpsProxy && !httpProxy && !allProxy && !socksProxy) {
logger.debug("[Proxy Fetch] No proxy environment variables found - using standard fetch");
return createDirectFetchHandler();
}
logger.debug(`[Proxy Fetch] Configuring enhanced proxy with multiple protocol support`);
logger.debug(`[Proxy Fetch] HTTP_PROXY: ${sanitizeProxyUrl(httpProxy)}`);
logger.debug(`[Proxy Fetch] HTTPS_PROXY: ${sanitizeProxyUrl(httpsProxy)}`);
logger.debug(`[Proxy Fetch] ALL_PROXY: ${sanitizeProxyUrl(allProxy)}`);
logger.debug(`[Proxy Fetch] SOCKS_PROXY: ${sanitizeProxyUrl(socksProxy)}`);
logger.debug(`[Proxy Fetch] NO_PROXY: ${noProxy || "not set"}`);
return createProxiedFetchHandler(proxyEnv);
}
/**
* Mask credentials in a proxy URL for safe logging/reporting.
*
* Exported so provider-side fetch loggers (lmStudio, llamaCpp, deepseek,
* nvidiaNim) can sanitize upstream URLs before emitting warnings — reverse-
* proxied deployments can embed credentials or signed query params in the
* base URL, and those should never reach application logs verbatim.
*/
export function maskProxyUrl(url) {
if (!url) {
return null;
}
try {
const u = new URL(url);
if (u.username || u.password) {
u.username = "***";
u.password = "***";
}
return u.toString();
}
catch {
return "[invalid-url]";
}
}
/**
* Get enhanced proxy status information
*/
export function getProxyStatus() {
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
const noProxy = process.env.NO_PROXY || process.env.no_proxy;
return {
enabled: !!(httpsProxy || httpProxy || allProxy || socksProxy),
httpProxy: maskProxyUrl(httpProxy),
httpsProxy: maskProxyUrl(httpsProxy),
allProxy: maskProxyUrl(allProxy),
socksProxy: maskProxyUrl(socksProxy),
noProxy: noProxy || null,
method: "enhanced-proxy-agent",
capabilities: [
"HTTP/HTTPS Proxy",
"SOCKS4/SOCKS5 Proxy",
"Proxy Authentication",
"NO_PROXY Bypass",
"CIDR Range Matching",
"Wildcard Domain Matching",
],
};
}
//# sourceMappingURL=proxyFetch.js.map