/** * 📄 Proxy Route * API 프록시 라우트 * * - 서버 API로의 요청 프록시 처리 * - 쿠키 기반 인증 토큰 및 리프레시 토큰 관리 * - POST 및 PUT 요청 핸들링 * - 사용자 인증 정보 검증 및 응답 처리 * - 에러 핸들링 및 상태 코드 반환 * - 사이트 ID 및 헤더 설정 */ import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME, COOKIE_DOMAIN, REFRESH_TOKEN, SERVER_API_URL, SITE_ID, } from "@/shared/config"; import { cookies } from "next/headers"; import { NextResponse } from "next/server"; async function handler( request: Request, params: { url: string[] }, method: "GET" | "POST" | "PUT" | "DELETE", ) { const cookieStore = await cookies(); const headers: Record = { "Content-Type": "application/json", "X-Site-Id": SITE_ID, }; const deviceId = request.headers.get("X-Device-Id"); if (deviceId) { headers["X-Device-Id"] = deviceId; } let body = {}; const isRefreshHandler = params.url.includes("refresh"); // silent refresh if (isRefreshHandler) { const refreshToken = cookieStore.get(REFRESH_TOKEN); headers[CLAIM_NAME] = refreshToken?.value ?? ""; if (!headers[CLAIM_NAME]) { return NextResponse.json( { message: "Can't refresh" }, { status: 401 }, ); } } try { if (!isRefreshHandler) { body = await request.json(); } const result = await fetch(`${SERVER_API_URL}/${params.url.join("/")}`, { method, headers, body: JSON.stringify(body), }); if (!result.ok) { console.log("Invalid Credentials "); return NextResponse.json( { message: "Invalid Credentials" }, { status: 401 }, ); } const accessToken = result.headers.get(ACCESS_TOKEN); const refreshToken = result.headers.get(REFRESH_TOKEN); const userId = result.headers.get(AUTH_USER_ID); if (accessToken && userId) { const response = NextResponse.json({ [ACCESS_TOKEN]: accessToken, [AUTH_USER_ID]: userId, }); if (refreshToken) { cookieStore.set(REFRESH_TOKEN, refreshToken, { httpOnly: true, sameSite: "lax", domain: getCookieDomain(), path: "/", }); } return response; } return NextResponse.json( { message: "Invalid Credentials" }, { status: 401 }, ); } catch (error) { return NextResponse.json( { message: "Server Error", error }, { status: 500 }, ); } } export async function POST( request: Request, props: { params: Promise<{ url: string[] }> }, ) { const params = await props.params; return handler(request, params, "POST"); } export async function PUT( request: Request, props: { params: Promise<{ url: string[] }> }, ) { const params = await props.params; return handler(request, params, "PUT"); } function getCookieDomain(): string | undefined { if (typeof window === "undefined") return undefined; if (COOKIE_DOMAIN) return COOKIE_DOMAIN; const { hostname } = window.location; if (hostname === "localhost" || hostname === "127.0.0.1") return undefined; return hostname; }