스킬 정리 및 리팩토링

This commit is contained in:
2026-02-26 09:05:17 +09:00
parent 4c52d6d82f
commit 406af7408a
71 changed files with 3776 additions and 3934 deletions

View File

@@ -1,4 +1,9 @@
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,
@@ -8,11 +13,6 @@ import type {
DashboardStockOverviewResponse,
DashboardStockSearchResponse,
} from "@/features/trade/types/trade.types";
import {
DOMESTIC_KIS_SESSION_OVERRIDE_HEADER,
DOMESTIC_KIS_SESSION_OVERRIDE_STORAGE_KEY,
parseDomesticKisSession,
} from "@/lib/kis/domestic-market-session";
/**
* 종목 검색 API 호출
@@ -32,12 +32,10 @@ export async function fetchStockSearch(
const payload = (await response.json()) as
| DashboardStockSearchResponse
| { error?: string };
| KisApiErrorPayload;
if (!response.ok) {
throw new Error(
"error" in payload ? payload.error : "종목 검색 중 오류가 발생했습니다.",
);
throw new Error(resolveKisApiErrorMessage(payload, "종목 검색 중 오류가 발생했습니다."));
}
return payload as DashboardStockSearchResponse;
@@ -56,19 +54,19 @@ export async function fetchStockOverview(
`/api/kis/domestic/overview?symbol=${encodeURIComponent(symbol)}`,
{
method: "GET",
headers: buildKisRequestHeaders(credentials),
headers: buildKisRequestHeaders(credentials, {
includeSessionOverride: true,
}),
cache: "no-store",
},
);
const payload = (await response.json()) as
| DashboardStockOverviewResponse
| { error?: string };
| KisApiErrorPayload;
if (!response.ok) {
throw new Error(
"error" in payload ? payload.error : "종목 조회 중 오류가 발생했습니다.",
);
throw new Error(resolveKisApiErrorMessage(payload, "종목 조회 중 오류가 발생했습니다."));
}
return payload as DashboardStockOverviewResponse;
@@ -88,7 +86,9 @@ export async function fetchStockOrderBook(
`/api/kis/domestic/orderbook?symbol=${encodeURIComponent(symbol)}`,
{
method: "GET",
headers: buildKisRequestHeaders(credentials),
headers: buildKisRequestHeaders(credentials, {
includeSessionOverride: true,
}),
cache: "no-store",
signal,
},
@@ -96,12 +96,10 @@ export async function fetchStockOrderBook(
const payload = (await response.json()) as
| DashboardStockOrderBookResponse
| { error?: string };
| KisApiErrorPayload;
if (!response.ok) {
throw new Error(
"error" in payload ? payload.error : "호가 조회 중 오류가 발생했습니다.",
);
throw new Error(resolveKisApiErrorMessage(payload, "호가 조회 중 오류가 발생했습니다."));
}
return payload as DashboardStockOrderBookResponse;
@@ -124,18 +122,18 @@ export async function fetchStockChart(
const response = await fetch(`/api/kis/domestic/chart?${query.toString()}`, {
method: "GET",
headers: buildKisRequestHeaders(credentials),
headers: buildKisRequestHeaders(credentials, {
includeSessionOverride: true,
}),
cache: "no-store",
});
const payload = (await response.json()) as
| DashboardStockChartResponse
| { error?: string };
| KisApiErrorPayload;
if (!response.ok) {
throw new Error(
"error" in payload ? payload.error : "차트 조회 중 오류가 발생했습니다.",
);
throw new Error(resolveKisApiErrorMessage(payload, "차트 조회 중 오류가 발생했습니다."));
}
return payload as DashboardStockChartResponse;
@@ -152,51 +150,21 @@ export async function fetchOrderCash(
): Promise<DashboardStockCashOrderResponse> {
const response = await fetch("/api/kis/domestic/order-cash", {
method: "POST",
headers: buildKisRequestHeaders(credentials, { jsonContentType: true }),
headers: buildKisRequestHeaders(credentials, {
jsonContentType: true,
includeSessionOverride: true,
}),
body: JSON.stringify(request),
cache: "no-store",
});
const payload = (await response.json()) as DashboardStockCashOrderResponse;
const payload = (await response.json()) as
| DashboardStockCashOrderResponse
| KisApiErrorPayload;
if (!response.ok) {
throw new Error(payload.message || "주문 전송 중 오류가 발생했습니다.");
throw new Error(resolveKisApiErrorMessage(payload, "주문 전송 중 오류가 발생했습니다."));
}
return payload;
return payload as DashboardStockCashOrderResponse;
}
function buildKisRequestHeaders(
credentials: KisRuntimeCredentials,
options?: { jsonContentType?: boolean },
) {
const headers: Record<string, string> = {
"x-kis-app-key": credentials.appKey,
"x-kis-app-secret": credentials.appSecret,
"x-kis-trading-env": credentials.tradingEnv,
};
if (options?.jsonContentType) {
headers["content-type"] = "application/json";
}
const sessionOverride = readSessionOverrideForDev();
if (sessionOverride) {
headers[DOMESTIC_KIS_SESSION_OVERRIDE_HEADER] = sessionOverride;
}
return headers;
}
function readSessionOverrideForDev() {
if (typeof window === "undefined") return null;
try {
const raw = window.localStorage.getItem(
DOMESTIC_KIS_SESSION_OVERRIDE_STORAGE_KEY,
);
return parseDomesticKisSession(raw);
} catch {
return null;
}
}