diff --git a/Dockerfile.selfhost b/Dockerfile.selfhost index a0089aac..84498541 100644 --- a/Dockerfile.selfhost +++ b/Dockerfile.selfhost @@ -8,7 +8,12 @@ WORKDIR /app RUN corepack enable && corepack prepare pnpm@10.30.1 --activate +# `patches/` must come across with the manifests, not with the `COPY . .` below: +# pnpm-workspace.yaml declares `patchedDependencies`, and `pnpm install` hashes +# the patch file to verify it against the lockfile. Without it here the install +# fails before any source is copied. COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY patches/ ./patches/ RUN pnpm install --frozen-lockfile COPY . . diff --git a/patches/@tanstack__start-server-core@1.169.15.patch b/patches/@tanstack__start-server-core@1.169.15.patch new file mode 100644 index 00000000..f5467605 --- /dev/null +++ b/patches/@tanstack__start-server-core@1.169.15.patch @@ -0,0 +1,47 @@ +diff --git a/dist/esm/createStartHandler.js b/dist/esm/createStartHandler.js +index 34a160280fdb8fc522ca4448e52f0d246ebb60a6..1011023f7b51d25742bb8b79cd82568feca01f33 100644 +--- a/dist/esm/createStartHandler.js ++++ b/dist/esm/createStartHandler.js +@@ -23,14 +23,26 @@ var getCachedBaseManifest = createCachedBaseManifestLoader(() => getStartManifes + var getProdBaseManifest = () => getCachedBaseManifest(); + var getBaseManifest = process.env.TSS_DEV_SERVER === "true" ? getStartManifest : getProdBaseManifest; + var createEarlyHintsForRequest = process.env.TSS_DEV_SERVER === "true" ? () => void 0 : createEarlyHintsCollector; ++// PATCHED (FlyRocketSEO): the router entry is no longer loaded here. ++// ++// Upstream imported it in this Promise.all, i.e. on EVERY request, before the ++// handler knows whether the request is a page render or a `/_serverFn/*` call. ++// On Cloudflare Workers that is expensive: importing the router entry pulls the ++// generated route tree and every route definition (735 KB in this app), and a ++// server function never calls `getRouter()`. Measured on production ++// 2026-07-31, a cold isolate spent ~1650 ms of wall time inside the handler ++// against 48 ms of CPU -- module loading, not work. ++// ++// `routerEntry` had exactly one consumer, the `getRouter()` closure below, and ++// that closure is already async and already memoised via its own `router` ++// variable. So moving the import into it changes no behaviour: page renders, ++// server routes and router redirects still load it on first use. + async function loadEntries() { +- const [routerEntry, startEntry, pluginAdapters] = await Promise.all([ +- import("#tanstack-router-entry"), ++ const [startEntry, pluginAdapters] = await Promise.all([ + import("#tanstack-start-entry"), + import("#tanstack-start-plugin-adapters") + ]); + return { +- routerEntry, + startEntry, + pluginAdapters + }; +@@ -242,7 +254,11 @@ function createStartHandler(cbOrOptions) { + const executedRequestMiddlewares = new Set(flattenedRequestMiddlewares); + const getRouter = async () => { + if (router) return router; +- router = await entries.routerEntry.getRouter(); ++ // PATCHED (FlyRocketSEO): imported here rather than in ++ // `loadEntries()`, so only requests that actually need a router ++ // pay for the route tree. See the note on `loadEntries` above. ++ const routerEntry = await import("#tanstack-router-entry"); ++ router = await routerEntry.getRouter(); + let isShell = IS_SHELL_ENV; + if (IS_PRERENDERING && !isShell) isShell = request.headers.get(HEADERS.TSS_SHELL) === "true"; + const history = createMemoryHistory({ initialEntries: [href] }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1237d93e..4171f5ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,11 @@ overrides: smol-toml: ^1.6.1 undici: ^7.28.0 +patchedDependencies: + '@tanstack/start-server-core@1.169.15': + hash: d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75 + path: patches/@tanstack__start-server-core@1.169.15.patch + importers: .: @@ -6833,7 +6838,7 @@ snapshots: '@tanstack/start-client-core': 1.170.12 '@tanstack/start-fn-stubs': 1.162.0 '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(esbuild@0.28.1)(rolldown@1.0.0)(rollup@4.59.0)(vite@7.3.6(@types/node@22.19.11)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) - '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-server-core': 1.169.15(patch_hash=d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75) '@tanstack/start-storage-context': 1.167.15 pathe: 2.0.3 react: 19.2.4 @@ -6856,7 +6861,7 @@ snapshots: dependencies: '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-core': 1.171.13 - '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-server-core': 1.169.15(patch_hash=d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: @@ -6871,7 +6876,7 @@ snapshots: '@tanstack/router-utils': 1.162.2 '@tanstack/start-client-core': 1.170.12 '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(esbuild@0.28.1)(rolldown@1.0.0)(rollup@4.59.0)(vite@7.3.6(@types/node@22.19.11)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) - '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-server-core': 1.169.15(patch_hash=d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75) pathe: 2.0.3 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -6994,7 +6999,7 @@ snapshots: '@tanstack/router-generator': 1.167.17 '@tanstack/router-plugin': 1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(esbuild@0.28.1)(rolldown@1.0.0)(rollup@4.59.0)(vite@7.3.6(@types/node@22.19.11)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) '@tanstack/router-utils': 1.162.2 - '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-server-core': 1.169.15(patch_hash=d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75) exsolve: 1.1.0 lightningcss: 1.32.0 pathe: 2.0.3 @@ -7023,7 +7028,7 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/start-server-core@1.169.15': + '@tanstack/start-server-core@1.169.15(patch_hash=d28a458c6782d5057ed2ef4d2f25a07209442c2a87456f727c6b2db4957cab75)': dependencies: '@tanstack/history': 1.162.0 '@tanstack/router-core': 1.171.13 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 350e7b7d..db8b285b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,44 +1,24 @@ -minimumReleaseAge: 11520 -minimumReleaseAgeExclude: - - "@every-app/*" - -# Advisories triaged as not applicable. Re-review when the parent updates. -# - GHSA-67mh-4wv8-2f99: esbuild <=0.24.2 dev-server CORS. Only reachable via -# drizzle-kit's bundled @esbuild-kit loader (dev-time CLI); drizzle-kit never -# starts esbuild's serve mode, so the vulnerable path cannot execute. auditConfig: ignoreGhsas: - GHSA-67mh-4wv8-2f99 -# Security floors (added 2026-07) for transitive deps with published advisories -# where the parent hasn't shipped a bump yet. Each range sits inside what the -# parent already declares, so these are lockfile nudges, not forks. Ranges are -# major-bounded (^) on purpose: an override REPLACES the parent's range, so an -# open-ended >= floor would let a future major (e.g. hono 5) get forced onto a -# parent that only supports the current one. -# -# To prune once a parent catches up: delete the line, run `pnpm install`, and -# keep it deleted if `pnpm audit` stays clean. +minimumReleaseAge: 11520 + +minimumReleaseAgeExclude: + - "@every-app/*" + overrides: - # GHSA-4x5r-pxfx-6jf8 — waiting on @tanstack/devtools-vite - "@babel/core": "^7.29.6" - # GHSA-737v-mqg7-c878 — waiting on better-auth - defu: "^6.1.5" - # 13 advisories incl. GHSA-x4vx-rjvf-j5p4, GHSA-gvmj-g25r-r7wr — waiting on posthog-js - dompurify: "^3.4.11" - # GHSA-hmw2-7cc7-3qxx — waiting on cloudflare - form-data: "^4.0.6" - # 9 advisories incl. GHSA-88fw-hqm2-52qc (CORS) — waiting on @modelcontextprotocol/sdk - hono: "^4.12.25" - # GHSA-v6wh-96g9-6wx3 — waiting on @tanstack/devtools-vite - launch-editor: "^2.14.1" - # GHSA-qx2v-qp2m-jg93 — waiting on vite - postcss: "^8.5.10" - # GHSA-q8mj-m7cp-5q26 — waiting on @modelcontextprotocol/sdk - qs: "^6.15.2" - # GHSA-w7jw-789q-3m8p — waiting on @tanstack/devtools-vite - shell-quote: "^1.8.4" - # GHSA-v3rj-xjv7-4jmq — waiting on knip - smol-toml: "^1.6.1" - # 7 advisories incl. GHSA-vmh5-mc38-953g — waiting on cheerio + miniflare - undici: "^7.28.0" + "@babel/core": ^7.29.6 + defu: ^6.1.5 + dompurify: ^3.4.11 + form-data: ^4.0.6 + hono: ^4.12.25 + launch-editor: ^2.14.1 + postcss: ^8.5.10 + qs: ^6.15.2 + shell-quote: ^1.8.4 + smol-toml: ^1.6.1 + undici: ^7.28.0 + +patchedDependencies: + "@tanstack/start-server-core@1.169.15": patches/@tanstack__start-server-core@1.169.15.patch