File size: 4,345 Bytes
d4f8959 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | import type {
UploadResponse,
Report,
RedFlagsResponse,
RecommendationResponse,
QueryRequest,
QueryResponse,
CompareRequest,
CompareResponse,
CompaniesResponse,
} from '../types/api';
// Dev: '/api' is proxied to the backend by Vite (vite.config.ts).
// Production (single-container deploy): built with VITE_API_BASE='' so
// requests hit the same origin that serves the static bundle.
const BASE_URL =
(import.meta as ImportMeta & { env?: Record<string, string | undefined> })
.env?.VITE_API_BASE ?? '/api';
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${BASE_URL}${path}`, {
headers: { 'Content-Type': 'application/json', ...options?.headers },
...options,
});
if (!res.ok) {
if (res.status === 404) {
throw new NotFoundError('No filing found. Upload a filing first.');
}
const text = await res.text();
throw new Error(`API error ${res.status}: ${text}`);
}
return res.json() as Promise<T>;
}
export class NotFoundError extends Error {
constructor(message: string) {
super(message);
this.name = 'NotFoundError';
}
}
// βββ Upload βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function uploadFiling(
file: File,
company: string,
year: string
): Promise<UploadResponse> {
const form = new FormData();
form.append('file', file);
form.append('company', company);
form.append('year', year);
const res = await fetch(`${BASE_URL}/upload`, {
method: 'POST',
body: form,
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Upload failed (${res.status}): ${text}`);
}
return res.json() as Promise<UploadResponse>;
}
// βββ Report βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function getReport(company: string, year: string): Promise<Report> {
return request<Report>(`/report/${encodeURIComponent(company)}/${encodeURIComponent(year)}`);
}
// βββ Red Flags ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function getRedFlags(
company: string,
year: string
): Promise<RedFlagsResponse> {
return request<RedFlagsResponse>(
`/red_flags/${encodeURIComponent(company)}/${encodeURIComponent(year)}`
);
}
// βββ Recommendation βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function getRecommendation(
company: string,
year: string
): Promise<RecommendationResponse> {
return request<RecommendationResponse>(
`/recommendation/${encodeURIComponent(company)}/${encodeURIComponent(year)}`
);
}
// βββ Query ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function queryFiling(payload: QueryRequest): Promise<QueryResponse> {
return request<QueryResponse>('/query', {
method: 'POST',
body: JSON.stringify(payload),
});
}
// βββ Compare βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function compareFilers(payload: CompareRequest): Promise<CompareResponse> {
return request<CompareResponse>('/compare', {
method: 'POST',
body: JSON.stringify(payload),
});
}
// βββ Companies ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function getCompanies(): Promise<CompaniesResponse> {
return request<CompaniesResponse>('/companies');
}
|