import type { Repository, ChangeMeta, ChangeDetail, TreeEntry } from "@pijulab/shared";
const base = "/api";
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${base}${path}`, {
credentials: "include",
headers: { "Content-Type": "application/json", ...options?.headers },
...options,
});
if (!res.ok) {
const err = await res.json().catch(() => ({ message: res.statusText }));
throw new Error((err as { message?: string }).message ?? "Request failed");
}
return res.json() as Promise<T>;
}
export interface AuthUser {
id: number;
username: string;
email: string;
displayName: string | null;
}
export const api = {
auth: {
signup: (body: { username: string; email: string; password: string }) =>
request<AuthUser>("/auth/signup", { method: "POST", body: JSON.stringify(body) }),
login: (body: { email: string; password: string }) =>
request<AuthUser>("/auth/login", { method: "POST", body: JSON.stringify(body) }),
logout: () => request<{ ok: boolean }>("/auth/logout", { method: "POST" }),
},
me: {
get: () => request<AuthUser>("/me"),
repos: () => request<Repository[]>("/me/repos"),
},
repos: {
create: (body: { name: string; description?: string; visibility: "public" | "private" }) =>
request<{ id: number; name: string }>("/repos", {
method: "POST",
body: JSON.stringify(body),
}),
get: (owner: string, name: string) => request<Repository>(`/repos/${owner}/${name}`),
channels: (owner: string, name: string) =>
request<string[]>(`/repos/${owner}/${name}/channels`),
tree: (owner: string, name: string, channel: string, subpath = "") =>
request<TreeEntry[]>(
`/repos/${owner}/${name}/tree?channel=${channel}&path=${encodeURIComponent(subpath)}`,
),
log: (owner: string, name: string, channel: string) =>
request<ChangeMeta[]>(`/repos/${owner}/${name}/log?channel=${channel}`),
change: (owner: string, name: string, hash: string) =>
request<ChangeDetail>(`/repos/${owner}/${name}/change/${hash}`),
},
};