all repos — weimar @ a338ad5884f38dd2d5e241df42fd565a97f27f72

Unnamed repository; edit this file 'description' to name the repository.

web/src/lib/api.ts (view raw)

  1const BASE = '/api';
  2
  3export interface User {
  4	id: number;
  5	username: string;
  6	is_admin: boolean;
  7	created_at: string;
  8	updated_at: string;
  9}
 10
 11export interface Image {
 12	id: number;
 13	filename: string;
 14	storage_path: string;
 15	thumbnail_path: string | null;
 16	uploaded_by: number;
 17	file_size: number;
 18	width: number;
 19	height: number;
 20	mime_type: string;
 21	created_at: string;
 22	updated_at: string;
 23	tags: string[];
 24}
 25
 26export interface ImageList {
 27	images: Image[];
 28	total: number;
 29}
 30
 31export interface Tag {
 32	tag: string;
 33	usage_count: number;
 34}
 35
 36export interface ApiError {
 37	error: string;
 38}
 39
 40async function request<T>(path: string, opts: RequestInit = {}): Promise<T> {
 41	const res = await fetch(BASE + path, {
 42		credentials: 'include',
 43		headers: opts.body instanceof FormData ? {} : { 'Content-Type': 'application/json' },
 44		...opts,
 45	});
 46	if (!res.ok) {
 47		const body = await res.json().catch(() => ({ error: res.statusText }));
 48		throw new Error((body as ApiError).error || `HTTP ${res.status}`);
 49	}
 50	return res.json();
 51}
 52
 53export async function login(username: string, password: string): Promise<User> {
 54	return request<User>('/auth/login', {
 55		method: 'POST',
 56		body: JSON.stringify({ username, password }),
 57	});
 58}
 59
 60export async function register(username: string, password: string): Promise<User> {
 61	return request<User>('/auth/register', {
 62		method: 'POST',
 63		body: JSON.stringify({ username, password }),
 64	});
 65}
 66
 67export async function logout(): Promise<void> {
 68	await request('/auth/logout', { method: 'POST' });
 69}
 70
 71export async function listImages(tags: string[] = [], page = 1, perPage = 50): Promise<ImageList> {
 72	const params = new URLSearchParams();
 73	params.set('page', String(page));
 74	params.set('per_page', String(perPage));
 75	for (const t of tags) {
 76		params.append('tags', t);
 77	}
 78	return request<ImageList>(`/images?${params}`);
 79}
 80
 81export async function getImage(id: number): Promise<Image> {
 82	return request<Image>(`/images/${id}`);
 83}
 84
 85export function imageDownloadUrl(id: number): string {
 86	return `${BASE}/images/${id}/download`;
 87}
 88
 89export function thumbnailUrl(id: number): string {
 90	return `${BASE}/images/${id}/thumbnail`;
 91}
 92
 93export async function uploadImage(file: File, tags: string[]): Promise<Image> {
 94	const fd = new FormData();
 95	fd.append('file', file);
 96	for (const t of tags) {
 97		fd.append('tags', t);
 98	}
 99	return request<Image>('/upload', { method: 'POST', body: fd });
100}
101
102export async function suggestTags(query: string): Promise<Tag[]> {
103	return request<Tag[]>(`/tags/suggest?q=${encodeURIComponent(query)}`);
104}