mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-09 22:35:54 -05:00
Compare commits
1 Commits
fix/vector
...
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
|
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 getBody = <T>(c: Response | Request): Promise<T> => {
|
||||||
const contentType = c.headers.get("content-type");
|
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")) {
|
if (contentType && contentType.includes("application/json")) {
|
||||||
|
console.log("📄 Parsing as JSON");
|
||||||
return c.json();
|
return c.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType && contentType.includes("application/pdf")) {
|
if (contentType && contentType.includes("application/pdf")) {
|
||||||
|
console.log("📄 Parsing as PDF blob");
|
||||||
return c.blob() as Promise<T>;
|
return c.blob() as Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("📄 Parsing as text");
|
||||||
return c.text() as Promise<T>;
|
return c.text() as Promise<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,6 +34,8 @@ export const customMutator = async <T = any>(
|
|||||||
params?: any;
|
params?: any;
|
||||||
} = {},
|
} = {},
|
||||||
): Promise<T> => {
|
): Promise<T> => {
|
||||||
|
console.log("🚀 === CUSTOM MUTATOR START ===");
|
||||||
|
|
||||||
const { params, ...requestOptions } = options;
|
const { params, ...requestOptions } = options;
|
||||||
const method = (requestOptions.method || "GET") as
|
const method = (requestOptions.method || "GET") as
|
||||||
| "GET"
|
| "GET"
|
||||||
@@ -32,6 +48,15 @@ export const customMutator = async <T = any>(
|
|||||||
...((requestOptions.headers as Record<string, string>) || {}),
|
...((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;
|
const isFormData = data instanceof FormData;
|
||||||
|
|
||||||
// Currently, only two content types are handled here: application/json and multipart/form-data
|
// 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()
|
? "?" + new URLSearchParams(params).toString()
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const response = await fetch(`${BASE_URL}${url}${queryString}`, {
|
const finalUrl = `${BASE_URL}${url}${queryString}`;
|
||||||
...requestOptions,
|
|
||||||
|
console.log("🎯 Final request details:", {
|
||||||
|
finalUrl,
|
||||||
method,
|
method,
|
||||||
headers,
|
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 {
|
console.log("📨 Response received:", {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
data: response_data,
|
statusText: response.statusText,
|
||||||
headers: response.headers,
|
ok: response.ok,
|
||||||
} as T;
|
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 =
|
const BACKEND_BASE_URL =
|
||||||
process.env.NEXT_PUBLIC_AGPT_SERVER_BASE_URL || "http://localhost:8006";
|
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 {
|
function buildBackendUrl(path: string[], queryString: string): string {
|
||||||
const backendPath = path.join("/");
|
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(
|
async function handleJsonRequest(
|
||||||
@@ -17,21 +26,37 @@ async function handleJsonRequest(
|
|||||||
method: string,
|
method: string,
|
||||||
backendUrl: string,
|
backendUrl: string,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
console.log("📝 Handling JSON request:", { method, backendUrl });
|
||||||
const payload = await req.json();
|
const payload = await req.json();
|
||||||
return await makeAuthenticatedRequest(
|
console.log("📄 Request payload:", payload);
|
||||||
|
|
||||||
|
const result = await makeAuthenticatedRequest(
|
||||||
method,
|
method,
|
||||||
backendUrl,
|
backendUrl,
|
||||||
payload,
|
payload,
|
||||||
"application/json",
|
"application/json",
|
||||||
);
|
);
|
||||||
|
console.log("✅ JSON request completed successfully");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFormDataRequest(
|
async function handleFormDataRequest(
|
||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
backendUrl: string,
|
backendUrl: string,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
console.log("📁 Handling FormData request:", { backendUrl });
|
||||||
const formData = await req.formData();
|
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(
|
async function handleUrlEncodedRequest(
|
||||||
@@ -39,22 +64,31 @@ async function handleUrlEncodedRequest(
|
|||||||
method: string,
|
method: string,
|
||||||
backendUrl: string,
|
backendUrl: string,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
console.log("🔤 Handling URL encoded request:", { method, backendUrl });
|
||||||
const textPayload = await req.text();
|
const textPayload = await req.text();
|
||||||
const params = new URLSearchParams(textPayload);
|
const params = new URLSearchParams(textPayload);
|
||||||
const payload = Object.fromEntries(params.entries());
|
const payload = Object.fromEntries(params.entries());
|
||||||
return await makeAuthenticatedRequest(
|
console.log("📄 URL encoded payload:", payload);
|
||||||
|
|
||||||
|
const result = await makeAuthenticatedRequest(
|
||||||
method,
|
method,
|
||||||
backendUrl,
|
backendUrl,
|
||||||
payload,
|
payload,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
);
|
);
|
||||||
|
console.log("✅ URL encoded request completed successfully");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleRequestWithoutBody(
|
async function handleRequestWithoutBody(
|
||||||
method: string,
|
method: string,
|
||||||
backendUrl: string,
|
backendUrl: string,
|
||||||
): Promise<any> {
|
): 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(
|
function createUnsupportedContentTypeResponse(
|
||||||
@@ -91,7 +125,17 @@ function createResponse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createErrorResponse(error: unknown): NextResponse {
|
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 =
|
const detail =
|
||||||
error instanceof Error ? error.message : "An unknown error occurred";
|
error instanceof Error ? error.message : "An unknown error occurred";
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -110,14 +154,32 @@ async function handler(
|
|||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
{ params }: { params: Promise<{ path: string[] }> },
|
{ params }: { params: Promise<{ path: string[] }> },
|
||||||
) {
|
) {
|
||||||
|
console.log("🚀 === PROXY REQUEST START ===");
|
||||||
|
|
||||||
const { path } = await params;
|
const { path } = await params;
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
const queryString = url.search;
|
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 backendUrl = buildBackendUrl(path, queryString);
|
||||||
|
|
||||||
const method = req.method;
|
const method = req.method;
|
||||||
const contentType = req.headers.get("Content-Type");
|
const contentType = req.headers.get("Content-Type");
|
||||||
|
|
||||||
|
console.log("🎯 Processing request:", {
|
||||||
|
method,
|
||||||
|
contentType,
|
||||||
|
backendUrl,
|
||||||
|
});
|
||||||
|
|
||||||
let responseBody: any;
|
let responseBody: any;
|
||||||
const responseStatus: number = 200;
|
const responseStatus: number = 200;
|
||||||
const responseHeaders: Record<string, string> = {
|
const responseHeaders: Record<string, string> = {
|
||||||
@@ -126,20 +188,37 @@ async function handler(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (method === "GET" || method === "DELETE") {
|
if (method === "GET" || method === "DELETE") {
|
||||||
|
console.log("🔄 Routing to handleRequestWithoutBody");
|
||||||
responseBody = await handleRequestWithoutBody(method, backendUrl);
|
responseBody = await handleRequestWithoutBody(method, backendUrl);
|
||||||
} else if (contentType?.includes("application/json")) {
|
} else if (contentType?.includes("application/json")) {
|
||||||
|
console.log("🔄 Routing to handleJsonRequest");
|
||||||
responseBody = await handleJsonRequest(req, method, backendUrl);
|
responseBody = await handleJsonRequest(req, method, backendUrl);
|
||||||
} else if (contentType?.includes("multipart/form-data")) {
|
} else if (contentType?.includes("multipart/form-data")) {
|
||||||
|
console.log("🔄 Routing to handleFormDataRequest");
|
||||||
responseBody = await handleFormDataRequest(req, backendUrl);
|
responseBody = await handleFormDataRequest(req, backendUrl);
|
||||||
responseHeaders["Content-Type"] = "text/plain";
|
responseHeaders["Content-Type"] = "text/plain";
|
||||||
} else if (contentType?.includes("application/x-www-form-urlencoded")) {
|
} else if (contentType?.includes("application/x-www-form-urlencoded")) {
|
||||||
|
console.log("🔄 Routing to handleUrlEncodedRequest");
|
||||||
responseBody = await handleUrlEncodedRequest(req, method, backendUrl);
|
responseBody = await handleUrlEncodedRequest(req, method, backendUrl);
|
||||||
} else {
|
} else {
|
||||||
|
console.log("❌ Unsupported content type:", contentType);
|
||||||
return createUnsupportedContentTypeResponse(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);
|
return createResponse(responseBody, responseStatus, responseHeaders);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log("💥 === PROXY REQUEST FAILED ===");
|
||||||
return createErrorResponse(error);
|
return createErrorResponse(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,40 @@ export function buildRequestUrl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerAuthToken(): Promise<string> {
|
export async function getServerAuthToken(): Promise<string> {
|
||||||
|
console.log("🔐 Getting server auth token...");
|
||||||
|
|
||||||
const supabase = await getServerSupabase();
|
const supabase = await getServerSupabase();
|
||||||
|
|
||||||
if (!supabase) {
|
if (!supabase) {
|
||||||
|
console.error("❌ Supabase client not available");
|
||||||
throw new Error("Supabase client not available");
|
throw new Error("Supabase client not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("✅ Supabase client obtained");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { session },
|
data: { session },
|
||||||
error,
|
error,
|
||||||
} = await supabase.auth.getSession();
|
} = 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) {
|
if (error || !session?.access_token) {
|
||||||
|
console.warn("⚠️ No valid session or access token found");
|
||||||
return "no-token-found";
|
return "no-token-found";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("✅ Valid access token obtained");
|
||||||
return session.access_token;
|
return session.access_token;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to get auth token:", error);
|
console.error("❌ Failed to get auth token:", error);
|
||||||
return "no-token-found";
|
return "no-token-found";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +61,16 @@ export function createRequestHeaders(
|
|||||||
hasRequestBody: boolean,
|
hasRequestBody: boolean,
|
||||||
contentType: string = "application/json",
|
contentType: string = "application/json",
|
||||||
): Record<string, string> {
|
): 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> = {};
|
const headers: Record<string, string> = {};
|
||||||
|
|
||||||
if (hasRequestBody) {
|
if (hasRequestBody) {
|
||||||
@@ -56,6 +81,12 @@ export function createRequestHeaders(
|
|||||||
headers["Authorization"] = `Bearer ${token}`;
|
headers["Authorization"] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("🏷️ Headers created:", {
|
||||||
|
headerKeys: Object.keys(headers),
|
||||||
|
hasAuth: !!headers["Authorization"],
|
||||||
|
hasContentType: !!headers["Content-Type"],
|
||||||
|
});
|
||||||
|
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,49 +188,121 @@ export async function makeAuthenticatedRequest(
|
|||||||
payload?: Record<string, any>,
|
payload?: Record<string, any>,
|
||||||
contentType: string = "application/json",
|
contentType: string = "application/json",
|
||||||
): Promise<any> {
|
): 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 token = await getServerAuthToken();
|
||||||
const payloadAsQuery = ["GET", "DELETE"].includes(method);
|
const payloadAsQuery = ["GET", "DELETE"].includes(method);
|
||||||
const hasRequestBody = !payloadAsQuery && payload !== undefined;
|
const hasRequestBody = !payloadAsQuery && payload !== undefined;
|
||||||
|
|
||||||
const response = await fetch(url, {
|
console.log("🎯 Request configuration:", {
|
||||||
method,
|
payloadAsQuery,
|
||||||
headers: createRequestHeaders(token, hasRequestBody, contentType),
|
hasRequestBody,
|
||||||
body: hasRequestBody
|
tokenAvailable: token !== "no-token-found",
|
||||||
? serializeRequestBody(payload, contentType)
|
|
||||||
: undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
const headers = createRequestHeaders(token, hasRequestBody, contentType);
|
||||||
const errorDetail = await parseApiError(response);
|
const body = hasRequestBody
|
||||||
|
? serializeRequestBody(payload, contentType)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
// Handle authentication errors gracefully during logout
|
console.log("📡 Making fetch request to:", url);
|
||||||
if (isAuthenticationError(response, errorDetail)) {
|
console.log(
|
||||||
if (isLogoutInProgress()) {
|
"📤 Request body preview:",
|
||||||
// Silently return null during logout to prevent error noise
|
body ? String(body).substring(0, 200) + "..." : "No body",
|
||||||
console.debug(
|
);
|
||||||
"Authentication request failed during logout, ignoring:",
|
|
||||||
errorDetail,
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For authentication errors outside logout, log but don't throw
|
// For other errors, throw as normal
|
||||||
// This prevents crashes when session expires naturally
|
throw new Error(errorDetail);
|
||||||
console.warn("Authentication failed:", errorDetail);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For other errors, throw as normal
|
const responseData = await parseApiResponse(response);
|
||||||
throw new Error(errorDetail);
|
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(
|
export async function makeAuthenticatedFileUpload(
|
||||||
url: string,
|
url: string,
|
||||||
formData: FormData,
|
formData: FormData,
|
||||||
): Promise<string> {
|
): 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 token = await getServerAuthToken();
|
||||||
|
|
||||||
const headers: Record<string, string> = {};
|
const headers: Record<string, string> = {};
|
||||||
@@ -207,30 +310,68 @@ export async function makeAuthenticatedFileUpload(
|
|||||||
headers["Authorization"] = `Bearer ${token}`;
|
headers["Authorization"] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't set Content-Type for FormData - let the browser set it with boundary
|
console.log("🏷️ Upload headers:", {
|
||||||
const response = await fetch(url, {
|
hasAuth: !!headers["Authorization"],
|
||||||
method: "POST",
|
headerKeys: Object.keys(headers),
|
||||||
headers,
|
|
||||||
body: formData,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
console.log("📡 Making file upload request to:", url);
|
||||||
// Handle authentication errors gracefully for file uploads too
|
|
||||||
const errorMessage = `Error uploading file: ${response.statusText}`;
|
|
||||||
|
|
||||||
if (response.status === 401 || response.status === 403) {
|
try {
|
||||||
if (isLogoutInProgress()) {
|
// Don't set Content-Type for FormData - let the browser set it with boundary
|
||||||
console.debug(
|
const response = await fetch(url, {
|
||||||
"File upload authentication failed during logout, ignoring",
|
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 "";
|
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