147 lines
4.4 KiB
TypeScript
147 lines
4.4 KiB
TypeScript
import { auth } from '$lib/stores/auth';
|
|
import { get } from 'svelte/store';
|
|
|
|
const API_BASE = '/api/v1';
|
|
|
|
interface RequestOptions extends RequestInit {
|
|
params?: Record<string, string>;
|
|
}
|
|
|
|
async function request<T>(endpoint: string, options: RequestOptions = {}): Promise<T> {
|
|
const { params, ...init } = options;
|
|
|
|
let url = `${API_BASE}${endpoint}`;
|
|
if (params) {
|
|
// Filtrar parámetros undefined y null
|
|
const filteredParams = Object.entries(params)
|
|
.filter(([key, value]) => value !== undefined && value !== null && value !== '')
|
|
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
|
|
|
|
if (Object.keys(filteredParams).length > 0) {
|
|
const searchParams = new URLSearchParams(filteredParams);
|
|
url += `?${searchParams.toString()}`;
|
|
}
|
|
}
|
|
|
|
const authState = get(auth);
|
|
const token = authState.token || (typeof window !== 'undefined' ? localStorage.getItem('internal_auth_token') : null);
|
|
|
|
// Resolve tenant_id from store or from the persisted user object in localStorage
|
|
let tenantId = authState.user?.tenant_id ?? null;
|
|
if (!tenantId && typeof window !== 'undefined') {
|
|
try {
|
|
const stored = localStorage.getItem('internal_auth_user');
|
|
if (stored) tenantId = JSON.parse(stored)?.tenant_id ?? null;
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
const headers = new Headers(init.headers);
|
|
if (token) {
|
|
headers.set('Authorization', `Bearer ${token}`);
|
|
}
|
|
if (tenantId && !headers.has('X-Tenant-ID')) {
|
|
headers.set('X-Tenant-ID', tenantId);
|
|
}
|
|
if (!headers.has('Content-Type')) {
|
|
headers.set('Content-Type', 'application/json');
|
|
}
|
|
|
|
const response = await fetch(url, {
|
|
...init,
|
|
headers
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
// Token expired or invalid
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.removeItem('internal_auth_token');
|
|
localStorage.removeItem('internal_auth_user');
|
|
window.location.href = '/login';
|
|
}
|
|
throw new Error('Unauthorized');
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(errorData.detail || `API error: ${response.statusText}`);
|
|
}
|
|
|
|
// Handle empty responses (like 204 No Content)
|
|
if (response.status === 204) {
|
|
return {} as T;
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async function downloadFile(endpoint: string, filename: string): Promise<void> {
|
|
const authState = get(auth);
|
|
const token = authState.token || (typeof window !== 'undefined' ? localStorage.getItem('internal_auth_token') : null);
|
|
|
|
let tenantId = authState.user?.tenant_id ?? null;
|
|
if (!tenantId && typeof window !== 'undefined') {
|
|
try {
|
|
const stored = localStorage.getItem('internal_auth_user');
|
|
if (stored) tenantId = JSON.parse(stored)?.tenant_id ?? null;
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
const headers = new Headers();
|
|
if (token) {
|
|
headers.set('Authorization', `Bearer ${token}`);
|
|
}
|
|
if (tenantId) {
|
|
headers.set('X-Tenant-ID', tenantId);
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE}${endpoint}`, {
|
|
method: 'GET',
|
|
headers
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.removeItem('internal_auth_token');
|
|
localStorage.removeItem('internal_auth_user');
|
|
window.location.href = '/login';
|
|
}
|
|
throw new Error('Unauthorized');
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(errorData.detail || `Download error: ${response.statusText}`);
|
|
}
|
|
|
|
// Crear blob y descargar
|
|
const blob = await response.blob();
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
window.URL.revokeObjectURL(url);
|
|
}
|
|
|
|
export const api = {
|
|
get: <T>(endpoint: string, params?: Record<string, string>) =>
|
|
request<T>(endpoint, { method: 'GET', params }),
|
|
|
|
post: <T>(endpoint: string, body: any) =>
|
|
request<T>(endpoint, { method: 'POST', body: JSON.stringify(body) }),
|
|
|
|
put: <T>(endpoint: string, body: any) =>
|
|
request<T>(endpoint, { method: 'PUT', body: JSON.stringify(body) }),
|
|
|
|
patch: <T>(endpoint: string, body: any) =>
|
|
request<T>(endpoint, { method: 'PATCH', body: JSON.stringify(body) }),
|
|
|
|
delete: <T>(endpoint: string) =>
|
|
request<T>(endpoint, { method: 'DELETE' }),
|
|
|
|
downloadFile: (endpoint: string, filename: string) =>
|
|
downloadFile(endpoint, filename)
|
|
};
|