diff --git a/changelog/cli/0.10.55.md b/changelog/cli/0.10.55.md new file mode 100644 index 000000000..2e2eb6f54 --- /dev/null +++ b/changelog/cli/0.10.55.md @@ -0,0 +1,25 @@ +--- +package: "@webjsdev/cli" +version: 0.10.55 +date: 2026-08-10T22:07:33.109Z +commit_count: 2 +--- +## Fixes + +- **the scaffold's rate-limit demo keys on the visitor, not the proxy** ([#1388](https://github.com/webjsdev/webjs/pull/1388)) [`ec610c69`](https://github.com/webjsdev/webjs/commit/ec610c69) + The rate-limit middleware a generated app receives took the default bucket key, + which is the socket peer. Deployed behind anything, that peer is the proxy, and + a proxy POOL hands out one full allowance per proxy, so the demo promised five + requests per ten seconds and refused nobody. It passes `trustProxy: true` now, + and its comments say what the default keys on and what a CDN does to it, since + the old `keyed by client IP by default` line is what made the mistake easy to + copy. `gallery:clear` also sheds the card's own test alongside the card, so a + reset app does not keep a test for a demo it no longer has. +- **the api template's demo explains the CDN case** ([#1390](https://github.com/webjsdev/webjs/pull/1390)) [`215b8f18`](https://github.com/webjsdev/webjs/commit/215b8f18) + The emitted middleware now points at `clientIpHeader` (new in + `@webjsdev/server` 0.8.63) and says why it is needed behind a CDN: the default + chain reads the leftmost `X-Forwarded-For` entry, which is then the CDN's + egress address, pinned per connection, so the limiter buckets connections + rather than visitors. The option is left UNSET in the generated app on purpose, + because the right header depends on what you deploy behind, and naming the + wrong one is a spoofing hazard rather than a no-op. diff --git a/changelog/server/0.8.63.md b/changelog/server/0.8.63.md new file mode 100644 index 000000000..0788c1700 --- /dev/null +++ b/changelog/server/0.8.63.md @@ -0,0 +1,27 @@ +--- +package: "@webjsdev/server" +version: 0.8.63 +date: 2026-08-10T22:07:33.040Z +commit_count: 1 +--- +## Fixes + +- **`rateLimit` can name the header carrying the visitor** ([#1390](https://github.com/webjsdev/webjs/pull/1390)) [`215b8f18`](https://github.com/webjsdev/webjs/commit/215b8f18) + `trustProxy: true` was not enough behind a CDN. The default chain starts at the + leftmost `X-Forwarded-For` entry, which behind Cloudflare is Cloudflare's + EGRESS address rather than the visitor, and those are pinned per connection, so + the limiter handed out one bucket per connection. The failure reads as working: + a page that pings on a button click holds one connection and counts down + correctly, while every fresh connection starts a new window and nobody is ever + refused. `rateLimit({ clientIpHeader })` and `clientIp(req, { header })` now + name the ONE forwarded header to trust, e.g. `'cf-connecting-ip'`. When set it + is the only wire header read, falling back to the stamped peer then `_anon_`; a + blank value falls through rather than becoming a bucket key every visitor + shares, and a comma chain is split so a proxy that appends cannot mint a bucket + per hop. It requires `trustProxy: true`, since naming a header to trust is the + trust decision, and `WEBJS_NO_TRUST_PROXY=1` still outranks both. Resolution + with no `clientIpHeader` is unchanged: the framework deliberately does NOT + prefer `CF-Connecting-IP` on its own, because Cloudflare overwrites that header + (unforgeable behind Cloudflare, forgeable everywhere else), so preferring it + globally would let a client on an nginx or bare-platform deploy outrank the + header the real proxy sets. diff --git a/package-lock.json b/package-lock.json index 14cd0b167..006a70660 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6979,7 +6979,7 @@ }, "packages/cli": { "name": "@webjsdev/cli", - "version": "0.10.54", + "version": "0.10.55", "license": "MIT", "dependencies": { "@webjsdev/mcp": "^0.1.0", @@ -7044,7 +7044,7 @@ }, "packages/server": { "name": "@webjsdev/server", - "version": "0.8.62", + "version": "0.8.63", "license": "MIT", "dependencies": { "@webjsdev/core": "^0.7.50", diff --git a/packages/cli/package.json b/packages/cli/package.json index 18ea284a8..cb79c0a19 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@webjsdev/cli", - "version": "0.10.54", + "version": "0.10.55", "type": "module", "description": "The CLI for WebJs, a full-stack JavaScript framework built on web components with server-side rendering and no build step. Runs the dev and production servers, scaffolds apps, validates conventions, and drives the database. Node 24+ or Bun.", "bin": { diff --git a/packages/server/package.json b/packages/server/package.json index 426253300..8925f2d62 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@webjsdev/server", - "version": "0.8.62", + "version": "0.8.63", "type": "module", "description": "The server for WebJs, a full-stack JavaScript framework built on web components with server-side rendering and no build step. Provides the file-based router, SSR, server actions, route handlers, middleware, and live reload on Node 24+ or Bun.", "main": "index.js",