lilith-platform.live/codebase/@packages/@lilith/provider-api-client/src/client.ts
2026-04-18 19:25:56 -07:00

75 lines
1.9 KiB
TypeScript

export class ApiError extends Error {
constructor(
message: string,
public readonly status: number,
public readonly code?: string,
) {
super(message);
this.name = 'ApiError';
}
}
export class NotFoundError extends ApiError {
constructor(message = 'Not found') {
super(message, 404, 'not_found');
this.name = 'NotFoundError';
}
}
export class RateLimitError extends ApiError {
constructor(message = 'Too many requests. Please wait a moment before trying again.') {
super(message, 429, 'rate_limited');
this.name = 'RateLimitError';
}
}
export class ValidationError extends ApiError {
constructor(message: string) {
super(message, 422, 'validation_error');
this.name = 'ValidationError';
}
}
export class NetworkError extends Error {
constructor(message: string, public readonly cause?: unknown) {
super(message);
this.name = 'NetworkError';
}
}
export async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
let res: Response;
try {
res = await fetch(url, init);
} catch (err) {
throw new NetworkError(
`Network error: ${err instanceof Error ? err.message : String(err)}`,
err,
);
}
if (res.status === 404) throw new NotFoundError();
if (res.status === 429) throw new RateLimitError();
if (res.status === 422) {
let body: { error?: string; message?: string } = {};
try {
body = (await res.json()) as { error?: string; message?: string };
} catch {
// ignore
}
throw new ValidationError(body.error ?? body.message ?? 'Validation failed');
}
if (!res.ok) {
let body: { error?: string; message?: string } = {};
try {
body = (await res.json()) as { error?: string; message?: string };
} catch {
// ignore
}
throw new ApiError(body.error ?? body.message ?? `Request failed: ${res.status}`, res.status);
}
return res.json() as Promise<T>;
}