MCPcopy
hub / github.com/dataelement/Clawith / request

Function request

frontend/src/services/api.ts:7–76  ·  view source on GitHub ↗
(url: string, options: RequestInit = {})

Source from the content-addressed store, hash-verified

5const API_BASE = '/api';
6
7async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
8 const token = localStorage.getItem('token');
9 const headers: Record<string, string> = {
10 'Content-Type': 'application/json',
11 ...(token ? { Authorization: `Bearer ${token}` } : {}),
12 };
13
14 const res = await fetch(`${API_BASE}${url}`, { ...options, headers });
15
16 if (!res.ok) {
17 // Auto-logout on expired/invalid token (but not on auth endpoints — let them show errors)
18 const isAuthEndpoint = url.startsWith('/auth/login')
19 || url.startsWith('/auth/register')
20 || url.startsWith('/auth/verify-email')
21 || url.startsWith('/auth/resend-verification')
22 || url.startsWith('/auth/forgot-password')
23 || url.startsWith('/auth/reset-password');
24 if (res.status === 401 && !isAuthEndpoint) {
25 localStorage.removeItem('token');
26 localStorage.removeItem('user');
27 window.location.href = '/login';
28 throw new Error('Session expired');
29 }
30 const bodyText = await res.text();
31 let error: { detail?: unknown };
32 try {
33 error = bodyText ? JSON.parse(bodyText) : {};
34 } catch {
35 const snippet = bodyText.trim().slice(0, 280);
36 error = {
37 detail: snippet || `HTTP ${res.status} ${res.statusText || ''}`.trim(),
38 };
39 }
40 // Pydantic validation errors return detail as an array of objects
41 const fieldLabels: Record<string, string> = {
42 name: '名称',
43 role_description: '角色描述',
44 agent_type: '智能体类型',
45 primary_model_id: '主模型',
46 max_tokens_per_day: '每日 Token 上限',
47 max_tokens_per_month: '每月 Token 上限',
48 };
49 let message = '';
50 if (Array.isArray(error.detail)) {
51 message = error.detail
52 .map((e: any) => {
53 const field = e.loc?.slice(-1)[0] || '';
54 const label = fieldLabels[field] || field;
55 return label ? `${label}: ${e.msg}` : e.msg;
56 })
57 .join('; ');
58 } else if (typeof error.detail === 'object' && error.detail !== null) {
59 // Structured error detail (e.g., NeedsVerificationResponse)
60 message = (error.detail as Record<string, any>).message || `HTTP ${res.status}`;
61 } else {
62 const d = error.detail;
63 if (typeof d === 'string') message = d;
64 else if (d != null && typeof d === 'object') message = JSON.stringify(d);

Callers 1

api.tsFile · 0.85

Calls 1

jsonMethod · 0.45

Tested by

no test coverage detected