84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
/**
|
|
* 서버에 없는 전략 ID — 세션 간 404 반복 방지 (sessionStorage)
|
|
*/
|
|
const STORAGE_KEY = 'gc_strategy_missing_ids_v1';
|
|
const MAX_STORED = 64;
|
|
|
|
const strategyMissingIds = new Set<number>();
|
|
|
|
function persistStrategyMissingCache(): void {
|
|
try {
|
|
const arr = [...strategyMissingIds].filter(id => id > 0).slice(-MAX_STORED);
|
|
if (arr.length === 0) sessionStorage.removeItem(STORAGE_KEY);
|
|
else sessionStorage.setItem(STORAGE_KEY, JSON.stringify(arr));
|
|
} catch {
|
|
/* private mode · 용량 */
|
|
}
|
|
}
|
|
|
|
/** 앱 기동 시 이전 탭에서 기록한 missing ID 복원 */
|
|
export function hydrateStrategyMissingCache(): void {
|
|
try {
|
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return;
|
|
const parsed = JSON.parse(raw) as unknown;
|
|
if (!Array.isArray(parsed)) return;
|
|
for (const n of parsed) {
|
|
const id = Number(n);
|
|
if (id > 0) strategyMissingIds.add(id);
|
|
}
|
|
} catch {
|
|
try { sessionStorage.removeItem(STORAGE_KEY); } catch { /* ok */ }
|
|
}
|
|
}
|
|
|
|
export function isStrategyMissingOnServer(strategyId: number): boolean {
|
|
return strategyId > 0 && strategyMissingIds.has(strategyId);
|
|
}
|
|
|
|
export function markStrategyMissingOnServer(strategyId: number): void {
|
|
if (strategyId <= 0) return;
|
|
strategyMissingIds.add(strategyId);
|
|
persistStrategyMissingCache();
|
|
}
|
|
|
|
export function unmarkStrategyMissingOnServer(strategyId: number): void {
|
|
if (strategyId <= 0) return;
|
|
if (strategyMissingIds.delete(strategyId)) persistStrategyMissingCache();
|
|
}
|
|
|
|
/** 전략 목록에 다시 나타난 ID 는 missing 에서 제거 */
|
|
export function reconcileStrategyMissingWithValidIds(validIds: Iterable<number>): void {
|
|
const valid = new Set(validIds);
|
|
let changed = false;
|
|
for (const id of strategyMissingIds) {
|
|
if (valid.has(id)) {
|
|
strategyMissingIds.delete(id);
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) persistStrategyMissingCache();
|
|
}
|
|
|
|
export function markStrategyMissingFromPath(pathOnly: string): void {
|
|
const m = pathOnly.match(/^\/strategies\/(\d+)(?:\/|$)/);
|
|
if (m) markStrategyMissingOnServer(Number(m[1]));
|
|
}
|
|
|
|
/** 목록에 없는 참조 ID를 missing 으로 기록 — 삭제된 전략 404 반복 방지 */
|
|
export function markStrategyIdsMissingUnlessValid(
|
|
validIds: Iterable<number>,
|
|
referencedIds: Iterable<number | null | undefined>,
|
|
): void {
|
|
const valid = new Set(
|
|
[...validIds].map(id => Math.trunc(id)).filter(id => id > 0),
|
|
);
|
|
for (const raw of referencedIds) {
|
|
if (raw == null) continue;
|
|
const id = Math.trunc(raw);
|
|
if (id > 0 && !valid.has(id)) markStrategyMissingOnServer(id);
|
|
}
|
|
}
|
|
|
|
hydrateStrategyMissingCache();
|