pub const DEVTOOLS_CLIENT: &str = "// The devtools panel: the signal graph, the patch traffic and the pending state.\n//\n// docs/08 \u{a7}8.6 asks for \"a devtools extension showing signal graph, patch traffic and pending\n// state\". This is the three things and not the extension, and the difference is deliberate: an\n// extension is a second artefact with its own distribution, its own permissions and its own release\n// pipeline, and nothing in this repository could run one \u{2014} the browser gate here drives a page.\n// A panel the server serves is testable by the same harness that tests the client, and it is the\n// same residue: no framework, no CDN, nothing the network policy this program derives would refuse.\n//\n// It is loaded only when it is asked for (`beck.devtools()` in each mode\'s shim), so a page that\n// does not want it pays nothing, and it is appended to `body` rather than into `#b-root` \u{2014} a patch\n// path is a child index from the frame root, and a panel inside it would be counted.\n(() => {\n if (window.__beckDevtools) return;\n window.__beckDevtools = true;\n\n const root = document.getElementById(\"b-root\");\n if (!root) return;\n\n const panel = document.createElement(\"aside\");\n panel.id = \"beck-devtools\";\n panel.setAttribute(\"aria-label\", \"Beck devtools\");\n const style = document.createElement(\"style\");\n style.textContent = `\n #beck-devtools {\n position: fixed; right: 0; bottom: 0; z-index: 2147483647; width: min(26rem, 100vw);\n max-height: 70vh; overflow: auto; box-sizing: border-box;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n background: #0f1115; color: #d7dce5; border-top: 1px solid #262c36;\n border-left: 1px solid #262c36;\n }\n #beck-devtools header {\n display: flex; gap: .5rem; align-items: baseline; justify-content: space-between;\n padding: .4rem .6rem; border-bottom: 1px solid #262c36; position: sticky; top: 0;\n background: #161a21;\n }\n #beck-devtools h1 { margin: 0; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }\n #beck-devtools h2 {\n margin: .6rem 0 .2rem; font-size: 10px; letter-spacing: .12em; text-transform: uppercase;\n color: #8b95a5;\n }\n #beck-devtools section { padding: 0 .6rem .6rem; }\n #beck-devtools table { border-collapse: collapse; width: 100%; }\n #beck-devtools td { padding: 1px 6px 1px 0; vertical-align: top; }\n #beck-devtools td.k { color: #8b95a5; white-space: nowrap; }\n #beck-devtools td.n { text-align: right; font-variant-numeric: tabular-nums; }\n #beck-devtools button {\n font: inherit; background: none; color: #8b95a5; border: 1px solid #262c36;\n border-radius: 3px; cursor: pointer; padding: 0 .4rem;\n }\n #beck-devtools .per-session { color: #6aa9ff; }\n #beck-devtools .recompute { color: #f0a35e; }\n #beck-devtools .incremental { color: #7fd18a; }\n `;\n\n const head = document.createElement(\"header\");\n const title = document.createElement(\"h1\");\n title.textContent = \"beck\";\n const close = document.createElement(\"button\");\n close.textContent = \"close\";\n close.addEventListener(\"click\", () => {\n try {\n localStorage.setItem(\"beck:devtools\", \"\");\n } catch (e) {\n // A context with no storage. Closing still works; it just will not be remembered.\n }\n panel.remove();\n });\n head.append(title, close);\n\n const traffic = document.createElement(\"section\");\n const client = document.createElement(\"section\");\n const graph = document.createElement(\"section\");\n panel.append(style, head, traffic, client, graph);\n document.body.appendChild(panel);\n\n const rows = (into, heading, pairs) => {\n into.textContent = \"\";\n const h = document.createElement(\"h2\");\n h.textContent = heading;\n const table = document.createElement(\"table\");\n for (const [k, v, cls] of pairs) {\n const tr = document.createElement(\"tr\");\n const kd = document.createElement(\"td\");\n kd.className = \"k\";\n kd.textContent = k;\n const vd = document.createElement(\"td\");\n vd.className = cls || \"n\";\n vd.textContent = v;\n tr.append(kd, vd);\n table.append(tr);\n }\n into.append(h, table);\n };\n\n // ---- patch traffic and pending state --------------------------------------------------------\n //\n // Both are read from what the residue already counts. Nothing here derives a second account of\n // what the client is doing \u{2014} a panel that computed its own could be the only wrong thing on the\n // screen, and it is the one thing on the screen a developer would believe.\n const draw = () => {\n const s = beck.stats;\n rows(traffic, \"patch traffic\", [\n [\"socket\", s.connected ? \"open\" : \"reconnecting\", \"k\"],\n [\"frames applied\", s.frames],\n [\"ops applied\", s.ops],\n [\"bytes in\", s.bytes_in],\n [\"bytes out\", s.bytes_out],\n [\"frames sent\", s.sent],\n [\"navigations\", s.navigations],\n ]);\n\n let d = {};\n try {\n d = beck.inspect.describe();\n } catch (e) {\n d = { mode: \"?\" };\n }\n const pending = d.pending || [];\n rows(client, \"client\", [\n [\"mode\", d.mode || \"?\", \"k\"],\n [\"route\", d.path || \"\", \"k\"],\n [\"actor\", d.actor || \"\", \"k\"],\n [\"seq\", d.seq === undefined ? \"\" : d.seq],\n [\"pending\", pending.length],\n ...pending.map((id) => [\"\", id.slice(0, 8), \"k\"]),\n ]);\n };\n\n document.addEventListener(\"beck:traffic\", draw);\n document.addEventListener(\"beck:ready\", draw);\n document.addEventListener(\"beck:rejected\", draw);\n // A tick as well as the events, because two of the numbers move on *sending* \u{2014} which is not a\n // patch and has no frame to hang an event on.\n setInterval(draw, 500);\n draw();\n\n // ---- the signal graph -----------------------------------------------------------------------\n //\n // The one thing the browser cannot know: a Mode A client is never sent a program. It comes from\n // `/beck-signals.json`, which is the running program\'s own graph and the same verdicts\n // `beck explain incremental` prints.\n fetch(\"/beck-signals.json\")\n .then((r) => r.json())\n .then((g) => {\n const pairs = [\n [\"program\", g.program, \"k\"],\n [\"page\", g.page, \"k\"],\n [\"mode\", g.mode, \"k\"],\n [\"reads of session\", g.reads, \"k\"],\n [\"operators\", g.plan.operators],\n [\"maintained\", g.plan.maintained],\n [\"recomputed\", g.plan.recomputed],\n [\"per session\", g.plan.per_session],\n ];\n rows(graph, \"signal graph\", pairs);\n const table = document.createElement(\"table\");\n for (const n of g.nodes) {\n const tr = document.createElement(\"tr\");\n const name = document.createElement(\"td\");\n name.className = \"k\";\n name.textContent = n.label;\n const what = document.createElement(\"td\");\n what.className = n.verdict ? n.verdict.replace(\" \", \"-\") : \"k\";\n what.textContent = n.op + (n.verdict ? \" \u{b7} \" + n.verdict : \"\") + \" \u{b7} \" + n.tier;\n tr.append(name, what);\n table.append(tr);\n }\n graph.append(table);\n })\n .catch((e) => rows(graph, \"signal graph\", [[\"unavailable\", String(e), \"k\"]]));\n})();\n";Expand description
The devtools panel: the signal graph, the patch traffic and the pending commands.
Loaded only when it is asked for (?devtools, or the switch it leaves in localStorage), which
is what keeps it out of the residue every page pays for. It reads the same three things the
runtime already publishes and computes nothing of its own — a panel that derived a second
account of the client’s state could be the only wrong one on the screen.