Ryanba 5a8481416f
fix(frontend): surface upload API error details (#1113)
Preserve backend upload/list/delete error details in the frontend API layer so users see the actual server failure instead of a generic message.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-03-13 21:55:33 +08:00

109 lines
2.1 KiB
TypeScript

/**
* API functions for file uploads
*/
import { getBackendBaseURL } from "../config";
export interface UploadedFileInfo {
filename: string;
size: number;
path: string;
virtual_path: string;
artifact_url: string;
extension?: string;
modified?: number;
markdown_file?: string;
markdown_path?: string;
markdown_virtual_path?: string;
markdown_artifact_url?: string;
}
export interface UploadResponse {
success: boolean;
files: UploadedFileInfo[];
message: string;
}
export interface ListFilesResponse {
files: UploadedFileInfo[];
count: number;
}
async function readErrorDetail(
response: Response,
fallback: string,
): Promise<string> {
const error = await response
.json()
.catch(() => ({ detail: fallback }));
return error.detail ?? fallback;
}
/**
* Upload files to a thread
*/
export async function uploadFiles(
threadId: string,
files: File[],
): Promise<UploadResponse> {
const formData = new FormData();
files.forEach((file) => {
formData.append("files", file);
});
const response = await fetch(
`${getBackendBaseURL()}/api/threads/${threadId}/uploads`,
{
method: "POST",
body: formData,
},
);
if (!response.ok) {
throw new Error(await readErrorDetail(response, "Upload failed"));
}
return response.json();
}
/**
* List all uploaded files for a thread
*/
export async function listUploadedFiles(
threadId: string,
): Promise<ListFilesResponse> {
const response = await fetch(
`${getBackendBaseURL()}/api/threads/${threadId}/uploads/list`,
);
if (!response.ok) {
throw new Error(
await readErrorDetail(response, "Failed to list uploaded files"),
);
}
return response.json();
}
/**
* Delete an uploaded file
*/
export async function deleteUploadedFile(
threadId: string,
filename: string,
): Promise<{ success: boolean; message: string }> {
const response = await fetch(
`${getBackendBaseURL()}/api/threads/${threadId}/uploads/${filename}`,
{
method: "DELETE",
},
);
if (!response.ok) {
throw new Error(await readErrorDetail(response, "Failed to delete file"));
}
return response.json();
}