Compare commits

...

1 Commits

Author SHA1 Message Date
abhi1992002
86b4731b90 Add detailed logging for API requests and responses 2025-07-01 09:49:04 +05:30
3 changed files with 356 additions and 58 deletions

View File

@@ -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;
}
};

View File

@@ -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);
}
}

View File

@@ -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;
}
}