스킬 정리 및 리팩토링
This commit is contained in:
188
lib/kis/error-codes.ts
Normal file
188
lib/kis/error-codes.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file lib/kis/error-codes.ts
|
||||
* @description KIS FAQ 오류코드(msg_cd) 문구를 공통으로 해석하는 유틸입니다.
|
||||
* @see https://apiportal.koreainvestment.com/faq-error-code 한국투자증권 공식 오류코드 기준
|
||||
*/
|
||||
|
||||
export const KIS_ERROR_CODE_REFERENCE_URL =
|
||||
"https://apiportal.koreainvestment.com/faq-error-code";
|
||||
|
||||
const KIS_ERROR_CODE_MESSAGE_MAP = {
|
||||
EGW00001: "일시적 오류가 발생했습니다.",
|
||||
EGW00002: "서버 에러가 발생했습니다.",
|
||||
EGW00003: "접근이 거부되었습니다.",
|
||||
EGW00004: "권한을 부여받지 않은 고객입니다.",
|
||||
EGW00101: "유효하지 않은 요청입니다.",
|
||||
EGW00102: "AppKey는 필수입니다.",
|
||||
EGW00103: "유효하지 않은 AppKey입니다.",
|
||||
EGW00104: "AppSecret은 필수입니다.",
|
||||
EGW00105: "유효하지 않은 AppSecret입니다.",
|
||||
EGW00106: "redirect_uri는 필수입니다.",
|
||||
EGW00107: "유효하지 않은 redirect_uri입니다.",
|
||||
EGW00108: "유효하지 않은 서비스구분(service)입니다.",
|
||||
EGW00109: "scope는 필수입니다.",
|
||||
EGW00110: "유효하지 않은 scope 입니다.",
|
||||
EGW00111: "유효하지 않은 state 입니다.",
|
||||
EGW00112: "유효하지 않은 grant 입니다.",
|
||||
EGW00113: "응답구분(response_type)은 필수입니다.",
|
||||
EGW00114: "지원하지 않는 응답구분(response_type)입니다.",
|
||||
EGW00115: "권한부여 타입(grant_type)은 필수입니다.",
|
||||
EGW00116: "지원하지 않는 권한부여 타입(grant_type)입니다.",
|
||||
EGW00117: "지원하지 않는 토큰 타입(token_type)입니다.",
|
||||
EGW00118: "유효하지 않은 code 입니다.",
|
||||
EGW00119: "code를 찾을 수 없습니다.",
|
||||
EGW00120: "기간이 만료된 code 입니다.",
|
||||
EGW00121: "유효하지 않은 token 입니다.",
|
||||
EGW00122: "token을 찾을 수 없습니다.",
|
||||
EGW00123: "기간이 만료된 token 입니다.",
|
||||
EGW00124: "유효하지 않은 session_key 입니다.",
|
||||
EGW00125: "session_key를 찾을 수 없습니다.",
|
||||
EGW00126: "기간이 만료된 session_key 입니다.",
|
||||
EGW00127: "제휴사번호(corpno)는 필수입니다.",
|
||||
EGW00128: "계좌번호(acctno)는 필수입니다.",
|
||||
EGW00129: "HTS_ID는 필수입니다.",
|
||||
EGW00130: "유효하지 않은 유저(user)입니다.",
|
||||
EGW00131: "유효하지 않은 hashkey입니다.",
|
||||
EGW00132: "Content-Type이 유효하지 않습니다.",
|
||||
EGW00201: "초당 거래건수를 초과하였습니다.",
|
||||
EGW00202: "GW라우팅 중 오류가 발생했습니다.",
|
||||
EGW00203: "OPS라우팅 중 오류가 발생했습니다.",
|
||||
EGW00204: "Internal Gateway 인스턴스를 잘못 입력했습니다.",
|
||||
EGW00205: "credentials_type이 유효하지 않습니다.(Bearer)",
|
||||
EGW00206: "API 사용 권한이 없습니다.",
|
||||
EGW00207: "IP 주소가 없거나 유효하지 않습니다.",
|
||||
EGW00208: "고객유형(custtype)이 유효하지 않습니다.",
|
||||
EGW00209: "일련번호(seq_no)가 유효하지 않습니다.",
|
||||
EGW00210: "법인고객의 경우 모의투자를 이용할 수 없습니다.",
|
||||
EGW00211: "고객명(personalname)은 필수 입니다.",
|
||||
EGW00212: "휴대전화번호(personalphone)는 필수 입니다.",
|
||||
EGW00213: "제휴사명(corpname)은 필수 입니다. / 모의투자 tr이 아닙니다.",
|
||||
EGW00300: "Gateway 라우팅 오류가 발생했습니다.",
|
||||
EGW00301: "연결 시간이 초과되었습니다. 직전 거래를 반드시 확인하세요.",
|
||||
EGW00302: "거래시간이 초과되었습니다. 직전 거래를 반드시 확인하세요.",
|
||||
EGW00303: "법인고객에게 허용되지 않은 IP접근입니다.",
|
||||
EGW00304:
|
||||
"고객식별키(법인 personalSeckey, 개인 appSecret)가 유효하지 않습니다.",
|
||||
OPSQ0001: "호출 전처리 오류 입니다.",
|
||||
OPSQ0002: "없는 서비스 코드 입니다.",
|
||||
OPSQ0003: "호출 오류 입니다.",
|
||||
OPSQ0004: "호출 후처리 오류 입니다.",
|
||||
OPSQ0005: "호출 후처리 오류 입니다.",
|
||||
OPSQ0006: "호출 후처리 오류 입니다.",
|
||||
OPSQ0007: "호출 후처리(헤더설정) 오류 입니다.",
|
||||
OPSQ0008: "호출 후처리(MCI전송) 오류 입니다.",
|
||||
OPSQ0009: "호출 후처리(MCI수신) 오류 입니다.",
|
||||
OPSQ0010: "호출 결과처리(리소스 부족) 오류 입니다.",
|
||||
OPSQ0011: "호출 결과처리(리소스 부족) 오류 입니다.",
|
||||
OPSQ1002: "세션 연결 오류.",
|
||||
OPSQ2000: "ERROR : INPUT INVALID_CHECK_ACNO",
|
||||
OPSQ2001: "ERROR : INPUT INVALID_CHECK_MRKT_DIV_CODE",
|
||||
OPSQ2002: "ERROR : INPUT INVALID_CHECK_FIELD_LENGTH",
|
||||
OPSQ2003: "ERROR : SET_MCI_SEND_DATA",
|
||||
OPSQ3001: "ERROR : RESPONSE_ADDITEMTOOBJECT",
|
||||
OPSQ3002: "ERROR : GET_CALL_PARAM_MCI_SEND_DATA_LEN",
|
||||
OPSQ3004: "ERROR : OUT_STRING_ARRAY ALLOC FAILED",
|
||||
OPSQ9995: "JSON PARSING ERROR : body not found",
|
||||
OPSQ9996: "JSON PARSING ERROR : header not found",
|
||||
OPSQ9997: "JSON PARSING ERROR : invalid json format",
|
||||
OPSQ9998: "JSON PARSING ERROR : seq_no not found",
|
||||
OPSQ9999: "JSON PARSING ERROR : tr_id not found",
|
||||
OPSP0000: "SUBSCRIBE SUCCESS",
|
||||
OPSP0001: "UNSUBSCRIBE SUCCESS",
|
||||
OPSP0002: "ALREADY IN SUBSCRIBE",
|
||||
OPSP0003: "UNSUBSCRIBE ERROR(not found!)",
|
||||
OPSP0007: "SUBSCRIBE INTERNAL ERROR",
|
||||
OPSP0008: "MAX SUBSCRIBE OVER",
|
||||
OPSP0009: "SUBSCRIBE ERROR : mci send failed",
|
||||
OPSP0010: "SUBSCRIBE WARNNING : invalid appkey",
|
||||
OPSP0011: "invalid approval(appkey) : NOT FOUND",
|
||||
OPSP8991: "SUBSCRIBE ERROR : invalid tr_id",
|
||||
OPSP8992: "SUBSCRIBE ERROR : invalid tr_key",
|
||||
OPSP8993: "JSON PARSING ERROR : invalid tr_key",
|
||||
OPSP8994: "JSON PARSING ERROR : personalseckey not found",
|
||||
OPSP8995: "JSON PARSING ERROR : appsecret not found",
|
||||
OPSP8996: "ALREADY IN USE appkey",
|
||||
OPSP8997: "JSON PARSING ERROR : invalid tr_type",
|
||||
OPSP8998: "JSON PARSING ERROR : invalid custtype",
|
||||
OPSP8999: "resource not available (ALLOC_CALL_PARAM)",
|
||||
OPSP9990: "JSON PARSING ERROR : tr_key not found",
|
||||
OPSP9991: "JSON PARSING ERROR : input not found",
|
||||
OPSP9992: "JSON PARSING ERROR : body not found",
|
||||
OPSP9993: "JSON PARSING ERROR : internal error",
|
||||
OPSP9994: "JSON PARSING ERROR : INVALID appkey",
|
||||
OPSP9995: "JSON PARSING ERROR : resource not available",
|
||||
OPSP9996: "JSON PARSING ERROR : appkey",
|
||||
OPSP9997: "JSON PARSING ERROR : custtype not found",
|
||||
OPSP9998: "JSON PARSING ERROR : header not found",
|
||||
OPSP9999: "JSON PARSING ERROR : invalid json format",
|
||||
} as const;
|
||||
|
||||
export interface KisErrorGuide {
|
||||
code: string;
|
||||
message: string;
|
||||
referenceUrl: string;
|
||||
}
|
||||
|
||||
interface BuildKisErrorDetailParams {
|
||||
message?: string;
|
||||
msgCode?: string;
|
||||
extraMessages?: Array<string | undefined>;
|
||||
}
|
||||
|
||||
function normalizeKisErrorCode(msgCode?: string) {
|
||||
return msgCode?.trim().toUpperCase() ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @description KIS msg_cd를 공식 FAQ 문구와 매칭합니다.
|
||||
* @param msgCode KIS 응답 msg_cd
|
||||
* @returns 코드/문구/참고 URL 정보. 없으면 null
|
||||
* @see lib/kis/client.ts kisGet/kisPost 비즈니스 오류 메시지 구성
|
||||
* @see features/kis-realtime/stores/kisWebSocketStore.ts 실시간 제어 오류 안내문 구성
|
||||
*/
|
||||
export function getKisErrorGuide(msgCode?: string): KisErrorGuide | null {
|
||||
const code = normalizeKisErrorCode(msgCode);
|
||||
if (!code) return null;
|
||||
|
||||
const message =
|
||||
KIS_ERROR_CODE_MESSAGE_MAP[
|
||||
code as keyof typeof KIS_ERROR_CODE_MESSAGE_MAP
|
||||
];
|
||||
if (!message) return null;
|
||||
|
||||
return {
|
||||
code,
|
||||
message,
|
||||
referenceUrl: KIS_ERROR_CODE_REFERENCE_URL,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description KIS 오류 조각(msg1/msg_cd/부가메시지)을 사람이 읽기 쉬운 한 줄로 합칩니다.
|
||||
* @param params 오류 문자열 조합 입력값
|
||||
* @returns 중복 제거된 상세 메시지
|
||||
* @see lib/kis/token.ts buildTokenIssueDetail 토큰 발급/폐기 오류 상세 구성
|
||||
* @see lib/kis/approval.ts issueKisApprovalKey 승인키 발급 오류 상세 구성
|
||||
*/
|
||||
export function buildKisErrorDetail({
|
||||
message,
|
||||
msgCode,
|
||||
extraMessages = [],
|
||||
}: BuildKisErrorDetailParams) {
|
||||
const tokens = new Set<string>();
|
||||
|
||||
for (const raw of [...extraMessages, message]) {
|
||||
const normalized = raw?.trim();
|
||||
if (normalized) tokens.add(normalized);
|
||||
}
|
||||
|
||||
const guide = getKisErrorGuide(msgCode);
|
||||
const normalizedCode = normalizeKisErrorCode(msgCode);
|
||||
if (guide) {
|
||||
tokens.add(`${guide.code} (${guide.message})`);
|
||||
} else if (normalizedCode) {
|
||||
tokens.add(normalizedCode);
|
||||
}
|
||||
|
||||
return [...tokens].join(" / ");
|
||||
}
|
||||
Reference in New Issue
Block a user