The site is a build, published at thankywal.github.io/muxel - #39
Merged
Conversation
The console, the product page and the guide were served by an express process on a VPS. Everything that process did which needed a process was rendering the README into the guide, and that can happen once, at build time. The machine it ran on was the last thing in Muxel's own path that an owner had to trust for a page which, by design, talks to nothing but their own Worker. scripts/build-site.mjs writes the whole site as files: the product page at the root, the console at /console/, and the guide in five languages plus the two documents the READMEs link to. The hostname the old process used to pick between the product page and the console becomes a path, which is free because the console has no router, no history and no hash — nothing in it reads the URL. The base path is the one thing that differs between hosts: a project site lives under /muxel/ and a custom domain lives at /. The workflow reads it from GitHub rather than deciding it here, so pointing a domain at this later changes nothing in the repository. Every root-absolute URL the site uses is moved onto that base on the way out, and what may be moved is the set of names the build actually emits — a link to something that is not there cannot be quietly repointed, and one nobody taught the build about fails it. server.mjs now serves what the build wrote instead of building on demand, so the copy it hands a browser and the copy Pages hands a browser are the same bytes rather than two renderings that can drift. The build's own test found one bug worth naming: an open bracket in the URL pattern ate `text.replace(/docs/g, x)`, because a regular expression in JavaScript starts exactly the way a path does. Also: .dev.vars.example still offered live web search and reading a document as data, which were removed at revision 20. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoYEEHLJc4CifTLHjKpcDF
app.muxel.site was typed out in seventeen places — the Worker's own first screen, four languages of Telegram strings, the assistant's description of itself, the command line, two deploy scripts, the console's own HTML — and in five READMEs besides. The domain is going to another project, so all of it had to move, which is exactly the change seventeen copies of a string make expensive. CONSOLE_HOME lives in core, because the programs that name it cannot all import each other: the Worker puts it on its first screen, the command line prints it after a deploy, and the console links back to it. The translations take it as a variable rather than four copies of a sentence. The files that cannot import anything — the READMEs, the deploy scripts, the console's HTML — are held to the same value by a test, because a document that sends an owner somewhere empty is worse than one that says nothing at all. The console becomes the site rather than a page of it. It used to be chosen by hostname, and the hostname that chose it is the one leaving, so https://thankywal.github.io/muxel/ is the console and the product page moves to /product/, where the console's footer and an unknown path both still reach it. The build learned about the top of the site on the way: a link to it has no path segment to be recognised by, and a lone slash is far too common in code to rewrite on sight, so only an attribute counts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoYEEHLJc4CifTLHjKpcDF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The console, the product page and the guide were served by an express process on a VPS, and the address every document sent a new owner to was
app.muxel.site. That domain is going to another project, so both had to move.The site is files
scripts/build-site.mjswrites the whole site, and GitHub Pages serves it:The console is the site, not a page of it. It used to be chosen by hostname —
app.muxel.sitewas the console andmuxel.sitewas the product page — and the hostname that chose it is the one leaving. That is free: the console has no router, no history and no hash. Nothing in it reads the URL.One record for the address
app.muxel.sitewas typed out in seventeen places — the Worker's own first screen, four languages of Telegram strings, the assistant's description of itself, the command line, two deploy scripts, the console's HTML — and in five READMEs besides.CONSOLE_HOMEnow lives in@muxel/core, because the programs that name it cannot all import each other. The translations take it as a{console}variable rather than four copies of a sentence. The files that cannot import anything — the READMEs, the deploy scripts, the console's HTML — are held to the same value by a test.The base path
A project site lives under
/muxel/, a custom domain lives at/. The workflow reads that from GitHub (configure-pages→base_path) rather than deciding it here. Every root-absolute URL is moved onto that base on the way out, and what may be moved is the set of names the build actually emits — a link to something that is not there cannot be quietly repointed, and one nobody taught the build about fails it.Two bugs the new test found
text.replace(/docs/g, x)— a regular expression in JavaScript starts exactly the way a path does. It was one root name away from corruptingapp.js.href="/"was left pointing atthankywal.github.io/rather than at the site. A lone slash is everysplitand everyjoin, so only an attribute counts.One site, two places it can be put
server.mjsnow serves what the build wrote instead of building on demand, so the copy it hands a browser and the copy Pages hands a browser are the same bytes. It answers exactly as Pages does:/docs→ 301 →/docs/, unknown paths →404.html.Verified
server.mjsagainst the root build:/,/product/,/docs,/docs/,/docs/my/,/app.js,/notice.jsoncorrect;/nope→ 404Also
.dev.vars.examplestill offered "live web search, reading a document as data" — both removed at revision 20.Merging this turns GitHub Pages on (
enablement: true) and publishes the site athttps://thankywal.github.io/muxel/. Nothing is removed from the VPS by this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01LoYEEHLJc4CifTLHjKpcDF