Files
auto-trade/features/dashboard/store/use-kis-runtime-store.ts

193 lines
5.1 KiB
TypeScript
Raw Normal View History

2026-02-06 17:50:35 +09:00
"use client";
2026-02-10 11:16:39 +09:00
import { fetchKisWebSocketApproval } from "@/features/dashboard/apis/kis-auth.api";
2026-02-11 15:27:03 +09:00
import type { KisTradingEnv } from "@/features/dashboard/types/dashboard.types";
import { createJSONStorage, persist } from "zustand/middleware";
import { create } from "zustand";
2026-02-06 17:50:35 +09:00
/**
* @file features/dashboard/store/use-kis-runtime-store.ts
2026-02-11 15:27:03 +09:00
* @description Stores KIS input, verification, and websocket connection state.
* @see features/dashboard/hooks/useKisTradeWebSocket.ts
2026-02-06 17:50:35 +09:00
*/
export interface KisRuntimeCredentials {
appKey: string;
appSecret: string;
tradingEnv: KisTradingEnv;
2026-02-10 11:16:39 +09:00
accountNo: string;
2026-02-06 17:50:35 +09:00
}
2026-02-11 15:27:03 +09:00
interface KisWsConnection {
approvalKey: string;
wsUrl: string;
}
2026-02-06 17:50:35 +09:00
interface KisRuntimeStoreState {
kisTradingEnvInput: KisTradingEnv;
kisAppKeyInput: string;
kisAppSecretInput: string;
2026-02-10 11:16:39 +09:00
kisAccountNoInput: string;
2026-02-06 17:50:35 +09:00
verifiedCredentials: KisRuntimeCredentials | null;
isKisVerified: boolean;
tradingEnv: KisTradingEnv;
2026-02-10 11:16:39 +09:00
wsApprovalKey: string | null;
2026-02-11 15:27:03 +09:00
wsUrl: string | null;
2026-02-06 17:50:35 +09:00
}
interface KisRuntimeStoreActions {
setKisTradingEnvInput: (tradingEnv: KisTradingEnv) => void;
setKisAppKeyInput: (appKey: string) => void;
setKisAppSecretInput: (appSecret: string) => void;
2026-02-10 11:16:39 +09:00
setKisAccountNoInput: (accountNo: string) => void;
setVerifiedKisSession: (
credentials: KisRuntimeCredentials,
tradingEnv: KisTradingEnv,
) => void;
2026-02-06 17:50:35 +09:00
invalidateKisVerification: () => void;
clearKisRuntimeSession: (tradingEnv: KisTradingEnv) => void;
2026-02-11 15:27:03 +09:00
getOrFetchWsConnection: () => Promise<KisWsConnection | null>;
2026-02-06 17:50:35 +09:00
}
const INITIAL_STATE: KisRuntimeStoreState = {
kisTradingEnvInput: "real",
kisAppKeyInput: "",
kisAppSecretInput: "",
2026-02-10 11:16:39 +09:00
kisAccountNoInput: "",
2026-02-06 17:50:35 +09:00
verifiedCredentials: null,
isKisVerified: false,
tradingEnv: "real",
2026-02-10 11:16:39 +09:00
wsApprovalKey: null,
2026-02-11 15:27:03 +09:00
wsUrl: null,
2026-02-06 17:50:35 +09:00
};
2026-02-11 15:27:03 +09:00
const RESET_VERIFICATION_STATE = {
verifiedCredentials: null,
isKisVerified: false,
wsApprovalKey: null,
wsUrl: null,
};
2026-02-10 11:16:39 +09:00
2026-02-11 15:27:03 +09:00
let wsConnectionPromise: Promise<KisWsConnection | null> | null = null;
/**
* @description Runtime store for KIS session.
* @see features/dashboard/components/auth/KisAuthForm.tsx
*/
2026-02-10 11:16:39 +09:00
export const useKisRuntimeStore = create<
KisRuntimeStoreState & KisRuntimeStoreActions
>()(
2026-02-06 17:50:35 +09:00
persist(
2026-02-10 11:16:39 +09:00
(set, get) => ({
2026-02-06 17:50:35 +09:00
...INITIAL_STATE,
setKisTradingEnvInput: (tradingEnv) =>
set({
kisTradingEnvInput: tradingEnv,
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-06 17:50:35 +09:00
}),
setKisAppKeyInput: (appKey) =>
set({
kisAppKeyInput: appKey,
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-06 17:50:35 +09:00
}),
setKisAppSecretInput: (appSecret) =>
set({
kisAppSecretInput: appSecret,
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-10 11:16:39 +09:00
}),
setKisAccountNoInput: (accountNo) =>
set({
kisAccountNoInput: accountNo,
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-06 17:50:35 +09:00
}),
setVerifiedKisSession: (credentials, tradingEnv) =>
set({
verifiedCredentials: credentials,
isKisVerified: true,
tradingEnv,
2026-02-10 11:16:39 +09:00
wsApprovalKey: null,
2026-02-11 15:27:03 +09:00
wsUrl: null,
2026-02-06 17:50:35 +09:00
}),
invalidateKisVerification: () =>
set({
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-06 17:50:35 +09:00
}),
clearKisRuntimeSession: (tradingEnv) =>
set({
kisTradingEnvInput: tradingEnv,
kisAppKeyInput: "",
kisAppSecretInput: "",
2026-02-10 11:16:39 +09:00
kisAccountNoInput: "",
2026-02-11 15:27:03 +09:00
...RESET_VERIFICATION_STATE,
2026-02-06 17:50:35 +09:00
tradingEnv,
}),
2026-02-10 11:16:39 +09:00
2026-02-11 15:27:03 +09:00
getOrFetchWsConnection: async () => {
const { wsApprovalKey, wsUrl, verifiedCredentials } = get();
2026-02-10 11:16:39 +09:00
2026-02-11 15:27:03 +09:00
if (wsApprovalKey && wsUrl) {
return { approvalKey: wsApprovalKey, wsUrl };
2026-02-10 11:16:39 +09:00
}
if (!verifiedCredentials) {
return null;
}
2026-02-11 15:27:03 +09:00
if (wsConnectionPromise) {
return wsConnectionPromise;
2026-02-10 11:16:39 +09:00
}
2026-02-11 15:27:03 +09:00
wsConnectionPromise = (async () => {
2026-02-10 11:16:39 +09:00
try {
const data = await fetchKisWebSocketApproval(verifiedCredentials);
2026-02-11 15:27:03 +09:00
if (!data.approvalKey || !data.wsUrl) {
return null;
2026-02-10 11:16:39 +09:00
}
2026-02-11 15:27:03 +09:00
const nextConnection = {
approvalKey: data.approvalKey,
wsUrl: data.wsUrl,
} satisfies KisWsConnection;
set({
wsApprovalKey: nextConnection.approvalKey,
wsUrl: nextConnection.wsUrl,
});
return nextConnection;
2026-02-10 11:16:39 +09:00
} catch (error) {
console.error(error);
return null;
} finally {
2026-02-11 15:27:03 +09:00
wsConnectionPromise = null;
2026-02-10 11:16:39 +09:00
}
})();
2026-02-11 15:27:03 +09:00
return wsConnectionPromise;
2026-02-10 11:16:39 +09:00
},
2026-02-06 17:50:35 +09:00
}),
{
name: "autotrade-kis-runtime-store",
storage: createJSONStorage(() => localStorage),
partialize: (state) => ({
kisTradingEnvInput: state.kisTradingEnvInput,
kisAppKeyInput: state.kisAppKeyInput,
kisAppSecretInput: state.kisAppSecretInput,
2026-02-10 11:16:39 +09:00
kisAccountNoInput: state.kisAccountNoInput,
2026-02-06 17:50:35 +09:00
verifiedCredentials: state.verifiedCredentials,
isKisVerified: state.isKisVerified,
tradingEnv: state.tradingEnv,
2026-02-11 15:27:03 +09:00
// wsApprovalKey/wsUrl are kept in memory only (expiration-sensitive).
2026-02-06 17:50:35 +09:00
}),
},
),
);