mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-14 09:38:00 -05:00
Compare commits
1 Commits
claude-cod
...
abhimanyuy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86b4731b90 |
@@ -1,16 +1,30 @@
|
||||
const BASE_URL = `${process.env.NEXT_PUBLIC_FRONTEND_BASE_URL}/api/proxy`; // Sending request via nextjs Server
|
||||
|
||||
console.log("🔧 Custom Mutator - Base URL:", BASE_URL);
|
||||
console.log("🔧 Environment variables:", {
|
||||
NEXT_PUBLIC_FRONTEND_BASE_URL: process.env.NEXT_PUBLIC_FRONTEND_BASE_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
});
|
||||
|
||||
const getBody = <T>(c: Response | Request): Promise<T> => {
|
||||
const contentType = c.headers.get("content-type");
|
||||
|
||||
console.log("📦 Parsing response body:", {
|
||||
contentType,
|
||||
headers: Object.fromEntries(c.headers.entries()),
|
||||
});
|
||||
|
||||
if (contentType && contentType.includes("application/json")) {
|
||||
console.log("📄 Parsing as JSON");
|
||||
return c.json();
|
||||
}
|
||||
|
||||
if (contentType && contentType.includes("application/pdf")) {
|
||||
console.log("📄 Parsing as PDF blob");
|
||||
return c.blob() as Promise<T>;
|
||||
}
|
||||
|
||||
console.log("📄 Parsing as text");
|
||||
return c.text() as Promise<T>;
|
||||
};
|
||||
|
||||
@@ -20,6 +34,8 @@ export const customMutator = async <T = any>(
|
||||
params?: any;
|
||||
} = {},
|
||||
): Promise<T> => {
|
||||
console.log("🚀 === CUSTOM MUTATOR START ===");
|
||||
|
||||
const { params, ...requestOptions } = options;
|
||||
const method = (requestOptions.method || "GET") as
|
||||
| "GET"
|
||||
@@ -32,6 +48,15 @@ export const customMutator = async <T = any>(
|
||||
...((requestOptions.headers as Record<string, string>) || {}),
|
||||
};
|
||||
|
||||
console.log("📋 Request preparation:", {
|
||||
url,
|
||||
method,
|
||||
params,
|
||||
hasBody: !!data,
|
||||
bodyType: data instanceof FormData ? "FormData" : typeof data,
|
||||
originalHeaders: requestOptions.headers,
|
||||
});
|
||||
|
||||
const isFormData = data instanceof FormData;
|
||||
|
||||
// Currently, only two content types are handled here: application/json and multipart/form-data
|
||||
@@ -43,18 +68,71 @@ export const customMutator = async <T = any>(
|
||||
? "?" + new URLSearchParams(params).toString()
|
||||
: "";
|
||||
|
||||
const response = await fetch(`${BASE_URL}${url}${queryString}`, {
|
||||
...requestOptions,
|
||||
const finalUrl = `${BASE_URL}${url}${queryString}`;
|
||||
|
||||
console.log("🎯 Final request details:", {
|
||||
finalUrl,
|
||||
method,
|
||||
headers,
|
||||
body: data,
|
||||
queryString,
|
||||
bodyPreview: isFormData
|
||||
? "FormData (entries hidden)"
|
||||
: data
|
||||
? String(data).substring(0, 200) +
|
||||
(String(data).length > 200 ? "..." : "")
|
||||
: "No body",
|
||||
});
|
||||
|
||||
const response_data = await getBody<T>(response);
|
||||
try {
|
||||
console.log("📡 Making fetch request...");
|
||||
const response = await fetch(finalUrl, {
|
||||
...requestOptions,
|
||||
method,
|
||||
headers,
|
||||
body: data,
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
data: response_data,
|
||||
headers: response.headers,
|
||||
} as T;
|
||||
console.log("📨 Response received:", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
ok: response.ok,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
url: response.url,
|
||||
});
|
||||
|
||||
const response_data = await getBody<T>(response);
|
||||
|
||||
console.log("✅ Response data parsed:", {
|
||||
dataType: typeof response_data,
|
||||
dataPreview:
|
||||
typeof response_data === "object"
|
||||
? JSON.stringify(response_data).substring(0, 200) + "..."
|
||||
: String(response_data).substring(0, 200),
|
||||
});
|
||||
|
||||
const result = {
|
||||
status: response.status,
|
||||
data: response_data,
|
||||
headers: response.headers,
|
||||
} as T;
|
||||
|
||||
console.log("🏁 === CUSTOM MUTATOR END ===");
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("💥 === CUSTOM MUTATOR FAILED ===");
|
||||
console.error("❌ Fetch error:", error);
|
||||
console.error("❌ Error details:", {
|
||||
name: error instanceof Error ? error.name : "Unknown",
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : "No stack trace",
|
||||
cause: error instanceof Error ? error.cause : undefined,
|
||||
});
|
||||
console.error("❌ Request context:", {
|
||||
finalUrl,
|
||||
method,
|
||||
headers,
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,9 +7,18 @@ import {
|
||||
const BACKEND_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_AGPT_SERVER_BASE_URL || "http://localhost:8006";
|
||||
|
||||
console.log("🔧 Proxy Route - Backend Base URL:", BACKEND_BASE_URL);
|
||||
|
||||
function buildBackendUrl(path: string[], queryString: string): string {
|
||||
const backendPath = path.join("/");
|
||||
return `${BACKEND_BASE_URL}/${backendPath}${queryString}`;
|
||||
const finalUrl = `${BACKEND_BASE_URL}/${backendPath}${queryString}`;
|
||||
console.log("🔗 Building backend URL:", {
|
||||
path,
|
||||
backendPath,
|
||||
queryString,
|
||||
finalUrl,
|
||||
});
|
||||
return finalUrl;
|
||||
}
|
||||
|
||||
async function handleJsonRequest(
|
||||
@@ -17,21 +26,37 @@ async function handleJsonRequest(
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
console.log("📝 Handling JSON request:", { method, backendUrl });
|
||||
const payload = await req.json();
|
||||
return await makeAuthenticatedRequest(
|
||||
console.log("📄 Request payload:", payload);
|
||||
|
||||
const result = await makeAuthenticatedRequest(
|
||||
method,
|
||||
backendUrl,
|
||||
payload,
|
||||
"application/json",
|
||||
);
|
||||
console.log("✅ JSON request completed successfully");
|
||||
return result;
|
||||
}
|
||||
|
||||
async function handleFormDataRequest(
|
||||
req: NextRequest,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
console.log("📁 Handling FormData request:", { backendUrl });
|
||||
const formData = await req.formData();
|
||||
return await makeAuthenticatedFileUpload(backendUrl, formData);
|
||||
console.log(
|
||||
"📄 FormData entries:",
|
||||
Array.from(formData.entries()).map(([key, value]) => ({
|
||||
key,
|
||||
value: value instanceof File ? `File: ${value.name}` : value,
|
||||
})),
|
||||
);
|
||||
|
||||
const result = await makeAuthenticatedFileUpload(backendUrl, formData);
|
||||
console.log("✅ FormData request completed successfully");
|
||||
return result;
|
||||
}
|
||||
|
||||
async function handleUrlEncodedRequest(
|
||||
@@ -39,22 +64,31 @@ async function handleUrlEncodedRequest(
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
console.log("🔤 Handling URL encoded request:", { method, backendUrl });
|
||||
const textPayload = await req.text();
|
||||
const params = new URLSearchParams(textPayload);
|
||||
const payload = Object.fromEntries(params.entries());
|
||||
return await makeAuthenticatedRequest(
|
||||
console.log("📄 URL encoded payload:", payload);
|
||||
|
||||
const result = await makeAuthenticatedRequest(
|
||||
method,
|
||||
backendUrl,
|
||||
payload,
|
||||
"application/x-www-form-urlencoded",
|
||||
);
|
||||
console.log("✅ URL encoded request completed successfully");
|
||||
return result;
|
||||
}
|
||||
|
||||
async function handleRequestWithoutBody(
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
return await makeAuthenticatedRequest(method, backendUrl);
|
||||
console.log("🚀 Handling request without body:", { method, backendUrl });
|
||||
|
||||
const result = await makeAuthenticatedRequest(method, backendUrl);
|
||||
console.log("✅ Request without body completed successfully");
|
||||
return result;
|
||||
}
|
||||
|
||||
function createUnsupportedContentTypeResponse(
|
||||
@@ -91,7 +125,17 @@ function createResponse(
|
||||
}
|
||||
|
||||
function createErrorResponse(error: unknown): NextResponse {
|
||||
console.error("API proxy error:", error);
|
||||
console.error("❌ API proxy error:", error);
|
||||
console.error(
|
||||
"❌ Error stack:",
|
||||
error instanceof Error ? error.stack : "No stack trace",
|
||||
);
|
||||
console.error("❌ Error details:", {
|
||||
name: error instanceof Error ? error.name : "Unknown",
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
cause: error instanceof Error ? error.cause : undefined,
|
||||
});
|
||||
|
||||
const detail =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return NextResponse.json(
|
||||
@@ -110,14 +154,32 @@ async function handler(
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ path: string[] }> },
|
||||
) {
|
||||
console.log("🚀 === PROXY REQUEST START ===");
|
||||
|
||||
const { path } = await params;
|
||||
const url = new URL(req.url);
|
||||
const queryString = url.search;
|
||||
|
||||
console.log("📋 Request details:", {
|
||||
method: req.method,
|
||||
originalUrl: req.url,
|
||||
path,
|
||||
queryString,
|
||||
headers: Object.fromEntries(req.headers.entries()),
|
||||
nextUrl: url.toString(),
|
||||
});
|
||||
|
||||
const backendUrl = buildBackendUrl(path, queryString);
|
||||
|
||||
const method = req.method;
|
||||
const contentType = req.headers.get("Content-Type");
|
||||
|
||||
console.log("🎯 Processing request:", {
|
||||
method,
|
||||
contentType,
|
||||
backendUrl,
|
||||
});
|
||||
|
||||
let responseBody: any;
|
||||
const responseStatus: number = 200;
|
||||
const responseHeaders: Record<string, string> = {
|
||||
@@ -126,20 +188,37 @@ async function handler(
|
||||
|
||||
try {
|
||||
if (method === "GET" || method === "DELETE") {
|
||||
console.log("🔄 Routing to handleRequestWithoutBody");
|
||||
responseBody = await handleRequestWithoutBody(method, backendUrl);
|
||||
} else if (contentType?.includes("application/json")) {
|
||||
console.log("🔄 Routing to handleJsonRequest");
|
||||
responseBody = await handleJsonRequest(req, method, backendUrl);
|
||||
} else if (contentType?.includes("multipart/form-data")) {
|
||||
console.log("🔄 Routing to handleFormDataRequest");
|
||||
responseBody = await handleFormDataRequest(req, backendUrl);
|
||||
responseHeaders["Content-Type"] = "text/plain";
|
||||
} else if (contentType?.includes("application/x-www-form-urlencoded")) {
|
||||
console.log("🔄 Routing to handleUrlEncodedRequest");
|
||||
responseBody = await handleUrlEncodedRequest(req, method, backendUrl);
|
||||
} else {
|
||||
console.log("❌ Unsupported content type:", contentType);
|
||||
return createUnsupportedContentTypeResponse(contentType);
|
||||
}
|
||||
|
||||
console.log("✅ Request processed successfully:", {
|
||||
responseStatus,
|
||||
responseHeaders,
|
||||
responseBodyType: typeof responseBody,
|
||||
responseBodyPreview:
|
||||
typeof responseBody === "object"
|
||||
? JSON.stringify(responseBody).substring(0, 200) + "..."
|
||||
: String(responseBody).substring(0, 200),
|
||||
});
|
||||
|
||||
console.log("🏁 === PROXY REQUEST END ===");
|
||||
return createResponse(responseBody, responseStatus, responseHeaders);
|
||||
} catch (error) {
|
||||
console.log("💥 === PROXY REQUEST FAILED ===");
|
||||
return createErrorResponse(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,25 +18,40 @@ export function buildRequestUrl(
|
||||
}
|
||||
|
||||
export async function getServerAuthToken(): Promise<string> {
|
||||
console.log("🔐 Getting server auth token...");
|
||||
|
||||
const supabase = await getServerSupabase();
|
||||
|
||||
if (!supabase) {
|
||||
console.error("❌ Supabase client not available");
|
||||
throw new Error("Supabase client not available");
|
||||
}
|
||||
|
||||
console.log("✅ Supabase client obtained");
|
||||
|
||||
try {
|
||||
const {
|
||||
data: { session },
|
||||
error,
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
console.log("🔍 Session check:", {
|
||||
hasSession: !!session,
|
||||
hasAccessToken: !!session?.access_token,
|
||||
hasError: !!error,
|
||||
errorMessage: error?.message,
|
||||
userId: session?.user?.id,
|
||||
});
|
||||
|
||||
if (error || !session?.access_token) {
|
||||
console.warn("⚠️ No valid session or access token found");
|
||||
return "no-token-found";
|
||||
}
|
||||
|
||||
console.log("✅ Valid access token obtained");
|
||||
return session.access_token;
|
||||
} catch (error) {
|
||||
console.error("Failed to get auth token:", error);
|
||||
console.error("❌ Failed to get auth token:", error);
|
||||
return "no-token-found";
|
||||
}
|
||||
}
|
||||
@@ -46,6 +61,16 @@ export function createRequestHeaders(
|
||||
hasRequestBody: boolean,
|
||||
contentType: string = "application/json",
|
||||
): Record<string, string> {
|
||||
console.log("📋 Creating request headers:", {
|
||||
hasToken: token !== "no-token-found",
|
||||
tokenPreview:
|
||||
token !== "no-token-found"
|
||||
? `${token.substring(0, 10)}...`
|
||||
: "no-token-found",
|
||||
hasRequestBody,
|
||||
contentType,
|
||||
});
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (hasRequestBody) {
|
||||
@@ -56,6 +81,12 @@ export function createRequestHeaders(
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
console.log("🏷️ Headers created:", {
|
||||
headerKeys: Object.keys(headers),
|
||||
hasAuth: !!headers["Authorization"],
|
||||
hasContentType: !!headers["Content-Type"],
|
||||
});
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -157,49 +188,121 @@ export async function makeAuthenticatedRequest(
|
||||
payload?: Record<string, any>,
|
||||
contentType: string = "application/json",
|
||||
): Promise<any> {
|
||||
console.log("🔐 === AUTHENTICATED REQUEST START ===");
|
||||
console.log("📋 Request details:", {
|
||||
method,
|
||||
url,
|
||||
contentType,
|
||||
hasPayload: !!payload,
|
||||
payloadPreview: payload
|
||||
? JSON.stringify(payload).substring(0, 100) + "..."
|
||||
: "No payload",
|
||||
});
|
||||
|
||||
const token = await getServerAuthToken();
|
||||
const payloadAsQuery = ["GET", "DELETE"].includes(method);
|
||||
const hasRequestBody = !payloadAsQuery && payload !== undefined;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: createRequestHeaders(token, hasRequestBody, contentType),
|
||||
body: hasRequestBody
|
||||
? serializeRequestBody(payload, contentType)
|
||||
: undefined,
|
||||
console.log("🎯 Request configuration:", {
|
||||
payloadAsQuery,
|
||||
hasRequestBody,
|
||||
tokenAvailable: token !== "no-token-found",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorDetail = await parseApiError(response);
|
||||
const headers = createRequestHeaders(token, hasRequestBody, contentType);
|
||||
const body = hasRequestBody
|
||||
? serializeRequestBody(payload, contentType)
|
||||
: undefined;
|
||||
|
||||
// Handle authentication errors gracefully during logout
|
||||
if (isAuthenticationError(response, errorDetail)) {
|
||||
if (isLogoutInProgress()) {
|
||||
// Silently return null during logout to prevent error noise
|
||||
console.debug(
|
||||
"Authentication request failed during logout, ignoring:",
|
||||
errorDetail,
|
||||
);
|
||||
console.log("📡 Making fetch request to:", url);
|
||||
console.log(
|
||||
"📤 Request body preview:",
|
||||
body ? String(body).substring(0, 200) + "..." : "No body",
|
||||
);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
console.log("📨 Response received:", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
ok: response.ok,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
url: response.url,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorDetail = await parseApiError(response);
|
||||
console.error("❌ Request failed:", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
errorDetail,
|
||||
});
|
||||
|
||||
// Handle authentication errors gracefully during logout
|
||||
if (isAuthenticationError(response, errorDetail)) {
|
||||
if (isLogoutInProgress()) {
|
||||
// Silently return null during logout to prevent error noise
|
||||
console.debug(
|
||||
"Authentication request failed during logout, ignoring:",
|
||||
errorDetail,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// For authentication errors outside logout, log but don't throw
|
||||
// This prevents crashes when session expires naturally
|
||||
console.warn("Authentication failed:", errorDetail);
|
||||
return null;
|
||||
}
|
||||
|
||||
// For authentication errors outside logout, log but don't throw
|
||||
// This prevents crashes when session expires naturally
|
||||
console.warn("Authentication failed:", errorDetail);
|
||||
return null;
|
||||
// For other errors, throw as normal
|
||||
throw new Error(errorDetail);
|
||||
}
|
||||
|
||||
// For other errors, throw as normal
|
||||
throw new Error(errorDetail);
|
||||
}
|
||||
const responseData = await parseApiResponse(response);
|
||||
console.log("✅ Request completed successfully");
|
||||
console.log(
|
||||
"📦 Response data preview:",
|
||||
responseData
|
||||
? JSON.stringify(responseData).substring(0, 200) + "..."
|
||||
: "No data",
|
||||
);
|
||||
console.log("🏁 === AUTHENTICATED REQUEST END ===");
|
||||
|
||||
return parseApiResponse(response);
|
||||
return responseData;
|
||||
} catch (error) {
|
||||
console.error("💥 === AUTHENTICATED REQUEST FAILED ===");
|
||||
console.error("❌ Fetch error:", error);
|
||||
console.error("❌ Error details:", {
|
||||
name: error instanceof Error ? error.name : "Unknown",
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : "No stack trace",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function makeAuthenticatedFileUpload(
|
||||
url: string,
|
||||
formData: FormData,
|
||||
): Promise<string> {
|
||||
console.log("📁 === AUTHENTICATED FILE UPLOAD START ===");
|
||||
console.log("📋 Upload details:", {
|
||||
url,
|
||||
formDataEntries: Array.from(formData.entries()).map(([key, value]) => ({
|
||||
key,
|
||||
value:
|
||||
value instanceof File
|
||||
? `File: ${value.name} (${value.size} bytes)`
|
||||
: value,
|
||||
})),
|
||||
});
|
||||
|
||||
const token = await getServerAuthToken();
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
@@ -207,30 +310,68 @@ export async function makeAuthenticatedFileUpload(
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// Don't set Content-Type for FormData - let the browser set it with boundary
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: formData,
|
||||
console.log("🏷️ Upload headers:", {
|
||||
hasAuth: !!headers["Authorization"],
|
||||
headerKeys: Object.keys(headers),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Handle authentication errors gracefully for file uploads too
|
||||
const errorMessage = `Error uploading file: ${response.statusText}`;
|
||||
console.log("📡 Making file upload request to:", url);
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
if (isLogoutInProgress()) {
|
||||
console.debug(
|
||||
"File upload authentication failed during logout, ignoring",
|
||||
);
|
||||
try {
|
||||
// Don't set Content-Type for FormData - let the browser set it with boundary
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: formData,
|
||||
});
|
||||
|
||||
console.log("📨 Upload response received:", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
ok: response.ok,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Handle authentication errors gracefully for file uploads too
|
||||
const errorMessage = `Error uploading file: ${response.statusText}`;
|
||||
console.error("❌ File upload failed:", {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
errorMessage,
|
||||
});
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
if (isLogoutInProgress()) {
|
||||
console.debug(
|
||||
"File upload authentication failed during logout, ignoring",
|
||||
);
|
||||
return "";
|
||||
}
|
||||
console.warn("File upload authentication failed:", errorMessage);
|
||||
return "";
|
||||
}
|
||||
console.warn("File upload authentication failed:", errorMessage);
|
||||
return "";
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
const responseText = await response.text();
|
||||
console.log("✅ File upload completed successfully");
|
||||
console.log(
|
||||
"📦 Upload response preview:",
|
||||
responseText.substring(0, 200) + "...",
|
||||
);
|
||||
console.log("🏁 === AUTHENTICATED FILE UPLOAD END ===");
|
||||
|
||||
return await response.text();
|
||||
return responseText;
|
||||
} catch (error) {
|
||||
console.error("💥 === AUTHENTICATED FILE UPLOAD FAILED ===");
|
||||
console.error("❌ Upload error:", error);
|
||||
console.error("❌ Error details:", {
|
||||
name: error instanceof Error ? error.name : "Unknown",
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : "No stack trace",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user