Repository navigation
fix(server): serve the studio shell from an install path holding a dot-directory - #173
Merged
Merged
Conversation
…t-directory sendShell answered the unbranded shell with res.sendFile(<absolute path to studio/index.html>) and no root. Express 5's send applies its default dotfiles: 'ignore' to every segment of an absolute path, so wherever the install path holds a dot-directory (an nvm global install under ~/.nvm/…/lib/node_modules/observogram, ~/.local/…, a .claude/worktrees checkout) GET /, GET /index.html and every SPA path answered 404 NotFoundError; server/test-smoke.mjs failed at its GET / there. The shell is now named relative to root: STUDIO_DIR, as the static mount names its files, so send reads only 'index.html' for a dot segment. The bytes and headers (ETag, Last-Modified, Cache-Control, Accept-Ranges) are unchanged; the DEFAULT test pins them. No other res.sendFile or send in server/ takes an absolute path: both express.static mounts pass a root. DOT PATH in server/test-brand-shell.mjs boots a child from a link under <tmp>/.install/ with --preserve-symlinks, so it runs from a dot path on any checkout, and fails (404) at the parent commit. serve() takes `index`, the server module to boot by path. Suite total 1486 -> 1487. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What
sendShell(server/index.mjs) answered the unbranded studio shell withres.sendFile(SHELL_FILE), whereSHELL_FILEis the absolute path ofstudio/index.html, and passed noroot. Express 5'ssend(1.2.1) then applies its defaultdotfiles: 'ignore'to every segment of the absolute path (containsDotFile(parts)→ 404). So wherever the install path contains a dot-directory,GET /,GET /index.htmland every SPA-fallback path answered 404 NotFoundError:~/.nvm/versions/node/…/lib/node_modules/observogram~/.local/….claude/worktrees/….server/test-smoke.mjsfails there at itsgetText(base, '/')withHTTP 404, andserver/test-brand-shell.mjsDEFAULT fails too.Fix
With a
root,sendchecks only the relative part (index.html) for dot segments, the same way theexpress.staticmounts name their files. The response is unchanged: same bytes and the sameETag,Last-Modified,Cache-Control: public, max-age=0andAccept-Ranges: bytes. The existing DEFAULT test pins this "byte for byte with the static file headers", and it still passes. The branded shell is held in memory and never went throughsend.Audit of other calls: this was the only
res.sendFileinserver/. Bothexpress.staticmounts (/liband the studio assets) already pass a root through serve-static. Nores.downloador directsend(file call exists. Every otherres.send(...)sends a body, not a file.Regression test
server/test-brand-shell.mjsDOT PATH:<tmp>/.install/observogram, a link to the checkout (a junction on Windows, which needs no privilege), with--preserve-symlinks, so the child'simport.meta.urlkeeps the link path andSTUDIO_DIRholds the dot segment on any checkout, including CI's dot-free one;studio/index.htmlbyte for byte with the static file headers, and that/app.cssand/lib/brand.mjsare served;unlinkSynctakes the link, never the checkout).I confirmed it fails with the old line (404) and passes with the fix.
serve()inserver/fixtures/serve-child.mjsgains anindexoption (the server module to boot, by path). DEFAULT and DOT PATH share the shell-file assertions.Docs
docs/CHANGELOG.md## Unreleasedand a newdocs/UPDATE_JOURNEY.mdfollow-up section both quote 1486 → 1487, whichtools/test-doc-test-totals.mjschains.Validation
All runs are from this
.claude/worktrees/…checkout, which is itself a dot path:npm run lint: 0 errors. The 153 warnings were there before this change.npm test: 1487 tests, 1441 pass, 0 fail, 46 skipped (the Playwright browser legs, as before).tools/libchange, so no vendor manifest or golden change.🤖 Generated with Claude Code