45 lines
1.0 KiB
TypeScript
45 lines
1.0 KiB
TypeScript
import type {
|
||
Connection,
|
||
Pipeline,
|
||
Run,
|
||
RunWithPipeline,
|
||
StreamConfig,
|
||
} from "@/lib/db";
|
||
|
||
export type { Connection, Pipeline, Run, RunWithPipeline, StreamConfig };
|
||
|
||
export interface StreamInfo {
|
||
name: string;
|
||
columns?: string[];
|
||
}
|
||
|
||
export interface HealthResult {
|
||
sling: { path: string; version: string } | null;
|
||
atlas: { path: string; version: string } | null;
|
||
}
|
||
|
||
export interface RunDetail extends Run {
|
||
log?: string;
|
||
}
|
||
|
||
export class ApiError extends Error {
|
||
status: number;
|
||
constructor(message: string, status: number) {
|
||
super(message);
|
||
this.status = status;
|
||
}
|
||
}
|
||
|
||
export async function api<T>(url: string, init?: RequestInit): Promise<T> {
|
||
const res = await fetch(url, { cache: "no-store", ...init });
|
||
const data = (await res.json().catch(() => ({}))) as Record<string, unknown>;
|
||
if (!res.ok) {
|
||
const msg =
|
||
typeof data?.error === "string"
|
||
? data.error
|
||
: `请求失败(HTTP ${res.status})`;
|
||
throw new ApiError(msg, res.status);
|
||
}
|
||
return data as T;
|
||
}
|