import type { KisRuntimeCredentials } from "@/features/settings/store/use-kis-runtime-store"; import { buildKisRequestHeaders, resolveKisApiErrorMessage, type KisApiErrorPayload, } from "@/features/settings/apis/kis-api-utils"; import type { DashboardChartTimeframe, DashboardStockCashOrderRequest, DashboardStockCashOrderResponse, DashboardStockOrderableCashRequest, DashboardStockOrderableCashResponse, DashboardStockChartResponse, DashboardStockOrderBookResponse, DashboardStockOverviewResponse, DashboardStockSearchResponse, } from "@/features/trade/types/trade.types"; /** * 종목 검색 API 호출 * @param keyword 검색어 */ export async function fetchStockSearch( keyword: string, signal?: AbortSignal, ): Promise { const response = await fetch( `/api/kis/domestic/search?q=${encodeURIComponent(keyword)}`, { cache: "no-store", signal, }, ); const payload = (await response.json()) as | DashboardStockSearchResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "종목 검색 중 오류가 발생했습니다.")); } return payload as DashboardStockSearchResponse; } /** * 종목 상세 개요 조회 API 호출 * @param symbol 종목코드 * @param credentials KIS 인증 정보 */ export async function fetchStockOverview( symbol: string, credentials: KisRuntimeCredentials, ): Promise { const response = await fetch( `/api/kis/domestic/overview?symbol=${encodeURIComponent(symbol)}`, { method: "GET", headers: buildKisRequestHeaders(credentials, { includeSessionOverride: true, }), cache: "no-store", }, ); const payload = (await response.json()) as | DashboardStockOverviewResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "종목 조회 중 오류가 발생했습니다.")); } return payload as DashboardStockOverviewResponse; } /** * 종목 호가 조회 API 호출 * @param symbol 종목코드 * @param credentials KIS 인증 정보 */ export async function fetchStockOrderBook( symbol: string, credentials: KisRuntimeCredentials, signal?: AbortSignal, ): Promise { const response = await fetch( `/api/kis/domestic/orderbook?symbol=${encodeURIComponent(symbol)}`, { method: "GET", headers: buildKisRequestHeaders(credentials, { includeSessionOverride: true, }), cache: "no-store", signal, }, ); const payload = (await response.json()) as | DashboardStockOrderBookResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "호가 조회 중 오류가 발생했습니다.")); } return payload as DashboardStockOrderBookResponse; } /** * 종목 차트(분봉/일봉/주봉) 조회 API 호출 */ export async function fetchStockChart( symbol: string, timeframe: DashboardChartTimeframe, credentials: KisRuntimeCredentials, cursor?: string, ): Promise { const query = new URLSearchParams({ symbol, timeframe, }); if (cursor) query.set("cursor", cursor); const response = await fetch(`/api/kis/domestic/chart?${query.toString()}`, { method: "GET", headers: buildKisRequestHeaders(credentials, { includeSessionOverride: true, }), cache: "no-store", }); const payload = (await response.json()) as | DashboardStockChartResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "차트 조회 중 오류가 발생했습니다.")); } return payload as DashboardStockChartResponse; } /** * 주식 현금 주문 API 호출 * @param request 주문 요청 데이터 * @param credentials KIS 인증 정보 */ export async function fetchOrderCash( request: DashboardStockCashOrderRequest, credentials: KisRuntimeCredentials, ): Promise { const response = await fetch("/api/kis/domestic/order-cash", { method: "POST", headers: buildKisRequestHeaders(credentials, { jsonContentType: true, includeSessionOverride: true, }), body: JSON.stringify(request), cache: "no-store", }); const payload = (await response.json()) as | DashboardStockCashOrderResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "주문 전송 중 오류가 발생했습니다.")); } return payload as DashboardStockCashOrderResponse; } /** * 매수가능금액(주문가능현금) 조회 API 호출 * @param request 종목/가격 기준 조회 요청 * @param credentials KIS 인증 정보 */ export async function fetchOrderableCashEstimate( request: DashboardStockOrderableCashRequest, credentials: KisRuntimeCredentials, ): Promise { const response = await fetch("/api/kis/domestic/orderable-cash", { method: "POST", headers: buildKisRequestHeaders(credentials, { jsonContentType: true, includeAccountNo: true, includeSessionOverride: true, }), body: JSON.stringify(request), cache: "no-store", }); const payload = (await response.json()) as | DashboardStockOrderableCashResponse | KisApiErrorPayload; if (!response.ok) { throw new Error(resolveKisApiErrorMessage(payload, "매수가능금액 조회 중 오류가 발생했습니다.")); } return payload as DashboardStockOrderableCashResponse; }