first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:14:08 +03:00
commit b2825e1698
41 changed files with 14258 additions and 0 deletions

176
lib/auth-api.ts Normal file
View File

@@ -0,0 +1,176 @@
/**
* Auth API client for login, register, me, refresh.
* Uses NEXT_PUBLIC_BASE_API_URL on client (defaults to same as BASE_API_URL for server).
*/
const getBaseUrl = () =>
typeof window !== "undefined"
? process.env.NEXT_PUBLIC_BASE_API_URL ?? "http://127.0.0.1:8080"
: process.env.BASE_API_URL ?? process.env.NEXT_PUBLIC_BASE_API_URL ?? "http://127.0.0.1:8080";
const API_PREFIX = "/api/v1/auth";
export interface AuthUser {
id: number;
email: string;
first_name: string;
last_name: string;
username?: string;
is_admin: boolean;
email_verified?: boolean;
}
export interface LoginResponse {
access_token: string;
refresh_token: string;
user: AuthUser;
}
export interface RegisterResponse {
message: string;
user: AuthUser;
}
export interface RefreshResponse {
access_token: string;
refresh_token: string;
}
/** POST /api/v1/auth/login doğrudan backend (token clientta; cookie için loginViaCookie kullanın) */
export async function login(
email: string,
password: string
): Promise<LoginResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/login`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify({ email, password }),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error((err as { detail?: string }).detail ?? "Giriş başarısız");
}
return res.json();
}
/** Cookie tabanlı giriş tokenlar HTTP-only secure cookiede saklanır */
export async function loginViaCookie(
email: string,
password: string
): Promise<{ user: AuthUser }> {
const res = await fetch("/api/auth/cookie-login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: email.trim(), password }),
credentials: "include",
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error((data as { error?: string }).error ?? "Giriş başarısız");
}
return data as { user: AuthUser };
}
/** Cookie tabanlı çıkış */
export async function logoutViaCookie(): Promise<void> {
await fetch("/api/auth/cookie-logout", {
method: "POST",
credentials: "include",
});
}
/** Cookie oturumunu kontrol et (client tarafında oturum bilgisi için) */
export async function getCookieSession(): Promise<{
loggedIn: boolean;
user?: AuthUser;
}> {
const res = await fetch("/api/auth/cookie-session", { credentials: "include" });
const data = await res.json().catch(() => ({ loggedIn: false }));
return data as { loggedIn: boolean; user?: AuthUser };
}
/** POST /api/v1/auth/register */
export async function register(body: {
email: string;
first_name: string;
last_name: string;
password: string;
username: string;
}): Promise<RegisterResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/register`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
const detail = (err as { detail?: string | string[] }).detail;
const message = Array.isArray(detail) ? detail.join(" ") : detail ?? "Kayıt başarısız";
throw new Error(message);
}
return res.json();
}
/** GET /api/v1/auth/me */
export async function me(accessToken: string): Promise<{ user: AuthUser }> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/me`, {
headers: {
accept: "application/json",
Authorization: `Bearer ${accessToken}`,
},
});
if (!res.ok) throw new Error("Oturum bilgisi alınamadı");
return res.json();
}
/** POST /api/v1/auth/refresh */
export async function refresh(refreshToken: string): Promise<RefreshResponse> {
const base = getBaseUrl();
const res = await fetch(`${base}${API_PREFIX}/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json", accept: "application/json" },
body: JSON.stringify({ refresh_token: refreshToken }),
});
if (!res.ok) throw new Error("Token yenilenemedi");
return res.json();
}
const ACCESS_KEY = "auth_access_token";
const REFRESH_KEY = "auth_refresh_token";
const AUTH_CHANGE_EVENT = "auth-change";
/** Header vb. bileşenlerin oturum değişikliğini algılaması için tetiklenir. */
export function notifyAuthChange(): void {
if (typeof window === "undefined") return;
window.dispatchEvent(new Event(AUTH_CHANGE_EVENT));
}
export function setTokens(access: string, refreshToken: string): void {
if (typeof window === "undefined") return;
localStorage.setItem(ACCESS_KEY, access);
localStorage.setItem(REFRESH_KEY, refreshToken);
notifyAuthChange();
}
export function getAccessToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(ACCESS_KEY);
}
export function getRefreshToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(REFRESH_KEY);
}
export function clearTokens(): void {
if (typeof window === "undefined") return;
localStorage.removeItem(ACCESS_KEY);
localStorage.removeItem(REFRESH_KEY);
notifyAuthChange();
}
export { AUTH_CHANGE_EVENT };