116 lines
2.7 KiB
TypeScript
116 lines
2.7 KiB
TypeScript
// lib/auth-client.ts
|
|
|
|
const API_BASE_URL =
|
|
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
|
|
|
export type AuthUser = {
|
|
id: number;
|
|
email: string;
|
|
displayName?: string | null;
|
|
role: string;
|
|
};
|
|
|
|
export type AuthPayload = {
|
|
accessToken: string;
|
|
refreshToken?: string;
|
|
userId: number;
|
|
email: string;
|
|
displayName?: string | null;
|
|
role: string;
|
|
};
|
|
|
|
export type RegisterInput = {
|
|
email: string;
|
|
password: string;
|
|
displayName?: string;
|
|
};
|
|
|
|
export type LoginInput = {
|
|
email: string;
|
|
password: string;
|
|
};
|
|
|
|
const AUTH_STORAGE_KEY = "armory-auth";
|
|
|
|
export function storeAuth(payload: AuthPayload) {
|
|
if (typeof window === "undefined") return;
|
|
const user: AuthUser = {
|
|
id: payload.userId,
|
|
email: payload.email,
|
|
displayName: payload.displayName,
|
|
role: payload.role,
|
|
};
|
|
|
|
const toStore = {
|
|
user,
|
|
accessToken: payload.accessToken,
|
|
refreshToken: payload.refreshToken ?? null,
|
|
};
|
|
|
|
window.localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(toStore));
|
|
}
|
|
|
|
export function loadStoredAuth():
|
|
| { user: AuthUser; accessToken: string; refreshToken: string | null }
|
|
| null {
|
|
if (typeof window === "undefined") return null;
|
|
try {
|
|
const raw = window.localStorage.getItem(AUTH_STORAGE_KEY);
|
|
if (!raw) return null;
|
|
const parsed = JSON.parse(raw);
|
|
if (!parsed.user || !parsed.accessToken) return null;
|
|
return {
|
|
user: parsed.user as AuthUser,
|
|
accessToken: parsed.accessToken as string,
|
|
refreshToken: parsed.refreshToken ?? null,
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function clearStoredAuth() {
|
|
if (typeof window === "undefined") return;
|
|
window.localStorage.removeItem(AUTH_STORAGE_KEY);
|
|
}
|
|
|
|
async function handleAuthResponse(res: Response): Promise<AuthPayload> {
|
|
if (!res.ok) {
|
|
let message = `Request failed (${res.status})`;
|
|
try {
|
|
const body = await res.json();
|
|
if (body?.message) message = body.message;
|
|
} catch {
|
|
// ignore
|
|
}
|
|
throw new Error(message);
|
|
}
|
|
|
|
return (await res.json()) as AuthPayload;
|
|
}
|
|
|
|
export async function apiRegister(input: RegisterInput): Promise<AuthPayload> {
|
|
const res = await fetch(`${API_BASE_URL}/api/auth/register`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
},
|
|
body: JSON.stringify(input),
|
|
});
|
|
|
|
return handleAuthResponse(res);
|
|
}
|
|
|
|
export async function apiLogin(input: LoginInput): Promise<AuthPayload> {
|
|
const res = await fetch(`${API_BASE_URL}/api/auth/login`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "application/json",
|
|
},
|
|
body: JSON.stringify(input),
|
|
});
|
|
|
|
return handleAuthResponse(res);
|
|
} |