/* * 상태 축 고르기 — **순수**. "요청한 축만 남긴다." * * ── 왜 있나 (2026-08-05) ──────────────────────────────────────────────────── * 지도는 구독으로 "바뀌었다" 신호를 받고 상태를 다시 읽는다. 그 신호는 의도적으로 가볍고(`{kind, * revision}`) 리프레시도 250ms 로 합쳐진다 — 거기까지는 설계대로다. 문제는 **리프레시가 통째로** * 라는 것이다: 실 저널로 재 보니 트윈 하나가 최대 710KB 이고, 같은 공간에 셋이면 한 번에 약 2MB 다. * * 그런데 지도가 실제로 쓰는 것은 `locations`·`attentions`·`nowTime` **셋뿐**이다(코드 확인). 물품 * 2,278건·작업·오더를 받아 놓고 쓰지 않는다. 축을 골라 받으면 트윈에 따라 1.7~15배 줄어든다 * (물품이 많은 트윈은 15배, 신호가 많은 트윈은 2배 — 신호가 큰 쪽은 그것이 다음 과제다). * * ── 화면 이름을 API 에 넣지 않는다 ────────────────────────────────────────── * `twinMapState` 같은 화면 전용 질의를 만들지 않는다. 호출부가 **필요한 축을 말하고** 서버가 자른다 — * 새 화면이 생길 때마다 질의가 늘지 않고, 어휘도 화면 이름이 아니라 상태의 축이다(무방언). * * 모르는 축 이름은 **알리지 않고 버리지 않고 무시하되 그 사실을 돌려준다** — 오타 하나로 화면이 빈 * 채로 뜨는 것이 가장 나쁘다. */ /** * 상태가 들고 있는 축 — 이 목록 밖의 이름은 고를 수 없다. * * `energy` 는 에너지 트윈만 채운다(계량 지점·수요 구간·피크). `ALWAYS` 에 두지 않는다: 마감 구간을 * 하루치 들고 있어 작지 않고, 그것이 필요한 화면이 스스로 이름을 말하는 편이 맞다. */ export const STATE_AXES = ['locations', 'items', 'equipment', 'persons', 'assets', 'tasks', 'orders', 'attentions', 'acked', 'energy'] as const export type StateAxis = (typeof STATE_AXES)[number] /** 축과 무관하게 늘 남는 것 — 이것이 없으면 무엇을 받았는지 알 수 없다. */ const ALWAYS = ['revision', 'nowTime', 'simClockMs', 'corrections', 'unhandled'] as const export interface PickedAxes { /** 고른 축만 남은 상태. `axes` 가 비었으면 원본 그대로(자르지 않는다). */ state: any /** 상태 축이 아닌 이름 — 호출부가 오타를 알 수 있게 돌려준다. */ unknown: string[] } /** * 요청한 축만 남긴다. * * `axes` 가 비어 있으면 **자르지 않는다** — 기본값이 "전부" 여야 기존 호출부가 그대로 동작한다 * (자르는 쪽이 기본이면 축을 말하지 않은 화면이 알리지 않고 비어 버린다). */ export function pickAxes(state: any, axes: readonly string[] | undefined | null): PickedAxes { if (!state || typeof state !== 'object') return { state, unknown: [] } if (!axes?.length) return { state, unknown: [] } const known = new Set(STATE_AXES as readonly string[]) const wanted = axes.filter(a => known.has(a)) const unknown = axes.filter(a => !known.has(a)) /* 아는 축이 하나도 없으면 자르지 않는다 — 전부 오타인 경우에 빈 화면을 만들지 않는다. */ if (!wanted.length) return { state, unknown } const out: any = {} for (const k of ALWAYS) if (k in state) out[k] = state[k] for (const a of wanted) if (a in state) out[a] = state[a] return { state: out, unknown } }