chore(deploy): config-as-code railway.json + per-service watch path docs#53
Merged
Conversation
…tterns Add a repo-root railway.json that captures the build (DOCKERFILE builder, Dockerfile path) and a deploy restart policy. The watchPatterns field is explicitly set to ["**/*"] so every commit to main triggers a redeploy of every service. Background: the 4 Railway services (@webjskit/website, /docs, /ui-website, @webjskit-examples/blog) all build from the same repo and the same Dockerfile, but each had its own dashboard-set watch-path filter scoped to its own subdir. A root-level change (e.g. Dockerfile, package.json, changelog/) did not trigger the services whose subdir was untouched, which is how PR #51 (a Dockerfile-only fix) reached only ui-website and left webjs.dev/changelog broken until #52. Note: Railway dashboard-set values take precedence over config-as-code. After this merges, clear "Watch Paths" in the dashboard for each of the 4 services (Service → Settings → Source → Watch Paths → clear the list, save), so railway.json takes over. Once that is done, future cross-service infra changes (Dockerfile, compose.yaml, root package.json, etc.) trigger redeploys for all four services automatically.
Per-service watch paths cannot be expressed in a single repo-root railway.json (the file applies to every service that points at it and there is no per-service override in the JSON shape). Drop the **/* pattern from the file and move the per-service tables into the PR description for paste-into-dashboard use. The remaining build + deploy fields stay because they really are shared by all four services.
vivek7405
added a commit
that referenced
this pull request
May 21, 2026
…ocs (#53) * chore(deploy): config-as-code railway.json with cross-service watchPatterns Add a repo-root railway.json that captures the build (DOCKERFILE builder, Dockerfile path) and a deploy restart policy. The watchPatterns field is explicitly set to ["**/*"] so every commit to main triggers a redeploy of every service. Background: the 4 Railway services (@webjskit/website, /docs, /ui-website, @webjskit-examples/blog) all build from the same repo and the same Dockerfile, but each had its own dashboard-set watch-path filter scoped to its own subdir. A root-level change (e.g. Dockerfile, package.json, changelog/) did not trigger the services whose subdir was untouched, which is how PR #51 (a Dockerfile-only fix) reached only ui-website and left webjs.dev/changelog broken until #52. Note: Railway dashboard-set values take precedence over config-as-code. After this merges, clear "Watch Paths" in the dashboard for each of the 4 services (Service → Settings → Source → Watch Paths → clear the list, save), so railway.json takes over. Once that is done, future cross-service infra changes (Dockerfile, compose.yaml, root package.json, etc.) trigger redeploys for all four services automatically. * chore(deploy): drop the global watchPatterns from railway.json Per-service watch paths cannot be expressed in a single repo-root railway.json (the file applies to every service that points at it and there is no per-service override in the JSON shape). Drop the **/* pattern from the file and move the per-service tables into the PR description for paste-into-dashboard use. The remaining build + deploy fields stay because they really are shared by all four services.
This was referenced May 22, 2026
vivek7405
added a commit
that referenced
this pull request
May 26, 2026
The static /public/* handler did `join(appDir, path)` without checking that the resolved absolute path stays under `appDir/public/`. Node's URL parser normalises raw `..` segments, but it does NOT decode percent-encoded characters. webjs then runs `decodeURIComponent` on the parsed pathname AFTER URL parsing. Combined, this lets a `/public%2F..%2Fsecret%2Fsecret.svg` URL survive URL parsing as `/public%2F..%2Fsecret%2Fsecret.svg`, decode to `/public/../secret/secret.svg`, match the `/public/` branch, and have `join` resolve to `appDir/secret/secret.svg` (outside public/). Fix: after computing `abs = join(appDir, p)`, verify `abs.startsWith(appDir + path.sep + 'public' + path.sep)`. Reject with 404 if not. Tests in /tmp covered raw `..`, `%2E%2E`, percent-encoded slash, double-encoded forms. Only the `%2F..%2F` (encoded slash) variant exploited the /public/ branch specifically; the others fall through to URL-parser normalisation and hit the user-source branch, which is a separate appDir-wide-exposure concern filed as task #53.
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.
Problem
The 4 Railway services in this repo each have a per-subdir watch path. Root-level changes (Dockerfile, root configs) only fire the service whose list happens to mention them. PR #51's Dockerfile fix reached
ui-websitebut not website/docs/blog, which is whywebjs.dev/changelogstayed broken even after the merge.Mapped what each runtime actually depends on (imports, not prose mentions):
websitedocsblog(examples/)ui-website(
ts-pluginis editor-only, no runtime use, so it's intentionally excluded. The docs site mentions@webjskit/uiin prose on the UI doc page but does not import it, so ui is not a runtime dep there.)Plus everyone is built from the same
Dockerfileand runswebjs start, so cli/core/server transitively land in every image.Fix
Two parts.
1.
railway.jsonat the repo rootAdds a shared, file-controlled record of the build (
builder: DOCKERFILE,dockerfilePath: Dockerfile) and the deploy restart policy.watchPatternsis not in this file because a single value at the repo root would apply identically to all four services and the whole point is to make each service trigger on a different set.2. Per-service watch paths (one-time dashboard cleanup)
For each service: open Settings → Source → Watch Paths, clear the existing list, paste the matching list below, and save.
@webjskit/website(webjs.dev)@webjskit/docs(docs.webjs.dev)@webjskit-examples/blog(example-blog.webjs.dev)@webjskit/ui-website(ui.webjs.dev)After the dashboard cleanup
website/app/page.ts→ only the website rebuilds.Dockerfileor rootpackage.json→ all four rebuild.packages/core/**orpackages/server/**→ all four rebuild (they all run on the framework).packages/ui/**→ only ui-website rebuilds.changelog/<pkg>/<version>.md→ only the website rebuilds (the page that reads it).Test plan
https://webjs.dev/changelogfinally renders the per-package entries (the deferred fix from PR fix(deploy): copy changelog/ into the production image #51).