Repository navigation
feat(web): refuse server function calls from another build - #4215
Conversation
- Add `buildId` to `configureServerFunctionsClient` and `configureServerFunctionsServer`. - The client sends `X-Server-Function-Build` on every call that is not GET-encoded. - A server with a different id answers 409 with its own id and does not run the function. - The client rejects with `versionSkew: true`, so an integration can reload the page. - GET-encoded reads stay header-free, so caches and preloads still match them by url. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 89a61a7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
Generated by Claude Code |
- Remove `buildId` from the client. The client runtime no longer sends the header, so it adds no bytes. - The 409 also carries the unknown-function label, so the client rejects with `unknownFunction: true`, the same as the 404. - Remove `BUILD_HEADER` from the public exports. The integration adds the header through `prepareRequest`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Moved the client half out of the transport, as suggested.
Two open questions for the integration side:
🤖 Generated with Claude Code |
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@solidjs/babel-plugin](https://redirect.github.com/solidjs/solid) ([source](https://redirect.github.com/solidjs/solid/tree/HEAD/packages/babel-plugin)) | [`2.0.0-rc.19` → `2.0.0-rc.20`](https://renovatebot.com/diffs/npm/@solidjs%2fbabel-plugin/2.0.0-rc.19/2.0.0-rc.20) |  |  | | [@solidjs/compiler](https://redirect.github.com/solidjs/solid) ([source](https://redirect.github.com/solidjs/solid/tree/HEAD/packages/compiler)) | [`2.0.0-rc.19` → `2.0.0-rc.20`](https://renovatebot.com/diffs/npm/@solidjs%2fcompiler/2.0.0-rc.19/2.0.0-rc.20) |  |  | | [@solidjs/signals](https://solidjs.com) ([source](https://redirect.github.com/solidjs/solid/tree/HEAD/packages/solid-signals)) | [`2.0.0-rc.19` → `2.0.0-rc.20`](https://renovatebot.com/diffs/npm/@solidjs%2fsignals/2.0.0-rc.19/2.0.0-rc.20) |  |  | | [@solidjs/vite-plugin](https://redirect.github.com/solidjs/solid-vite-plugin) | [`3.0.0-next.52` → `3.0.0-next.53`](https://renovatebot.com/diffs/npm/@solidjs%2fvite-plugin/3.0.0-next.52/3.0.0-next.53) |  |  | | [@solidjs/web](https://solidjs.com) ([source](https://redirect.github.com/solidjs/solid/tree/HEAD/packages/solid-web)) | [`2.0.0-rc.19` → `2.0.0-rc.20`](https://renovatebot.com/diffs/npm/@solidjs%2fweb/2.0.0-rc.19/2.0.0-rc.20) |  |  | | [solid-js](https://solidjs.com) ([source](https://redirect.github.com/solidjs/solid)) | [`2.0.0-rc.19` → `2.0.0-rc.20`](https://renovatebot.com/diffs/npm/solid-js/2.0.0-rc.19/2.0.0-rc.20) |  |  | | [wrangler](https://redirect.github.com/cloudflare/workers-sdk) ([source](https://redirect.github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler)) | [`4.155.0` → `4.156.0`](https://renovatebot.com/diffs/npm/wrangler/4.155.0/4.156.0) |  |  | --- ### Release Notes <details> <summary>solidjs/solid (@​solidjs/babel-plugin)</summary> ### [`v2.0.0-rc.20`](https://redirect.github.com/solidjs/solid/releases/tag/%40solidjs/babel-plugin%402.0.0-rc.20) [Compare Source](https://redirect.github.com/solidjs/solid/compare/@solidjs/babel-plugin@2.0.0-rc.19...@solidjs/babel-plugin@2.0.0-rc.20) ##### Patch Changes - [`56683ea`](https://redirect.github.com/solidjs/solid/commit/56683ea): SSR templates write characters above U+00FF in static text and quoted attribute values as numeric character references (`→` becomes `&#​8594;`), as do the static attributes baked into a spread element's attribute string. One character above U+00FF in a template made V8 store the whole rendered page as a two-byte string, which roughly doubled the cost of flattening and UTF-8 encoding the response ([#​4328](https://redirect.github.com/solidjs/solid/issues/4328)). Latin-1 characters stay literal. Tag internals, comments, raw-text bodies such as `<script>` and `<style>`, and the children of a spread `<script>` or `<style>` keep their characters, since browsers do not decode references there. Client output is unchanged. </details> <details> <summary>solidjs/solid-vite-plugin (@​solidjs/vite-plugin)</summary> ### [`v3.0.0-next.53`](https://redirect.github.com/solidjs/solid-vite-plugin/releases/tag/%40solidjs/vite-plugin%403.0.0-next.53) [Compare Source](https://redirect.github.com/solidjs/solid-vite-plugin/compare/@solidjs/vite-plugin@3.0.0-next.52...@solidjs/vite-plugin@3.0.0-next.53) ##### Patch Changes - [`2a081c3`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/2a081c3): Under `vite dev`, a server-function call that arrives before any page has loaded the server handler no longer loads the function's module ahead of `start.serverSetup`. The dev middleware imported the module first and the handler (which runs the server setup module first) second, so the module and everything it imports could load before instrumentation started. It now loads the handler first. - [`53bb865`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/53bb865): With `serverFunctions: { components: true }`, stylesheets that a `'use server'` module reaches (directly or through the components it imports) now reach the production client build, so the SSR document links them. The client compile replaces a server module with references, so its imports never joined the client graph: dev looked right, since its CSS crawl walks the SSR graph, but production rendered server components unstyled ([#​456](https://redirect.github.com/solidjs/solid-vite-plugin/issues/456)). The client build now walks what the module imports and imports those stylesheets from its client module. Script modules on the way are only loaded, never imported, so no server code reaches the client bundle, and compile-time CSS plugins such as StyleX still see them. Builds without `components` are unchanged. - [`3b0e262`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/3b0e262): Production builds now stamp server function calls with a build id ([solidjs/solid#4215](https://redirect.github.com/solidjs/solid/issues/4215)). The client build adds an `X-Server-Function-Build` header to every non-GET call, and the server build configures the runtime with the same id, read from the client build's `.vite/solid-server-functions.json`. A tab still running the previous deploy now gets a 409 (`unknownFunction: true`) for a function whose id survived the deploy, instead of running it with arguments of another shape. The app's own `prepareRequest` hook keeps working: the plugin wraps `configureServerFunctionsClient` so the build's stamp runs first and the app's hook runs after it. Dev is unchanged, a server built without a client build checks nothing, and a custom `runtime` is left alone. - [`4e64354`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/4e64354): Rename `start.setup` to `start.serverRenderSetup` and `start.instrument` to `start.serverSetup`, so the start lifecycle options say where and how often they run: `serverSetup` once before anything else on the server, `middleware` on every request, `serverRenderSetup` before every page render, `clientSetup` once in the browser. The old keys fail at config time with a message naming the replacement. - [`3236eca`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/3236eca): Add a "Migrating from vite-plugin-solid" section to the README, and point the rename banner at it. </details> <details> <summary>cloudflare/workers-sdk (wrangler)</summary> ### [`v4.156.0`](https://redirect.github.com/cloudflare/workers-sdk/blob/HEAD/packages/wrangler/CHANGELOG.md#41560) [Compare Source](https://redirect.github.com/cloudflare/workers-sdk/compare/wrangler@4.155.0...wrangler@4.156.0) ##### Minor Changes - [#​16532](https://redirect.github.com/cloudflare/workers-sdk/pull/16532) [`25802bc`](https://redirect.github.com/cloudflare/workers-sdk/commit/25802bce9f605916239bfd4714263c88f9b3098b) Thanks [@​simonha9](https://redirect.github.com/simonha9)! - Allow the experimental `wrangler d1 insights` command to run across every D1 database in the account The database name is now optional. With no name, the command returns the top queries across every D1 database in the account, and each result gains a `databaseId` field. ##### Patch Changes - [#​16369](https://redirect.github.com/cloudflare/workers-sdk/pull/16369) [`ec0bea4`](https://redirect.github.com/cloudflare/workers-sdk/commit/ec0bea48d6316c8ca893241efbf31f1ffcfa6134) Thanks [@​MattieTK](https://redirect.github.com/MattieTK)! - Stop autoconfig in non-interactive runs when a project root holds both static files and a Pages `functions` directory When a project without a detected framework has a `functions` directory, autoconfig asks whether it is a Cloudflare Pages project. Non-interactive runs (CI and coding agents) assume it is not and continue as a static site. When the static files are in the project root, that deploys the root as static assets, and the Pages Functions (the project's API routes) are not deployed. In that case autoconfig now stops with an error explaining that Pages Functions cannot be migrated automatically yet. For Pages Functions it suggests moving the static files into a subdirectory and deploying with `wrangler pages deploy`, or migrating the Functions to a Worker; for a `functions` directory that is not Pages Functions, it suggests moving the static files into a subdirectory or adding a configuration file. Projects whose static files are already in a subdirectory, projects detected as Pages or with a detected framework, and interactive runs where the user answers the prompt are unaffected. - [#​16367](https://redirect.github.com/cloudflare/workers-sdk/pull/16367) [`b4653b4`](https://redirect.github.com/cloudflare/workers-sdk/commit/b4653b40cdc6e176c4e5ac98696cf0dae641ff6b) Thanks [@​MattieTK](https://redirect.github.com/MattieTK)! - Write a protective `.assetsignore` when autoconfig uses the project root as the static assets directory Autoconfig is meant to write an `.assetsignore` when the project root itself is the assets directory, so that local files are not uploaded as public assets. The check compared the detected output directory, which is relative (`"."`), with the absolute project path, so it never matched and no `.assetsignore` was written. A static project with an `index.html` at its root (for example after `wrangler setup` or a zero-config `wrangler deploy`) then uploaded files such as `.env`, `.dev.vars`, `.git` and `node_modules` as public assets. The check now resolves the assets directory that the generated configuration uses and compares it with the project root, so frameworks that set their own build output directory (such as Nuxt or SvelteKit) do not get an unused root `.assetsignore`. The generated `.assetsignore` also covers what a Cloudflare Pages upload skips, alongside the existing `.wrangler`, `.dev.vars*` and `.env*` entries: `/_worker.js`, `/_routes.json` and `/functions` at the root (so nested paths such as `blog/functions/index.html` are still uploaded), `node_modules`, `.git` and `.DS_Store` at any depth, and `.npmrc`. If an existing `.assetsignore` only lists a narrower pattern such as `.env`, `.env*` is added so that files like `.env.production` are skipped too. When the project root of an assets-only project contains a Pages `functions` directory or `_worker.js`, autoconfig now warns that it will not be deployed, since it is excluded from the assets and not run as server code. - [#​16532](https://redirect.github.com/cloudflare/workers-sdk/pull/16532) [`25802bc`](https://redirect.github.com/cloudflare/workers-sdk/commit/25802bce9f605916239bfd4714263c88f9b3098b) Thanks [@​simonha9](https://redirect.github.com/simonha9)! - Fail the experimental `wrangler d1 insights` command with an actionable error when the GraphQL Analytics API rejects the request Previously the command printed an empty `[]`. Rate limit errors now say how long to wait before retrying, and authorization errors name the "Account Analytics: Read" permission the API token needs. - [#​16013](https://redirect.github.com/cloudflare/workers-sdk/pull/16013) [`8b64bec`](https://redirect.github.com/cloudflare/workers-sdk/commit/8b64becbd3817abb28654e270c0e0104170f29d7) Thanks [@​swalker326](https://redirect.github.com/swalker326)! - Fix Durable Object self-references in tests and container validation Durable Object bindings that explicitly name the Worker itself now resolve to the test runner in `@cloudflare/vitest-plugin`, for both `cloudflare.config.ts` and Wrangler configuration files. Named Wrangler environments use their effective Worker name, keeping bindings to the base Worker external. Container validation also accepts these self-references, using the effective deployment name to distinguish local and external bindings. Explicit binding targets remain intact during configuration conversion, so deploying with `--name` or a CI name override preserves the intended Durable Object target. - Updated dependencies \[[`15fbaed`](https://redirect.github.com/cloudflare/workers-sdk/commit/15fbaed2de992a529ca05d99424f8063d63217bf), [`d8899ac`](https://redirect.github.com/cloudflare/workers-sdk/commit/d8899ac4c85ff839d73daa9055a76a36248cd2e3)]: - <miniflare@5.20261023.3-beta> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/takumi3488/zandaka). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xODguMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE4OC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…#60) This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@solidjs/vite-plugin](https://redirect.github.com/solidjs/solid-vite-plugin) | [`3.0.0-next.52` → `3.0.0-next.53`](https://renovatebot.com/diffs/npm/@solidjs%2fvite-plugin/3.0.0-next.52/3.0.0-next.53) |  |  | --- ### Release Notes <details> <summary>solidjs/solid-vite-plugin (@​solidjs/vite-plugin)</summary> ### [`v3.0.0-next.53`](https://redirect.github.com/solidjs/solid-vite-plugin/releases/tag/%40solidjs/vite-plugin%403.0.0-next.53) [Compare Source](https://redirect.github.com/solidjs/solid-vite-plugin/compare/@solidjs/vite-plugin@3.0.0-next.52...@solidjs/vite-plugin@3.0.0-next.53) ##### Patch Changes - [`2a081c3`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/2a081c3): Under `vite dev`, a server-function call that arrives before any page has loaded the server handler no longer loads the function's module ahead of `start.serverSetup`. The dev middleware imported the module first and the handler (which runs the server setup module first) second, so the module and everything it imports could load before instrumentation started. It now loads the handler first. - [`53bb865`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/53bb865): With `serverFunctions: { components: true }`, stylesheets that a `'use server'` module reaches (directly or through the components it imports) now reach the production client build, so the SSR document links them. The client compile replaces a server module with references, so its imports never joined the client graph: dev looked right, since its CSS crawl walks the SSR graph, but production rendered server components unstyled ([#​456](https://redirect.github.com/solidjs/solid-vite-plugin/issues/456)). The client build now walks what the module imports and imports those stylesheets from its client module. Script modules on the way are only loaded, never imported, so no server code reaches the client bundle, and compile-time CSS plugins such as StyleX still see them. Builds without `components` are unchanged. - [`3b0e262`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/3b0e262): Production builds now stamp server function calls with a build id ([solidjs/solid#4215](https://redirect.github.com/solidjs/solid/issues/4215)). The client build adds an `X-Server-Function-Build` header to every non-GET call, and the server build configures the runtime with the same id, read from the client build's `.vite/solid-server-functions.json`. A tab still running the previous deploy now gets a 409 (`unknownFunction: true`) for a function whose id survived the deploy, instead of running it with arguments of another shape. The app's own `prepareRequest` hook keeps working: the plugin wraps `configureServerFunctionsClient` so the build's stamp runs first and the app's hook runs after it. Dev is unchanged, a server built without a client build checks nothing, and a custom `runtime` is left alone. - [`4e64354`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/4e64354): Rename `start.setup` to `start.serverRenderSetup` and `start.instrument` to `start.serverSetup`, so the start lifecycle options say where and how often they run: `serverSetup` once before anything else on the server, `middleware` on every request, `serverRenderSetup` before every page render, `clientSetup` once in the browser. The old keys fail at config time with a message naming the replacement. - [`3236eca`](https://redirect.github.com/solidjs/solid-vite-plugin/commit/3236eca): Add a "Migrating from vite-plugin-solid" section to the README, and point the rename banner at it. </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/takumi3488/ishigama-search). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xODguMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE4OC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
The unknown-id 404 (#3110) catches a function that a deploy removed or renamed. It cannot catch one whose id survived the deploy but whose arguments or result changed shape, because ids hash the file path and the name, not the body. This adds an opt-in build id check on the server for that case. It is the core version of solidjs/solid-start#2363.
Changes
BUILD_HEADER(X-Server-Function-Build) to the shared layer. It is not exported from either entry.buildIdto the server config. A call whose header names another build gets409, with the server's id under the same header andCache-Control: no-store. The arguments are not parsed and the function does not run.X-Server-Function-Unknown). The client rejects it withunknownFunction: true, the same as the unknown-id 404. There is one skew signal for integrations to check.prepareRequest. Platform skew protection, such as pinning a deployment by header or cookie, fits the same hook.buildIdchecks nothing.10-server-functions.md.Testing
test/server/server-functions-build-id.spec.tsx(6 tests) runs against the built bundles. It covers the refusal, a matching build, a call without the header, a server without an id, the client error flag through aprepareRequesthook, and a matching build through the client.link-claim.spec.tsxandlowercase-on-attribute.spec.tsx. These fail the same way without this change in my local setup, which has a stale compiler build.🤖 Generated with Claude Code