Public Access
1
0

chore: reorganize frontend into app and admin roots

This commit is contained in:
pguerrerox
2026-05-30 00:45:06 +00:00
parent d71f2f1f8a
commit a926d06b54
39 changed files with 76 additions and 49 deletions
+72
View File
@@ -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;
}