pub const THIN_CLIENT: &str = "// The thin client: `fold(apply_patch, initial_html, patch_stream)`.\n//\n// This file is compiler residue. Nothing here is application-specific \u{2014} no todo, no command\n// names, no view logic \u{2014} which is the point: \"the JavaScript never appears in the source at all\"\n// (docs/00-original-idea.md). It applies patches, captures declarative handlers, follows links,\n// and resumes a subscription by (subscription, seq). That is the whole of Mode A on the browser\n// side.\n//\n// The patch interpreter, the socket, the router and the id source are in `beck-patch.js`, because\n// Mode B needs the same four and produces the same patch ops \u{2014} it just produces them in the\n// browser instead of receiving them (docs/93).\n(() => {\n const root = document.getElementById(\"b-root\");\n if (!root) return;\n\n // `state` is shared with the socket rather than copied into it: `state.seq` is what a *reconnect*\n // resumes from, so it has to be the position of the last frame applied and not the position the\n // document was painted at. The two are the same only until the first patch arrives.\n const state = {\n sub: beck.uuid7(),\n actor: root.dataset.bActor || \"dev\",\n // The seq the server-rendered HTML reflects. The socket resumes from here, so first paint and\n // first patch cannot disagree, and hydration costs zero DOM work.\n seq: Number(root.dataset.bSeq) || 0,\n };\n\n // Commands proposed and not yet answered. In Mode A this is the whole of \"pending\": the server\n // holds the state, so a client has nothing to show for a command until the patch comes back, and\n // what it can say is *how many it is waiting on* \u{2014} which is what a devtools panel means by\n // pending and what a page could show as a spinner.\n const pending = new Map();\n\n const send = beck.connect(state, (msg) => {\n if (msg.t === \"p\") {\n beck.apply(root, msg.o);\n state.seq = msg.q;\n } else if (msg.t === \"u\" || msg.t === \"w\") {\n // \"current as of q, nothing changed\" \u{2014} keeps `seq` moving so a later reconnect does not ask\n // the server to replay a gap that turns out to be empty.\n state.seq = msg.q;\n // A welcome means the subscription exists, which is the whole of readiness in Mode A: the\n // handlers were installed synchronously and the page was rendered by the server.\n if (msg.t === \"w\") beck.ready(root, \"a\");\n } else if (msg.t === \"a\" || msg.t === \"n\") {\n pending.delete(msg.id);\n beck.stats.pending = pending.size;\n if (msg.t === \"n\") beck.announce(root, \"beck:rejected\", msg);\n }\n });\n\n beck.capture((command) => {\n const id = beck.uuid7();\n pending.set(id, command);\n beck.stats.pending = pending.size;\n send({ t: \"c\", id, command });\n });\n\n // A link is a route, and a route is `session.path`. In Mode A the server re-renders for the new\n // session and answers with a patch, so a navigation costs exactly what any other change costs:\n // the difference between two pages.\n beck.route((path) => {\n beck.stats.navigations += 1;\n send({ t: \"g\", path });\n });\n\n beck.inspect.describe = () => ({\n mode: \"A\",\n seq: state.seq,\n actor: state.actor,\n path: beck.here(),\n pending: Array.from(pending.keys()),\n });\n\n beck.devtools();\n})();\n";Expand description
Mode A: apply the patches the server sends, post commands back up the socket.