From 386229c1abe6b2014d0e88bb3ce29fa8ca1b1786 Mon Sep 17 00:00:00 2001 From: Dax Date: Thu, 5 Nov 2026 16:45:19 -0500 Subject: [PATCH] fix(stats): route /data with a query string to the stats worker (#62193) --- infra/stats.ts | 20 +++++++------------- packages/stats/README.md | 2 +- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/infra/stats.ts b/infra/stats.ts index 146ec710475..0a517d57c00 100644 --- a/infra/stats.ts +++ b/infra/stats.ts @@ -80,22 +80,16 @@ const app = new sst.cloudflare.x.SolidStart("Stats", { }) // The site serves itself under /data and //data, and these routes are its only way in: it has no custom domain -// or workers.dev URL. Route patterns can't wildcard the middle of a path, hence one pair per locale. `sst dev` deploys -// no Worker. +// or workers.dev URL. An exact `/data` pattern misses `/data?query`, so each pattern is a `/data*` prefix. Route patterns +// can't wildcard the middle of a path, hence one per locale. `sst dev` deploys no Worker. const appServer = app.nodes.server if (appServer) { for (const prefix of ["data", ...LOCALES.map((locale) => `${locale}/data`)]) { - const name = prefix.replaceAll("/", "") - for (const [suffix, pattern] of [ - ["", `${domain}/${prefix}`], - ["Path", `${domain}/${prefix}/*`], - ]) { - new cloudflare.WorkersRoute(`StatsRoute${name}${suffix}`, { - zoneId: zoneID, - pattern, - script: appServer.nodes.worker.scriptName, - }) - } + new cloudflare.WorkersRoute(`StatsRoute${prefix.replaceAll("/", "")}`, { + zoneId: zoneID, + pattern: `${domain}/${prefix}*`, + script: appServer.nodes.worker.scriptName, + }) } } diff --git a/packages/stats/README.md b/packages/stats/README.md index 3a5d6845efa..fc5691ac2e3 100644 --- a/packages/stats/README.md +++ b/packages/stats/README.md @@ -42,4 +42,4 @@ To run one sync pass on your machine against a stage's resources, run `bun sst s Stats HTML, JSON, and Markdown use a one-minute browser cache and a five-minute shared cache. Expired responses must revalidate instead of serving stale snapshots. -The Worker has no custom domain. `infra/stats.ts` routes `/data`, `/data/*`, `//data` and `//data/*` on the main host straight to it, so its responses skip the Cloudflare cache and reach browsers with these headers unchanged. Static assets are uploaded under `/data`, and the build moves Nitro's `_headers` to the assets root so they stay immutable. +The Worker has no custom domain. `infra/stats.ts` routes `/data*` and `//data*` on the main host straight to it, so its responses skip the Cloudflare cache and reach browsers with these headers unchanged. Static assets are uploaded under `/data`, and the build moves Nitro's `_headers` to the assets root so they stay immutable.