/* PLAN 511-A 브라우저 길 헬퍼 — `design_calc_server.ts` 를 그 자리에서 트랜스파일 · 판(`design_calc_sites`)과 * fetch 를 가짜로 끼워 판 따라 길 고름 · 잠잠 · 끊음 · 대조 · 기록을 잼. 결과 = 표준출력 JSON 한 벌. * 짝 = `test_511_a_calc_browser.py`. */ const path = require("path"); const { makeLoader } = require("./helper_ts_stub_loader.cjs"); const ROOT = path.join(__dirname, "..", ".."); const board = {}; const fetched = []; let answer = (body) => ({ [body.run[0]]: body.inputs.args?.[body.run[0]]?.[0] ?? null }); globalThis.fetch = async (url, init) => { const body = JSON.parse(init.body); fetched.push({ url, run: body.run, at: Date.now() }); if (init.signal?.aborted) throw new DOMException("끊김", "AbortError"); return { ok: true, status: 200, json: async () => ({ results: answer(body), ms: 1, wall_ms: 2 }), }; }; const plain = (value) => JSON.parse(JSON.stringify(value)); const { loadTs } = makeLoader({ root: ROOT, stubs: { design_calc_sites: { calcOnServerNow: (key) => board[key] === "server", calcProjectId: () => "p1", }, design_calc_node_trial: { plain }, }, }); const mod = loadTs(path.join(ROOT, "A00_Common", "design", "design_calc_server.ts")); const tick = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const echo = (value) => value; (async () => { const out = {}; // 1 판 both — 브라우저 값 · 서버 부름 0 · 브라우저 ms 기록 out.both = mod.calcChecked("quantity", "cross.fit", echo, [5]); await tick(500); out.bothFetched = fetched.length; out.local = globalThis.__aisloCalcServer.local["cross.fit"].length; // 2 판 server — 브라우저 값 바로 · 잠잠 뒤 한 번(빠른 둘째 부름이 첫째를 끊음) · 같음 board.quantity = "server"; let applied = 0; mod.calcChecked("quantity", "cross.fit", echo, [6], { apply: () => (applied += 1) }); out.server = mod.calcChecked("quantity", "cross.fit", echo, [7], { apply: () => (applied += 1) }); out.beforeQuiet = fetched.length; await tick(500); out.afterQuiet = fetched.length; const calls = globalThis.__aisloCalcServer.calls; out.same = calls[calls.length - 1].same; out.applied = applied; // 3 서버 값이 다름 — apply(서버 값) answer = () => ({ "cross.fit": 99 }); let got = null; mod.calcChecked("quantity", "cross.fit", echo, [8], { apply: (v) => (got = v) }); await tick(500); out.diffApplied = got; out.diffSame = calls[calls.length - 1].same; // 4 그리기 자리 — 처음 undefined · 답 오면 redraw · 같은 입력 = fresh answer = (body) => ({ "masshaul.series": ["s", body.inputs.args["masshaul.series"][0]] }); let redraws = 0; const first = mod.calcFromServer("quantity", "masshaul.series", [1], () => (redraws += 1)); await tick(500); const second = mod.calcFromServer("quantity", "masshaul.series", [1], () => (redraws += 1)); const third = mod.calcFromServer("quantity", "masshaul.series", [2], () => (redraws += 1)); out.draw = { first, second, third, redraws }; await tick(500); // 5 비동기 자리 — outer 끊음 = undefined · 부름 0 const before = fetched.length; const outer = new AbortController(); const pending = mod.calcOnServerOnly("quantity", "slot", mod.areasRequest([]), outer.signal); outer.abort(); out.aborted = (await pending) === undefined && fetched.length === before; // 6 왕복 흉내 — delayMs 만큼 늦음 globalThis.__aisloCalcServer.delayMs = 80; answer = () => ({ "structure.layouts": { areas: [1] } }); const t0 = Date.now(); out.onlyValue = await mod.calcOnServerOnly("quantity", "slot2", mod.areasRequest([])); out.delayed = Date.now() - t0 >= 400 + 80; out.roundMs = calls[calls.length - 1].roundMs; out.url = fetched[fetched.length - 1].url; process.stdout.write(JSON.stringify(out)); })();