This commit is contained in:
2026-06-17 00:21:00 +02:00
commit 408e48c568
41 changed files with 6617 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
import { env } from '$env/dynamic/public';
const BASE = env.PUBLIC_API_BASE || 'http://localhost:8080';
export class ApiError extends Error {
status: number;
constructor(status: number, message: string) {
super(message);
this.status = status;
}
}
async function request<T>(path: string, opts: RequestInit = {}): Promise<T> {
const res = await fetch(`${BASE}/api${path}`, {
credentials: 'include',
headers: { 'Content-Type': 'application/json', ...(opts.headers ?? {}) },
...opts
});
if (res.status === 204) return undefined as T;
const text = await res.text();
const data = text ? JSON.parse(text) : null;
if (!res.ok) {
throw new ApiError(res.status, data?.error ?? res.statusText);
}
return data as T;
}
export const api = {
get: <T>(p: string) => request<T>(p),
post: <T>(p: string, body?: unknown) =>
request<T>(p, { method: 'POST', body: body ? JSON.stringify(body) : undefined }),
patch: <T>(p: string, body?: unknown) =>
request<T>(p, { method: 'PATCH', body: body ? JSON.stringify(body) : undefined })
};
+53
View File
@@ -0,0 +1,53 @@
import { api } from './api';
export type User = {
id: string;
email: string;
display_name: string | null;
email_verified: boolean;
};
export type Settings = {
locale: string;
currency: string;
theme: string;
notify_email: boolean;
};
type Me = { user: User; settings: Settings };
class AuthStore {
user = $state<User | null>(null);
settings = $state<Settings | null>(null);
loaded = $state(false);
async refresh() {
try {
const me = await api.get<Me>('/auth/me');
this.user = me.user;
this.settings = me.settings;
} catch {
this.user = null;
this.settings = null;
} finally {
this.loaded = true;
}
}
set(me: Me) {
this.user = me.user;
this.settings = me.settings;
this.loaded = true;
}
async logout() {
try {
await api.post('/auth/logout');
} finally {
this.user = null;
this.settings = null;
}
}
}
export const auth = new AuthStore();