chore: reorganize frontend into app and admin roots
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
function isLoopbackHostname(hostname: string) {
|
||||
return hostname === 'localhost' || hostname === '127.0.0.1';
|
||||
}
|
||||
|
||||
function normalizeBaseUrl(baseUrl: string) {
|
||||
return baseUrl.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function resolveApiBaseUrl() {
|
||||
const configuredBaseUrl = (import.meta.env.VITE_API_BASE_URL ?? '').trim();
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
return normalizeBaseUrl(configuredBaseUrl);
|
||||
}
|
||||
|
||||
const fallbackBaseUrl = `${window.location.protocol}//${window.location.hostname}:4000/api`;
|
||||
|
||||
if (!configuredBaseUrl) {
|
||||
return fallbackBaseUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
const configuredUrl = new URL(configuredBaseUrl);
|
||||
|
||||
if (isLoopbackHostname(configuredUrl.hostname) && !isLoopbackHostname(window.location.hostname)) {
|
||||
configuredUrl.hostname = window.location.hostname;
|
||||
return normalizeBaseUrl(configuredUrl.toString());
|
||||
}
|
||||
|
||||
return normalizeBaseUrl(configuredUrl.toString());
|
||||
} catch {
|
||||
return normalizeBaseUrl(configuredBaseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
const apiBaseUrl = resolveApiBaseUrl();
|
||||
|
||||
export const hasApiConfig = Boolean(apiBaseUrl);
|
||||
|
||||
export async function apiRequest<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
if (!apiBaseUrl) {
|
||||
throw new Error('VITE_API_BASE_URL is not configured.');
|
||||
}
|
||||
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(`${apiBaseUrl}${path}`, {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(init?.headers ?? {}),
|
||||
},
|
||||
...init,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to reach the local API at ${apiBaseUrl}. Check that the API server is running and that VITE_API_BASE_URL matches the host you opened in the browser.`,
|
||||
{ cause: error },
|
||||
);
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
const payload = contentType.includes('application/json') ? ((await response.json()) as unknown) : null;
|
||||
|
||||
if (!response.ok) {
|
||||
const message = payload && typeof payload === 'object' && 'error' in payload ? String(payload.error) : 'Request failed.';
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return payload as T;
|
||||
}
|
||||
Reference in New Issue
Block a user