chore(catalog): add connect-stack dev helper#4833
Conversation
Adds `npm run connect-stack` which:
1. Prompts for (or accepts as arg) a live catalog URL,
defaulting to the current registryUrl with "-registry"
stripped.
2. Fetches <url>/config.js into static-dev/config.js so the
local dev server points at the same stack.
3. Writes static-dev/bookmarks.html with two bookmarklets
(Copy / Paste Quilt Auth) that shuttle localStorage USER
and TOKENS between the live catalog and localhost:3000 —
no manual DevTools, no sharing tokens.
4. If port 3000 is already in use, prints instructions and
exits; otherwise launches `npm start`, tails webpack
output to /tmp/connect-stack.log, and waits for
"compiled successfully" before printing login steps.
Replaces the undocumented external "connect-stack.js" tool
referenced by the generated comment in static-dev/config.js.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4833 +/- ##
=======================================
Coverage 45.62% 45.62%
=======================================
Files 831 831
Lines 33597 33597
Branches 5727 5727
=======================================
Hits 15328 15328
Misses 16264 16264
Partials 2005 2005
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
|
||
| async function fetchConfig(url) { | ||
| const configUrl = `${url}/config.js` | ||
| console.log(`Fetching ${configUrl}`) |
There was a problem hiding this comment.
fetch() has no timeout, so if the target server is slow or hangs the script will wait indefinitely. Adding an AbortController with a reasonable timeout (e.g. 15 s) gives the user a clear error instead of a stalled prompt.
| console.log(`Fetching ${configUrl}`) | |
| const controller = new AbortController() | |
| const timeout = setTimeout(() => controller.abort(), 15000) | |
| const res = await fetch(configUrl, { signal: controller.signal }).finally(() => clearTimeout(timeout)) |
| const BOOKMARKS_PATH = path.join(CATALOG_DIR, 'static-dev/bookmarks.html') | ||
| const LOG_PATH = path.join(os.tmpdir(), 'connect-stack.log') | ||
| const NODE20_BIN = '/opt/homebrew/opt/node@20/bin' | ||
| const PORT = 3000 |
There was a problem hiding this comment.
NODE20_BIN is prepended to PATH unconditionally. On Linux or macOS without Homebrew the path simply doesn't exist and is silently ignored, so the script falls back to whatever node/npm is already on PATH — which may be the wrong version (or not found at all). Acknowledged as a known limitation in the PR notes, but worth a runtime guard so contributors on other platforms see a clear message rather than a cryptic npm start failure.
A lightweight improvement would be to only prepend the path when it exists:
| const PORT = 3000 | |
| const NODE20_BIN = '/opt/homebrew/opt/node@20/bin' |
// Inside startDevServer, replace the env line:
const extraBin = fs.existsSync(NODE20_BIN) ? `${NODE20_BIN}:` : ''
const env = { ...process.env, PATH: `${extraBin}${process.env.PATH}` }Adds preinstall script that exits 1 with a clear message when `npm install`/`npm ci` runs under a non-20 node major — prevents silently regenerating the lock file under npm 11 and breaking CI. Complements the existing `engines.node` field (which npm only warns about, never enforces). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fiskus
left a comment
There was a problem hiding this comment.
I see two features here:
- copy
config.jsfromstack/config.jstostatic-dev/config.js:
- I think this operation is too simple to automate:
wget https://stack/config.js ./static-dev/config.js. I suggest to change README.md instead of making a script. - But if we automate, can we clear
SENTRY_SDNand make a backup of the current config at./static-dev/config.js.bak - If we automate, maybe, it is clearer to fetch JSON - stack/config.json, validate and adjust the properties, and then convert to config.js
- auto-login:
- I'm not sure if I fully understand this. Does the script steal credentials from original website and paste them to localhost?
- If so, that sounds useful in general, but the implementation is too hacky and too specific for my taste
And one non-feature: start the dev server. I'd suggest keeping this simple, and making it only to connect stack.
| const dflt = inferDefaultUrl() | ||
| const q = dflt | ||
| ? `Live catalog URL [${dflt}]: ` | ||
| : 'Live catalog URL (e.g. https://nightly.quilttest.com): ' |
There was a problem hiding this comment.
This code is opensourced, so, URL should be public
| : 'Live catalog URL (e.g. https://nightly.quilttest.com): ' | |
| : 'Live catalog URL (e.g. https://open.quiltdata.com): ' |
| } | ||
|
|
||
| function inferDefaultUrl() { | ||
| // Derive the catalog URL from registryUrl in the existing config.js, dropping "-registry". |
There was a problem hiding this comment.
So, this will rewrite the config with the same or updated JSON? I'd remove the default, so the action would be conscious.
Summary
Adds catalog/internals/scripts/connect-stack.js +
npm run connect-stackthat configures a local dev server against a live stack and provides two bookmarklets to shuttle auth state from the live site to localhost without manual DevTools.What it does
Why
The existing catalog/README.md dev-setup step ("copy `config.js.example`, edit it, `npm start`") assumes you already have a backend to hand-author the config for. And the comment `Auto-generated by connect-stack.js` at the top of catalog/static-dev/config.js referenced a tool that wasn't in the repo. This PR fills that gap with something discoverable (`npm run connect-stack`) and self-documenting.
The auth bookmarklet approach replaces ad-hoc workflows like "manually copy localStorage keys via DevTools" — which works but is fragile and has asked contributors to share JWTs via chat in the past.
Test plan
Notes
Related PRs
This PR was extracted from the logo-upload feature branch so the dev-tooling change lands independently of the feature:
connect-stack🤖 Generated with Claude Code
Greptile Summary
This PR adds
catalog/internals/scripts/connect-stack.js— a Node.js dev-helper that fetches a live stack'sconfig.js, writes it tostatic-dev/config.js, generates abookmarks.htmlwith auth-shuttle bookmarklets, and spawnsnpm startif port 3000 is free. A correspondingnpm run connect-stackscript is wired up inpackage.json. No runtime product code is touched.Confidence Score: 5/5
Safe to merge — purely additive dev tooling with no impact on production code.
Both findings are P2 style/best-practice suggestions (no fetch timeout, macOS-only PATH prepend). The static-dev/ directory is confirmed to exist in the repo via its committed .gitignore, so the writeFileSync calls are safe on a fresh clone. No runtime product code is modified.
catalog/internals/scripts/connect-stack.js — minor hardening opportunities (fetch timeout, cross-platform PATH guard), but nothing blocking.
Important Files Changed
npm start; two minor P2 issues (no fetch timeout, macOS-only PATH prepend)connect-stacknpm script entry; one-line change, no issuesSequence Diagram
sequenceDiagram participant Dev as Developer participant Script as connect-stack.js participant LiveSite as Live Catalog (HTTPS) participant FS as local filesystem participant DevServer as npm start (localhost:3000) participant Browser as Developer's Browser Dev->>Script: npm run connect-stack [url] Script->>Script: inferDefaultUrl() from static-dev/config.js Script->>Dev: prompt for live catalog URL (if not provided) Dev->>Script: URL confirmed Script->>LiveSite: GET /config.js LiveSite-->>Script: config.js body Script->>FS: write static-dev/config.js Script->>FS: write static-dev/bookmarks.html (copy + paste bookmarklets) Script->>Script: portInUse(3000)? alt Port 3000 free Script->>DevServer: spawn npm start DevServer-->>Script: stdout/stderr lines Script->>Script: watch for "compiled successfully" Script->>Dev: print login instructions else Port 3000 in use Script->>Dev: print instructions, skip npm start end Dev->>Browser: open localhost:3000/bookmarks.html Dev->>Browser: drag bookmarklets to bar Dev->>LiveSite: log in, click "Copy Quilt Auth" Browser->>Browser: copy USER+TOKENS JSON to clipboard Dev->>DevServer: visit localhost:3000, click "Paste Quilt Auth" Browser->>DevServer: write USER+TOKENS to localStorage, reloadReviews (1): Last reviewed commit: "chore(catalog): add connect-stack dev he..." | Re-trigger Greptile