/* 702-3 B09 조작 중 서버 셈 — 진짜 `B09_Estimation_UI_Live.ts` 를 트랜스파일해 가짜 fetch 위에서 돌림 · * 차례 번호 · 옛 요청 끊기 · 같은 지문 다시 안 보냄 · 기다리는 줄(옛 산근 안 씀 · 「셈 중」) · 못 받음 = 한 번만. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); const toasts = []; function load(rel, stubs) { const src = fs.readFileSync(path.join(ROOT, rel), "utf8"); const js = ts.transpileModule(src, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const mod = { exports: {} }; new Function("exports", "module", "require", js)(mod.exports, mod, (id) => stubs[id] ?? {}); return mod.exports; } const live = load("B09_Estimation/B09_Estimation_UI_Live.ts", { "@config/config_frontend": { API_BASE_URL: "/api" }, "@ui/ui_template_elements": { showToast: (text, kind) => toasts.push(kind) }, }); // 가짜 fetch — 보낸 차례대로 쥐고 있다가 손으로 답함 · 끊김 = AbortError const pending = []; global.fetch = (url, init) => new Promise((resolve, reject) => { const one = { url, body: JSON.parse(init.body), resolve, reject, aborted: false }; init.signal.addEventListener("abort", () => { one.aborted = true; reject(Object.assign(new Error("aborted"), { name: "AbortError" })); }); pending.push(one); }); const answer = (one, ok = true) => one.resolve({ ok, status: ok ? 200 : 500, json: async () => (ok ? { tag: one.body.user.tag } : {}), }); const flush = async () => { for (let k = 0; k < 8; k++) await new Promise((r) => setTimeout(r, 0)); }; const logic = (given) => ({ bill: { rows: [{ key: "hand:a", ref: { tab: "logic", code: "GF1", given } }, { key: "b" }] }, }); (async () => { const out = {}; const settled = []; const calc = live.createLiveCalc("P1", (next, sent) => settled.push([next && next.tag, sent.tag]), ); const base = { user: logic({ 높이: 3 }), sheets: { sg_hand: { "hand:a": "SG:old" } } }; // 기다리는 줄 = 서버 기준과 다른 로직 연결만 const u1 = { ...logic({ 높이: 4 }), tag: 1 }; const wait = live.waitingKeys(base, u1); out.wait = [...wait]; out.same = [...live.waitingKeys(base, base.user)]; out.strip = live.withoutWaiting(base, wait).sheets.sg_hand; const sheets = { bill: { rows: [ { key: "hand:a", sum: null }, { key: "b", sum: null }, ], }, }; live.markWaiting(sheets, wait); out.mark = sheets.bill.rows.map((r) => r.sum); // 차례 — 첫 요청 가는 중 같은 지문 = 안 보냄 · 바뀐 지문 = 옛 것 끊고 새로 calc.kick(wait, u1); calc.kick(wait, u1); out.sentAfterSame = pending.length; const u2 = { ...logic({ 높이: 5 }), tag: 2 }; calc.kick(live.waitingKeys(base, u2), u2); await flush(); out.firstAborted = pending[0].aborted; out.url = pending[1].url; answer(pending[1]); await flush(); out.settled = settled.slice(); out.busyAfter = calc.busy(); // 기다릴 줄 없음 = 가던 것 끊음 const u3 = { ...logic({ 높이: 6 }), tag: 3 }; calc.kick(live.waitingKeys(base, u3), u3); calc.kick(new Set(), base.user); await flush(); out.cancelled = [pending[2].aborted, calc.busy()]; // 못 받음 = 알림 한 번 · 같은 지문 다시 안 보냄 const u4 = { ...logic({ 높이: 7 }), tag: 4 }; calc.kick(live.waitingKeys(base, u4), u4); answer(pending[3], false); await flush(); calc.kick(live.waitingKeys(base, u4), u4); out.failed = [toasts, settled[settled.length - 1], pending.length]; console.log(JSON.stringify(out)); })().catch((e) => { console.error(e && e.stack ? e.stack : e); process.exit(1); });