feat: refresh shared chat and server workflows

This commit is contained in:
2026-05-26 12:26:33 +09:00
parent 51e0099bea
commit c1d0f4c1db
82 changed files with 18604 additions and 12461 deletions

View File

@@ -1,15 +1,21 @@
import { App as AntdApp } from 'antd';
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { getOrCreateClientId } from './app/main/clientIdentity';
import { reportClientError } from './app/main/errorLogApi';
import { AppShell } from './app/main';
import { InitialLoadingOverlay } from './app/main/InitialLoadingOverlay';
import { ReleasePendingMainModal } from './app/main/ReleasePendingMainModal';
import { buildChatPath } from './app/main/routes';
import { isPreviewRuntime } from './app/main/previewRuntime';
import { bindViewportCssVars } from './app/main/viewportCssVars';
import { reportVisitorPageView } from './features/history/api';
import { useAppStore } from './store';
const CHUNK_LOAD_RETRY_SESSION_KEY = 'ai-code-app.chunk-load-retried';
const CACHE_RECOVERY_SESSION_KEY = 'ai-code-app.cache-recovery-completed';
const INITIAL_LOADING_MIN_VISIBLE_MS = 450;
const CACHE_RECOVERY_NOTICE = '캐시된 화면 정보가 맞지 않아 홈으로 이동합니다. 다시 열어 주세요.';
const CACHE_RECOVERY_DELAY_MS = 900;
function shouldRetryChunkLoad(errorMessage: string) {
return /Failed to fetch dynamically imported module|Importing a module script failed|Load failed|ChunkLoadError/i.test(
@@ -17,6 +23,12 @@ function shouldRetryChunkLoad(errorMessage: string) {
);
}
function shouldRecoverFromCacheError(errorMessage: string) {
return /Failed to fetch dynamically imported module|Importing a module script failed|Load failed|ChunkLoadError|Loading chunk|Failed to load module script|does not provide an export named|Cannot find module/i.test(
errorMessage,
);
}
function retryChunkLoadOnce(errorMessage: string) {
if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {
return false;
@@ -39,7 +51,45 @@ function retryChunkLoadOnce(errorMessage: string) {
}
}
function getHomeRecoveryUrl() {
if (typeof window === 'undefined') {
return buildChatPath('live');
}
return new URL(buildChatPath('live'), window.location.origin).toString();
}
function tryRecoverToHomeFromCacheError(errorMessage: string, notify: (text: string) => void) {
if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {
return false;
}
if (isPreviewRuntime()) {
return false;
}
if (!shouldRecoverFromCacheError(errorMessage)) {
return false;
}
try {
if (sessionStorage.getItem(CACHE_RECOVERY_SESSION_KEY) === '1') {
return false;
}
sessionStorage.setItem(CACHE_RECOVERY_SESSION_KEY, '1');
notify(CACHE_RECOVERY_NOTICE);
window.setTimeout(() => {
window.location.replace(getHomeRecoveryUrl());
}, CACHE_RECOVERY_DELAY_MS);
return true;
} catch {
return false;
}
}
function App() {
const { message } = AntdApp.useApp();
const { currentPage } = useAppStore();
const lastTrackedPageIdRef = useRef<string | null>(null);
const [showInitialLoading, setShowInitialLoading] = useState(true);
@@ -51,6 +101,13 @@ function App() {
return undefined;
}
const notifyCacheRecovery = (text: string) => {
message.warning({
content: text,
duration: 1.5,
});
};
const handleError = (event: ErrorEvent) => {
const reportedError = event.error instanceof Error ? event.error : null;
const errorMessage = event.message || reportedError?.message || '클라이언트 오류가 발생했습니다.';
@@ -71,6 +128,8 @@ function App() {
column: event.colno || null,
},
});
tryRecoverToHomeFromCacheError(errorMessage, notifyCacheRecovery);
};
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
@@ -93,6 +152,8 @@ function App() {
reasonType: typeof reason,
},
});
tryRecoverToHomeFromCacheError(errorMessage, notifyCacheRecovery);
};
window.addEventListener('error', handleError);
@@ -102,7 +163,7 @@ function App() {
window.removeEventListener('error', handleError);
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
};
}, []);
}, [message]);
useEffect(() => {
getOrCreateClientId();