pc 프로그램 다운로드 기능 적용

This commit is contained in:
Macbook
2026-06-14 10:25:22 +09:00
parent 86b99d8c10
commit 92f67580e3
25 changed files with 1031 additions and 125 deletions
+17 -6
View File
@@ -14,8 +14,8 @@ export type StrategyFlowLayoutStore = Record<string, unknown>;
/** 배포 APK·exdev (모바일 APK — http) */
export const PRODUCTION_API_BASE = 'http://exdev.co.kr/api';
/** Tauri desktop — macOS ATS 호환 (https 필수) */
export const DESKTOP_API_BASE = 'https://exdev.co.kr/api';
/** Tauri desktop — exdev HTTP (HTTPS /api는 Caddy에서 빈 응답) */
export const DESKTOP_API_BASE = 'http://exdev.co.kr/api';
function viteEnv(): Record<string, string> | undefined {
return typeof import.meta !== 'undefined'
@@ -43,7 +43,6 @@ function isDesktopClient(): boolean {
}
function resolveApiBase(): string {
// Desktop(Tauri): https exdev (macOS ATS — http 차단)
if (isDesktopClient()) {
return DESKTOP_API_BASE;
}
@@ -128,6 +127,18 @@ const DEFAULT_FETCH_TIMEOUT_MS = 45_000;
/** exdev 첫 로그인 응답이 60초 이상 걸리는 경우 있음 */
const LOGIN_FETCH_TIMEOUT_MS = 180_000;
type HttpFetchFn = typeof fetch;
let httpFetchImpl: HttpFetchFn | null = null;
/** Tauri 등 WebView fetch 대신 네이티브 HTTP 사용 (desktop bootstrap에서 호출) */
export function setHttpFetch(fn: HttpFetchFn): void {
httpFetchImpl = fn;
}
function httpFetch(): HttpFetchFn {
return httpFetchImpl ?? fetch;
}
function wrapNetworkError(e: unknown): Error {
if (e instanceof TypeError || (e instanceof Error && /failed to fetch|load failed/i.test(e.message))) {
return new Error(
@@ -145,7 +156,7 @@ async function fetchWithTimeout(
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
return await fetch(url, {
return await httpFetch()(url, {
...init,
signal: controller.signal,
headers: { ...authHeaders(), ...(init?.headers ?? {}) },
@@ -978,7 +989,7 @@ export async function loadStrategy(id: number): Promise<StrategyDto | null> {
/** 전략 저장 (id 없으면 신규, 있으면 수정) — 실패 시 Error throw */
export async function saveStrategy(dto: StrategyDto): Promise<StrategyDto> {
const res = await fetch(`${API_BASE}/strategies`, {
const res = await httpFetch()(`${API_BASE}/strategies`, {
method: 'POST',
headers: authHeaders(),
body: JSON.stringify(dto),
@@ -1337,7 +1348,7 @@ export async function repairStrategyTimeframes(strategyId: number): Promise<void
/** 차트 실시간 파이프라인 pin (STOMP warm-up) */
export async function pinCandleWatch(market: string, candleType: string): Promise<void> {
try {
await fetch(
await httpFetch()(
`${API_BASE}/candles/watch?market=${encodeURIComponent(market)}&type=${encodeURIComponent(candleType)}`,
{ method: 'POST' },
);