other
This commit is contained in:
BIN
lib/.server-service.ts.swp
Normal file
BIN
lib/.server-service.ts.swp
Normal file
Binary file not shown.
33
lib/auth-helpers.ts
Normal file
33
lib/auth-helpers.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
'use client';
|
||||
|
||||
// Helper function to verify authentication with the local API
|
||||
export async function verifyAuth(token: string) {
|
||||
try {
|
||||
// Use a properly formed URL with origin
|
||||
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
||||
const authEndpoint = new URL('/api/auth/me', origin).toString();
|
||||
|
||||
console.log(`Verifying auth with ${authEndpoint} using token: ${token.substring(0, 10)}...`);
|
||||
|
||||
const response = await fetch(authEndpoint, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
// Prevent caching of auth requests
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Auth verification failed: ${response.status}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Authentication verification failed:", error);
|
||||
console.error("Error details:", error instanceof Error ? error.message : 'Unknown error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -21,65 +21,77 @@ function getAuthToken(): string | null {
|
||||
?.split('=')[1] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API base URL for client-side fetch calls
|
||||
*/
|
||||
function getClientApiBaseUrl(): string {
|
||||
// For client-side, we can access window.location if in browser
|
||||
if (typeof window !== 'undefined') {
|
||||
// Use the same origin (which includes the correct port)
|
||||
return `${window.location.origin}/api`;
|
||||
}
|
||||
|
||||
// Fallback when window is not available
|
||||
// For development mode, use port 3001 to match our server
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return 'http://localhost:3001/api';
|
||||
}
|
||||
|
||||
// Default fallback - relative URL
|
||||
return '/api';
|
||||
}
|
||||
|
||||
export async function fetchClient<T>(
|
||||
endpoint: string,
|
||||
options: FetchOptions = {}
|
||||
): Promise<T> {
|
||||
const { method = 'GET', body, headers = {}, ...rest } = options;
|
||||
|
||||
// Get the base API URL from environment or fallback
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// Ensure the endpoint starts with a slash
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
||||
|
||||
// For the specific case of internal-api.inboxi.ng - remove duplicate /api
|
||||
let url;
|
||||
if (apiUrl.includes('internal-api.inboxi.ng')) {
|
||||
// Special case for internal-api.inboxi.ng
|
||||
if (normalizedEndpoint.startsWith('/api/')) {
|
||||
url = `${apiUrl}${normalizedEndpoint.substring(4)}`; // Remove the /api part
|
||||
} else {
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
} else {
|
||||
// Normal case for other environments
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
|
||||
// Get auth token from cookies
|
||||
const authToken = getAuthToken();
|
||||
|
||||
// Prepare headers with authentication if token exists
|
||||
const requestHeaders: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...(headers as Record<string, string>),
|
||||
};
|
||||
|
||||
if (authToken) {
|
||||
// Backend expects "Bearer TOKEN" format
|
||||
requestHeaders['Authorization'] = `Bearer ${authToken}`;
|
||||
console.log('Authorization header set to:', `Bearer ${authToken.substring(0, 10)}...`);
|
||||
}
|
||||
|
||||
console.log('API Request:', {
|
||||
url,
|
||||
method,
|
||||
hasAuthToken: !!authToken
|
||||
});
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method,
|
||||
credentials: 'include',
|
||||
headers: requestHeaders,
|
||||
...rest,
|
||||
};
|
||||
|
||||
if (body && method !== 'GET') {
|
||||
fetchOptions.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the base API URL
|
||||
const baseUrl = getClientApiBaseUrl();
|
||||
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// Ensure baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them for the final URL
|
||||
const url = `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
|
||||
// Get auth token from cookies
|
||||
const authToken = getAuthToken();
|
||||
|
||||
// Prepare headers with authentication if token exists
|
||||
const requestHeaders: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...(headers as Record<string, string>),
|
||||
};
|
||||
|
||||
if (authToken) {
|
||||
// Backend expects "Bearer TOKEN" format
|
||||
requestHeaders['Authorization'] = `Bearer ${authToken}`;
|
||||
console.log('Authorization header set to:', `Bearer ${authToken.substring(0, 10)}...`);
|
||||
}
|
||||
|
||||
console.log('API Request:', {
|
||||
url,
|
||||
method,
|
||||
hasAuthToken: !!authToken
|
||||
});
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method,
|
||||
credentials: 'include',
|
||||
headers: requestHeaders,
|
||||
...rest,
|
||||
};
|
||||
|
||||
if (body && method !== 'GET') {
|
||||
fetchOptions.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(url, fetchOptions);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -97,6 +109,7 @@ export async function fetchClient<T>(
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API request failed:', error);
|
||||
console.error('Error details:', error instanceof Error ? error.message : 'Unknown error');
|
||||
|
||||
// Only show toast if this is a client-side error (not during SSR)
|
||||
if (typeof window !== 'undefined') {
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
import { cookies } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
/**
|
||||
* Gets the base URL for server API requests with proper fallbacks
|
||||
*/
|
||||
function getBaseUrl() {
|
||||
// For server components, we normally would use environment variables
|
||||
// But we need to be careful with how they're accessed
|
||||
|
||||
// Try to get the API URL from environment variables
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
// We need to get the host from somewhere to construct the URL
|
||||
// In production, we can rely on the VERCEL_URL or similar
|
||||
if (process.env.VERCEL_URL) {
|
||||
return `https://${process.env.VERCEL_URL}/api`;
|
||||
}
|
||||
|
||||
// If we have a configured API URL, use that
|
||||
if (apiUrl) {
|
||||
// If it's already an absolute URL, use it
|
||||
if (apiUrl.startsWith('http')) {
|
||||
return apiUrl;
|
||||
}
|
||||
// Otherwise, it's likely a relative path like /api
|
||||
return `http://localhost:3000${apiUrl.startsWith('/') ? apiUrl : `/${apiUrl}`}`;
|
||||
}
|
||||
|
||||
// Last resort fallback for development
|
||||
return 'http://localhost:3000/api';
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side fetch wrapper with authentication.
|
||||
*/
|
||||
@@ -14,8 +44,20 @@ export async function fetchServer<T = unknown>(
|
||||
if (!authToken) redirect('/login');
|
||||
|
||||
try {
|
||||
console.log(`${endpoint}`)
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${endpoint}`, {
|
||||
const baseUrl = getBaseUrl();
|
||||
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// Ensure baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them to get a complete URL
|
||||
const url = `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
|
||||
console.log(`Server fetch to: ${url}`);
|
||||
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
32
lib/server-utils.ts
Normal file
32
lib/server-utils.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Helper function to construct proper URLs for server components.
|
||||
* In Next.js server components, relative URLs don't work in fetch() calls.
|
||||
*/
|
||||
export function getServerApiUrl(endpoint: string): string {
|
||||
// Base API URL - use a hardcoded value for server components
|
||||
// This must be an absolute URL with protocol and domain
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api';
|
||||
|
||||
// Ensure endpoint doesn't start with a slash if baseUrl ends with one
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
// Ensure the baseUrl ends with a slash if it doesn't already
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
|
||||
// Combine them to get a complete URL
|
||||
return `${normalizedBaseUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to detect if code is running on server or client
|
||||
*/
|
||||
export function isServer(): boolean {
|
||||
return typeof window === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to detect if code is running in development mode
|
||||
*/
|
||||
export function isDevelopment(): boolean {
|
||||
return process.env.NODE_ENV === 'development';
|
||||
}
|
||||
Reference in New Issue
Block a user