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');
}