sync: phase 1 backend + frontend from server

This commit is contained in:
2026-06-30 09:26:03 -04:00
parent d4cdd89544
commit 30e159cbdb
31 changed files with 4758 additions and 114 deletions
+18 -3
View File
@@ -1,12 +1,17 @@
const API_BASE = '/api/v1';
export interface ApiError extends Error {
status?: number;
retryAfter?: number;
}
async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
const headers: Record<string, string> = {};
if (body !== undefined) {
headers['Content-Type'] = 'application/json';
}
const response = await fetch(`${API_BASE}${path}`, {
const response = await fetch(API_BASE + path, {
method,
headers,
credentials: 'include',
@@ -14,7 +19,8 @@ async function request<T>(method: string, path: string, body?: unknown): Promise
});
if (!response.ok) {
let errorMessage = `Request failed: ${response.status}`;
let errorMessage = 'Request failed: ' + response.status;
let retryAfter: number | undefined;
try {
const errorData = await response.json();
if (typeof errorData?.message === 'string') {
@@ -22,10 +28,19 @@ async function request<T>(method: string, path: string, body?: unknown): Promise
} else if (typeof errorData?.error === 'string') {
errorMessage = errorData.error;
}
if (response.status === 429 && typeof errorData?.retry_after === 'number') {
retryAfter = errorData.retry_after;
}
} catch {
// ignore parse error
}
throw new Error(errorMessage);
const err = new Error(errorMessage) as ApiError;
err.status = response.status;
if (response.status === 429) {
const ra = response.headers.get('Retry-After');
err.retryAfter = retryAfter ?? (ra ? parseInt(ra, 10) : undefined);
}
throw err;
}
if (response.status === 204) {