import type { DashboardKisWsApprovalResponse } from "@/features/dashboard/types/dashboard.types"; import type { KisCredentialInput } from "@/lib/kis/config"; import { hasKisConfig, normalizeTradingEnv } from "@/lib/kis/config"; import { getKisApprovalKey, resolveKisWebSocketUrl } from "@/lib/kis/approval"; import { NextRequest, NextResponse } from "next/server"; /** * @file app/api/kis/ws/approval/route.ts * @description KIS 웹소켓 approval key 발급 라우트 */ /** * 실시간 웹소켓 승인키 발급 * @param request appKey/appSecret/tradingEnv JSON 본문 * @returns approval key + ws url * @see features/dashboard/components/dashboard-main.tsx connectKisRealtimePrice - 실시간 체결가 구독 진입점 */ export async function POST(request: NextRequest) { const body = (await request.json()) as Partial; const credentials: KisCredentialInput = { appKey: body.appKey?.trim(), appSecret: body.appSecret?.trim(), tradingEnv: normalizeTradingEnv(body.tradingEnv), }; if (!hasKisConfig(credentials)) { return NextResponse.json( { ok: false, tradingEnv: normalizeTradingEnv(credentials.tradingEnv), message: "앱 키와 앱 시크릿을 모두 입력해 주세요.", } satisfies DashboardKisWsApprovalResponse, { status: 400 }, ); } try { const approvalKey = await getKisApprovalKey(credentials); const wsUrl = resolveKisWebSocketUrl(credentials); return NextResponse.json({ ok: true, tradingEnv: normalizeTradingEnv(credentials.tradingEnv), approvalKey, wsUrl, message: "KIS 실시간 웹소켓 승인키 발급이 완료되었습니다.", } satisfies DashboardKisWsApprovalResponse); } catch (error) { const message = error instanceof Error ? error.message : "웹소켓 승인키 발급 중 오류가 발생했습니다."; return NextResponse.json( { ok: false, tradingEnv: normalizeTradingEnv(credentials.tradingEnv), message, } satisfies DashboardKisWsApprovalResponse, { status: 401 }, ); } } interface DashboardKisWsApprovalRequest { appKey: string; appSecret: string; tradingEnv: "real" | "mock"; }