Skip to content

fix(adapter-node): skip socket cleanup for cluster workers - #16241

Open
tsushanth wants to merge 620 commits into
sveltejs:mainfrom
tsushanth:fix/16230-adapter-node-cluster-socket-deletion
Open

fix(adapter-node): skip socket cleanup for cluster workers#16241
tsushanth wants to merge 620 commits into
sveltejs:mainfrom
tsushanth:fix/16230-adapter-node-cluster-socket-deletion

Conversation

@tsushanth

Copy link
Copy Markdown

Fixes #16230.

Root cause

The stale-socket cleanup added in #15449 (released in adapter-node 5.5.7) unconditionally runs on every process startup:

if (fs.statSync(path).size === 0) {
  await rm(path);
}

The size === 0 heuristic is meant to detect a stale socket left over from an unclean shutdown, but a live unix domain socket also reports size = 0. In Node cluster / PM2 cluster mode:

  1. The primary process binds and creates the socket file.
  2. Each worker process inherits the primary's listening handle (no bind() of its own), runs the same startup code, finds size === 0, and deletes the live socket file.
  3. Workers appear healthy (they share the in-kernel listening state), but the socket path is gone from disk — the reverse proxy (e.g. nginx proxy_pass unix:…) can no longer connect. No error, no restart, silent regression.

Fix

Import node:cluster and skip the rm() call when the current process is a cluster worker. Workers inherit the socket handle from the primary and must never manage the socket file. The primary (or any single-process deployment) retains the existing cleanup behaviour unchanged.

cluster.isWorker is false in non-cluster processes, so this change is a no-op for single-process deployments.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 5, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 4a54700:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/4a54700cbf8eb3dc282a9f79e31b192c74ef6fb3

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16241

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4a54700

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@sveltejs/adapter-node Patch
@sveltejs/kit Major
@sveltejs/adapter-cloudflare Major
@sveltejs/adapter-vercel Major
@sveltejs/adapter-auto Patch
@sveltejs/adapter-static Patch
@sveltejs/adapter-netlify Major
@sveltejs/package Major
@sveltejs/enhanced-img Major

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

@enda

enda commented Jul 16, 2026

Copy link
Copy Markdown

Thanks for tackling this! The cluster.isWorker guard does fix the regression (workers must never touch the socket file), but I believe it quietly reintroduces the problem #15449 was solving, for the very setups it targeted.

In PM2 cluster mode (and any node:cluster-based supervisor), the primary is the supervisor's own daemon, it never runs the adapter's entry point. Every process that executes index.js has cluster.isWorker === true, so with this guard the stale-socket cleanup never runs at all in cluster deployments. After an unclean shutdown or reboot leaves a stale socket file behind, the bind fails with EADDRINUSE again, exactly the scenario #15449 addressed, where supervisors like PM2 were explicitly mentioned.

The root issue is that statSync(path).size === 0 can't distinguish a stale socket from a live one, both report size 0. Instead of special-casing cluster workers, I'd suggest replacing the heuristic with a liveness probe, which is topology-independent:

  1. stat the path; if it doesn't exist or !stats.isSocket(), do nothing (this also avoids ever deleting a regular file, which the size check doesn't guarantee).
  2. Try net.connect(path):
  • ECONNREFUSED → nothing is listening → stale → safe to remove;
  • connection succeeds, any other error, or a short timeout → assume live → leave it alone.

Note the conservative bias: a timeout or an unexpected error never leads to deletion, so the worst remaining case (a bound-but-frozen server) falls back to the old EADDRINUSE, never a silent deletion.

One caveat worth handling: with several instances racing a cold start, there's a TOCTOU window between the probe verdict and the rm: instance A can get ECONNREFUSED on the stale socket, and before its rm runs, instance B removes the stale file and re-binds a fresh live socket at the same path, which A then deletes. This is made worse in cluster mode: a subsequent listen from A would silently reuse the primary's existing handle without recreating the file, so the app keeps running with no socket on disk. Pinning the inode (stat before the probe, re-stat and compare dev+ino right before rm) shrinks that window from milliseconds to a couple of syscalls; an atomic mkdir(path + '.lock') mutex would close it entirely if we want to be strict. A post-listen existsSync(path) check that fails loudly (so the supervisor restarts into a now-free path) is a cheap extra safety net.

Sketch:

import net from 'node:net';
import { rm } from 'node:fs/promises';

function probe(path) {
  return new Promise((resolve) => {
    const socket = net.connect(path);
    const timer = setTimeout(() => {
      socket.destroy();
      resolve(true); // unresponsive but bound, be conservative
    }, 1000);
    socket.once('connect', () => {
      clearTimeout(timer);
      socket.destroy();
      resolve(true);
    });
    socket.once('error', (err) => {
      clearTimeout(timer);
      resolve(err.code !== 'ECONNREFUSED');
    });
  });
}

async function remove_stale_socket(path) {
  let before;
  try {
    before = fs.statSync(path);
  } catch {
    return; // nothing there
  }
  if (!before.isSocket()) return; // not a socket, don't touch it

  const alive = await probe(path);
  if (alive) return;

  try {
    const now = fs.statSync(path);
    if (now.ino !== before.ino || now.dev !== before.dev || !now.isSocket()) {
      return; // replaced since we probed, another instance just bound here
    }
    await rm(path, { force: true });
  } catch {
    // ENOENT: another instance already cleaned up
  }
}

With the probe in place the isWorker guard becomes unnecessary, and keeping it would still leave PM2 cluster mode without any stale-socket cleanup.

Happy to test any build against our PM2-cluster + nginx + unix-socket setup, since that's where we hit the original outage.

@tsushanth

Copy link
Copy Markdown
Author

The Node 20 CI failure is in remote-functions > renders correct values (expected "Example text", received "Updated text") — unrelated to this PR's adapter-node cluster socket change. The same test passes on Node 18, 22, and 24. All adapter-node-specific checks pass. Happy to rebase if there's a known fix upstream, but the failure doesn't appear to be caused by this change.

@tsushanth

Copy link
Copy Markdown
Author

Thanks @enda — great analysis. Replaced the cluster.isWorker guard with a liveness probe as suggested.

What changed:

  • Added remove_stale_socket(path) which stats the path (must exist and be a socket), probes with net.connect(), and only removes on ECONNREFUSED. Any other outcome (connect succeeds, timeout after 1s, unexpected error) leaves the file alone.
  • Re-stats and compares ino + dev right before rm to close the TOCTOU window between probe and delete.
  • Removed the cluster.isWorker guard — no longer needed and blocked cleanup in PM2 cluster setups.
  • Dropped the import cluster from 'node:cluster' that was only there for the guard.

The net import was already in scope (Node built-in). No new deps.

teemingc and others added 24 commits July 17, 2026 10:08
sveltejs#5215 (comment) is
right. Svelte 5 uses the web animations API so the we ought to remove
the note about Svelte 4 inline styles for animations
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.9

### Major Changes

- breaking: `handle`'s `resolve` is now typed to always return a
`Promise` ([sveltejs#16352](sveltejs#16352))

- breaking: replace the `$lib` alias with `#lib` and remove `files.lib`
config. ([sveltejs#16360](sveltejs#16360))

- breaking: disallow cross-origin form submissions without a
`Content-Type` header
([sveltejs#16347](sveltejs#16347))

- breaking: Server-only directories (`/server/` in the path) are now
treated as server-only everywhere inside the project (except
`src/routes` and the assets directory)
([sveltejs#16360](sveltejs#16360))

- breaking: delegate CORS handling to Vite for static directory requests
during development
([sveltejs#16357](sveltejs#16357))

### Minor Changes

- feat: reinstate `$env/static/private`, `$env/dynamic/private`,
`$env/static/public`, `$env/dynamic/public` and `$app/environment` as
deprecated aliases for `$app/env/private` `$app/env/public` and
`$app/env` ([sveltejs#16334](sveltejs#16334))

### Patch Changes

- perf: cache the default cookie header parse and avoid allocations in
`cookies.get` ([sveltejs#16341](sveltejs#16341))

- fix: avoid client-side code being bundled by Cloudflare Wrangler
([sveltejs#16364](sveltejs#16364))

- fix: handle rejected streamed server data after delayed loads
([sveltejs#16268](sveltejs#16268))

- fix: enable CSRF protection in builds with a non-production `NODE_ENV`
value ([sveltejs#16313](sveltejs#16313))
## @sveltejs/package@3.0.0-next.3

### Minor Changes

- feat: transform import aliases into relative imports in files
([sveltejs#16360](sveltejs#16360))
## @sveltejs/adapter-node@6.0.0-next.4

### Patch Changes

- fix: correctly bundle entrypoints on Windows
([sveltejs#16367](sveltejs#16367))
- Updated dependencies
[[`c1ee782`](sveltejs@c1ee782),
[`1a1b3ea`](sveltejs@1a1b3ea),
[`6423d98`](sveltejs@6423d98),
[`6d1f4f0`](sveltejs@6d1f4f0),
[`5ca9906`](sveltejs@5ca9906),
[`b148d31`](sveltejs@b148d31),
[`5ca9906`](sveltejs@5ca9906),
[`9f3d9bb`](sveltejs@9f3d9bb),
[`7bfd922`](sveltejs@7bfd922),
[`ffa0e3b`](sveltejs@ffa0e3b)]:
  - @sveltejs/kit@3.0.0-next.9
## @sveltejs/enhanced-img@1.0.0-next.2

### Patch Changes

- chore: replace the `$lib` alias with `#lib` in docs
([sveltejs#16360](sveltejs#16360))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…ejs#16383)

Addresses part of sveltejs#15461

`vite-plugin-sveltekit-guard` builds its `import_map` in every
environment, but the map is only read in the `load` hook, which bails
for non-client consumers before touching it. On the svelte.dev build
that makes 69% of the guard's `resolveId` calls (3,987 of 5,778) dead
work, and the guard was the top entry in dominikg's `PLUGIN_TIMINGS`
report in sveltejs#13756. This adds the same consumer bail to `resolveId`.

The error chains from sveltejs#14155 are unaffected because the client
environment collects its own edges. Measured on the svelte.dev build
with `3.0.0-next.6` and vite `8.0.16` (details in
sveltejs#15461 (comment)),
ssr-side hook time drops from ~296s cumulative to 23ms, the build
succeeds, and a planted two-hop `$lib/server` violation still fails with
the full chain. There is no new test because the behavior is meant to be
unobservable and the exact chain assertions already exist in
`test/apps/dev-only` (dev) and `test/build-errors/server-only.spec.js`
(build), both green with this change.

History for reviewers. sveltejs#15439 added hook filters everywhere except this
hook, which is blocked on vitejs/vite#21956. sveltejs#15543 proposed this skip
plus a node_modules importer skip and was closed pending kit 3. The ssr
half was not fixed by kit 3. The node_modules half is not implemented
here because it is unsafe, a library can legitimately import
`$app/server` and its violation chain has to walk node_modules edges.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
follow up to sveltejs#16383

Using `applyToEnvironment` is better here as the plugin isn't needed in
the server environment if we're already using an `if (...)` guard to opt
out early
fix for
[https://github.com/sveltejs/kit/security/code-scanning/33](https://github.com/sveltejs/kit/security/code-scanning/33)

We don't care about the `vbscript:` protocol since that only works on
internet explorer. I've also tested running it on Safari/Firefox/Chrome
and it's not recognised.

`data:` on the other hand does allow running some arbitrary javascript:
```
data:text/html,%3Cscript%3Ealert%28%27hi%27%29%3B%3C%2Fscript%3E
```
> An HTML document with <script>alert('hi');</script> that executes a
JavaScript alert. Note that the closing script tag is required.

Taken from
https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/data#datatexthtml3cscript3ealert2827hi27293b3c2fscript3e

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Restoring the install from cache seems to save 5-10 seconds. Solution
adapted from the article Rich shared
https://endform.dev/blog/playwright-github-actions#speed-fix-1-cache-the-browser-binaries
. OS-specific cache paths taken from
https://playwright.dev/docs/browsers#managing-browser-binaries

Cache is keyed to `pnpm-lock.yaml` so it will bust when we upgrade deps.
We _could_ derive the playwright version from the pnpm workspace file...
We decided this was more future-proof — we _might_ in future want to
have more env-related exports (e.g. some convenience schemas) and it
would be weird to a) have them in a different place to `defineEnvVars`
or b) put them in `@sveltejs/kit/hooks`

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
closes sveltejs#12391

Not sure how to word the warning message so I'm open to suggestions

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [ ] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [ ] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.10

### Major Changes

- breaking: move `defineEnvVars` to `@sveltejs/kit/env`
([sveltejs#16375](sveltejs#16375))

### Patch Changes

- fix: treat `data:` protocol URLs as external for redirect
([sveltejs#16392](sveltejs#16392))

- perf: skip import graph collection outside client environments
([sveltejs#16383](sveltejs#16383))

- fix: warn if there are plugins using `transformIndexHtml`
([sveltejs#16394](sveltejs#16394))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
follow up to sveltejs#16387
I missed adding it to the platform tests
closes sveltejs#11291

This makes the error messages more useful in a couple of contexts:
- during prerendering, surface the original error, and apply source
mapping where possible
- format the stack better in a few places
- harden a few places where errors were swallowed, log them to the
console now

Error messages are not yet super nicely formatted, so this is one thing
that can still be improved.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Resolves the TODO in `escape.js` from sveltejs#4024, which planned to simplify
the surrogate pattern with lookbehind assertions once widely supported.
Lookbehind has been safe everywhere relevant since Safari 16.4, but
`\p{Surrogate}` with the `u` flag is simpler still and supported even
longer (ES2018). Under the `u` flag a valid surrogate pair forms a
single astral code point, so `\p{Surrogate}` matches only unpaired
surrogates and the pattern's other two branches disappear, including the
branch that existed only to match valid pairs so the replace callback
could return them unchanged.

That branch is also why this is a perf change rather than a cleanup.
Every valid pair in rendered content currently invokes the replace
callback just to pass through. With the new pattern pairs never match,
so `escape_html` measures about 2x faster on emoji-heavy content in a
quick microbench, with plain ASCII at parity.

Output is unchanged. I diffed the old and new implementations over 200k
fuzzed strings built from surrogate halves, dict characters and astral
pairs, plus curated edge cases, in both modes, all byte-identical.
`escape.spec.js` passes as-is.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
> ℹ️ **Note**
> 
> This PR body was truncated due to platform limits.

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
|
[`11.8.0+sha512.c1f5e7c4cb241c8f174b743851d82f42b802324afc8b0f116b96adb15aa06664948dde36960a3ba1079ba5b4b29dd0140135b94b5b5f5263592249d68e555f26`
→ `11.15.0`](https://renovatebot.com/diffs/npm/pnpm/11.8.0/11.15.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.15.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.8.0/11.15.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.15.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.15.0):
pnpm 11.15

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.14.0...v11.15.0)

##### Minor Changes

- Optional peer dependencies declared only via `peerDependenciesMeta`
(for example `debug`'s `supports-color` peer) are now resolved from a
satisfying version already present in the dependency graph, the same way
explicitly declared optional peer dependencies are. Previously such
peers were only resolved this way when the package's metadata was read
back from the lockfile, so an unrelated dependency change could rewrite
peer resolutions across the whole lockfile.

##### Patch Changes

- Updated `adm-zip` to prevent crafted ZIP archives from causing
excessive memory allocation.

- `pnpm version -r` no longer writes a versioning-ledger entry with no
consumed intents as a bare `intents:` key, which the next run failed to
read with `ERR_PNPM_INVALID_VERSIONING_LEDGER`. Empty intent lists are
now written as `intents: []`, and the ledger reader accepts the bare
form left by earlier releases.

- Fixed pnpr workspace resolution to preserve project names and versions
for `workspace:` dependencies.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.14.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.14.0):
pnpm 11.14

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.13.1...v11.14.0)

#### Minor Changes

- `peerDependencies` now accept dependency specifiers that carry a
scheme — a named-registry spec (`<registry>:<version>`), an `npm:`
alias, or a `file:`/git/URL spec — instead of rejecting them with
`ERR_PNPM_INVALID_PEER_DEPENDENCY_SPECIFICATION`
[#&#8203;13095](https://redirect.github.com/pnpm/pnpm/issues/13095).
Such a peer is matched against the semver range carried by the specifier
(`work:5.x.x` is checked as `5.x.x`, `npm:bar@^5` as `^5`), or against
`*` when it carries no version, while the original specifier still
selects the package to auto-install. Bare `name@version` values, which
are almost always a mistake, are still rejected.

- Added `pnpm doctor`, which diagnoses the pnpm installation and the
environment it runs in: the versions and install method, whether the
global bin directory is on `PATH`, whether the store and cache are
writable, which link strategies (reflink, hardlink, symlink) the store's
filesystem supports, registry connectivity, and an offline `file:`
install that exercises the resolve/store/link path end to end. Each
check reports how to fix what it finds, and the command exits non-zero
when any check fails.

Use `--offline` to skip the checks that need network access, `--json`
for machine-readable output, and `--benchmark` to time the filesystem
and install checks.

- Added support for executing multiple scripts matching a RegExp passed
to `pnpm run` (e.g., `pnpm run "/^build:.*/"`), running matched scripts
in deterministic lexicographical order. Restored the `--sequential`
(`-s`) CLI option for `pnpm run`, which forces `workspaceConcurrency` to
1 so that matched scripts run sequentially one by one across and within
packages.

#### Patch Changes

- Fixed `pnpm install` failing with `ERR_PNPM_LOCKFILE_IS_SYMLINK` when
`pnpm-lock.yaml` is a symlink, as build sandboxes such as Bazel and Nix
stage it
[#&#8203;13073](https://redirect.github.com/pnpm/pnpm/issues/13073).
Reading a lockfile through a symlink is allowed again, and an install
that leaves the lockfile unchanged no longer rewrites it, so
`--frozen-lockfile` no longer needs to write at all. Writing a *changed*
lockfile through a symlink is still refused, as that would redirect the
write onto the symlink's target.

- Fixed frozen installs incorrectly treating equivalent Git dependency
specifiers as a stale lockfile. See
[#&#8203;13039](https://redirect.github.com/pnpm/pnpm/issues/13039).

- `pnpm owner ls` now reports authentication and authorization failures
(401/403) as dedicated errors that include the registry's response body,
matching `pnpm owner add`/`rm`, instead of a generic `Failed to fetch
owners` message.

- Recover from a metadata cache entry that disappears (concurrent cache
cleanup, antivirus) after the registry has already answered the
conditional request with `304 Not Modified`. The metadata is
re-requested once without cache validators instead of failing the
install with `ERR_PNPM_CACHE_MISSING_AFTER_304`.

- A project pinned to a broken pnpm release via `packageManager` or
`devEngines.packageManager` now reports which release is broken and what
to do about it, instead of failing inside the installer. `pnpm
self-update` already refused these releases; the version switch does
too.

- Prevent broken-lockfile errors from including snippets of the
lockfile's contents.

- `pnpm self-update` now checks that the version it installed can run
before making it the active pnpm. A release that installs but cannot
execute is discarded with an error instead of replacing a working
installation.

- Fixed an out-of-memory regression when workspace projects concurrently
resolve a package with large registry metadata
[pnpm/pnpm#13077](https://redirect.github.com/pnpm/pnpm/issues/13077).

- Fixed `pnpm update` rewriting exact version pins that use the `=`
operator (for example `=3.5.1`) to a caret range (`^3.5.1`). Exact pins
are now preserved and written back as the bare version. See
[#&#8203;12745](https://redirect.github.com/pnpm/pnpm/issues/12745).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.13.1`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.13.1):
pnpm 11.13.1

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.13.0...v11.13.1)

#### Patch Changes

- Fixed `pnpm pack` applying workspace-root ignore rules when a
workspace package has its own `.npmignore` file.
- Keep the interactive `minimumReleaseAge` approval prompt visible
during `pnpm install`. The progress reporter now pauses its redraws
while a prompt is waiting for input instead of overwriting it, so the
install no longer hangs on a question the user cannot see
[#&#8203;13019](https://redirect.github.com/pnpm/pnpm/issues/13019).
- Fixed `pnpm self-update` failing to link native platform binaries
stored in sibling global virtual store slots.

###
[`v11.13.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.13.0):
pnpm 11.13

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.12.0...v11.13.0)

#### Minor Changes

- Added `versioning.epics` to `pnpm-workspace.yaml`. An epic ties a
group of member packages to a lead package, constraining every member's
major version to a band derived from the lead's major: while the lead is
on major `M`, members live in `M*100 … M*100+99`. Members move
independently inside the band (patch, minor, and a `major` intent that
stays in-band); a bump that would carry a member past the band ceiling
is rejected until the lead advances its own major. When a release plan
takes the lead to a new stable major, every member re-bases to the band
floor in the same plan. Membership is matched with pnpm's package
selectors — name globs, `./`-prefixed directory globs, and `!`-prefixed
negations.

- Added the `team` command for managing organization teams and team
memberships on the registry, with create, destroy, add, rm, and ls
subcommands and support for --otp, --parseable, and --json flags.

- Added native workspace release management
[#&#8203;12952](https://redirect.github.com/pnpm/pnpm/issues/12952): the
new `pnpm change` command records change intents as
changesets-compatible `.changeset/*.md` files (`pnpm change status`
shows the pending release plan), and the bare `pnpm version -r` consumes
them — bumping versions across the workspace with dependent propagation
through `workspace:` ranges, fixed groups, a `maxBump` cap, `--filter`
narrowing, and `--dry-run` — writing changelogs, and recording consumed
intents in a committed ledger that keeps cherry-picks and merge-backs
between release branches safe. Packages can be moved onto per-package
release lanes with the new `pnpm lane <name> --filter <pkg>` command and
back with `pnpm lane main --filter <pkg>` (`pnpm lane` shows the
membership), releasing `X.Y.Z-lane.N` prereleases from the same runs
that release stable versions of the packages on the main lane.
Configuration lives under the new `versioning` key of
`pnpm-workspace.yaml` (`fixed`, `ignore`, `maxBump`, `lanes`,
`changelog`). When two workspace projects publish the same name, intent
files, `versioning.lanes`, and `versioning.fixed`/`ignore` may reference
a project by its workspace-relative directory path (e.g.
`"./pnpm/npm/pnpm"`) — the one additive extension to the changesets
format, applied automatically by `pnpm change`.

Release changelogs default to `registry` storage
(`versioning.changelog.storage`): no `CHANGELOG.md` is committed. Each
release's section is composed at publish time and packed into the
published tarball on top of the previously published version's
changelog, and the consumed change intents are garbage-collected by a
later `pnpm version -r` only once the registry confirms the version is
published with its section. Set `versioning.changelog.storage:
repository` to keep committed `CHANGELOG.md` files instead.

- Added a new override selector form with an empty range — `"pkg@":
"<version>"` — called a convergence override. It rewrites a dependency
edge only when its exact version satisfies the edge's declared range, so
compatible consumers converge on one version while incompatible
consumers keep their own resolution — now and for any dependent added in
the future
[#&#8203;12794](https://redirect.github.com/pnpm/pnpm/issues/12794).

  ```yaml
  overrides:
    "form-data@": 4.0.6
  ```

The value must be an exact version. When a full resolution detects that
every declared range also admits a newer version, pnpm warns that the
override is stale and names the version to converge on. Previously an
empty range in an override selector was undocumented and behaved like a
bare (unscoped) override.

#### Patch Changes

- A `tokenHelper` set in the global pnpm `auth.ini` is no longer
rejected as project-level configuration. The guard that blocks
`tokenHelper` from a project `.npmrc` only treated `~/.npmrc` as a
trusted source, so a helper written to `auth.ini` (for example by `pnpm
config set`) failed on every command and could not even be removed with
`pnpm config delete`. A `tokenHelper` in a workspace or project `.npmrc`
is still rejected.

- `pnpm cache delete` now removes a package's metadata from every
metadata cache directory (`metadata`, `metadata-full`, and
`metadata-full-filtered`), instead of only the one the current
resolution mode reads. Previously a package cached under a different
mode (e.g. `metadata-full-filtered`) was left behind. Closes
[#&#8203;12753](https://redirect.github.com/pnpm/pnpm/issues/12753).

- Fixed an injected workspace dependency (`injectWorkspacePackages:
true`) incorrectly staying as `file:` instead of deduping back to
`link:` when an unrelated, ordinary shared dependency resolved to a
peer-suffixed variant for the target project's own copy but not for the
injected occurrence. See
[#&#8203;10433](https://redirect.github.com/pnpm/pnpm/issues/10433).

- `pnpm deploy` now supports workspaces that use catalogs.

- Fixed `pnpm deploy` with a shared lockfile so local `file:` tarball
dependencies keep their package name in the generated deploy lockfile.
This prevents warm-store deploys from failing with
`ERR_PNPM_UNEXPECTED_PKG_CONTENT_IN_STORE` when the tarball filename
includes the version.

- Options that follow `create`, `exec`, or `test` appearing as a
subcommand of another command are now parsed instead of being silently
treated as positional parameters. For example, `pnpm team create
@&#8203;org:team --registry <url>` previously ignored the `--registry`
option and sent the request to the default registry.

- `pnpm add -g`, `pnpm update -g`, `pnpm setup`, and the self-updater no
longer fail with `ERR_PNPM_MISSING_TIME` when `trustPolicy:
no-downgrade` or `resolutionMode: time-based` is set in the global
config
[#&#8203;12883](https://redirect.github.com/pnpm/pnpm/issues/12883). The
decision to fetch full registry metadata now lives in one place, and the
`no-downgrade` trust policy always requests full metadata (matching the
self-updater), since the trust evidence it checks is missing from
abbreviated metadata even on registries that include the `time` field.

- `pnpm list` and `pnpm why` no longer crash with `EMFILE: too many open
files` when a project has a large number of unsaved dependencies
(packages present in `node_modules` but not in the lockfile). The reads
of those packages are now concurrency-limited.

- The published `pnpm` package no longer declares `dependencies` or
`devDependencies`. Because the CLI bundles its runtime dependencies into
`dist/node_modules`, those fields are dropped when packing, so `npm
install` of the tarball no longer tries to resolve internal-only
packages such as `@pnpm/test-ipc-server`. Closes
[#&#8203;12955](https://redirect.github.com/pnpm/pnpm/issues/12955).

- Fixed `pnpm publish --otp` and `pnpm publish --batch --otp` to send
the configured OTP to the registry.

- `pnpm publish` again sends the package's README to the registry as
metadata, so registries can render it on the package page. The readme is
always included in the published metadata (matching the npm CLI), while
the `embed-readme` setting continues to control only whether the readme
is written into the `package.json` inside the tarball. This restores the
behavior that was lost when publishing became fully native. Closes
[#&#8203;12966](https://redirect.github.com/pnpm/pnpm/issues/12966).

- Fixed the dependency status check wrongly reporting "up to date" when
a `package.json`, `.pnpmfile.cjs`, or patch file was edited in the same
second as the previous install, on filesystems that record mtimes at
whole-second resolution (for example ext4 with 128-byte inodes). The
optimistic repeat-install fast path and `verify-deps-before-run`
compared mtimes strictly, so a same-second edit whose mtime rounded down
looked unchanged and re-resolution was skipped. Such a file's whole
second is now treated as possibly-modified, falling through to the
content check; behavior on sub-second filesystems is unchanged.

- Retry package metadata requests when a registry or proxy returns `304
Not Modified` to an unconditional request, preventing false
`ERR_PNPM_CACHE_MISSING_AFTER_304` failures
[pnpm/pnpm#12882](https://redirect.github.com/pnpm/pnpm/issues/12882).

If the retry also returns `304`, report
`ERR_PNPM_META_NOT_MODIFIED_WITHOUT_CACHE` instead.

- Fixed `pnpm update` removing transitive lockfile entries when
`dedupePeerDependents` is disabled and the selected package is absent
[pnpm/pnpm#12456](https://redirect.github.com/pnpm/pnpm/issues/12456).

- Limit modern deploy lockfiles and localized virtual stores to
dependencies reachable from the selected dependency groups.

- A `tokenHelper` command is now given a 60-second time limit. A helper
that hangs (deadlock, stuck I/O) is killed and reported as an error
instead of leaving the command waiting forever.

- Fixed orphaned child processes on Windows when pnpm exits on an error
while commands spawned by `pnpm exec` or `pnpm dlx` are still running
(for example, when one project's command fails during `pnpm --recursive
exec`). The PIDs of these commands are now recorded when they are
spawned and their whole process trees are terminated with `taskkill` on
an error exit. Previously the cleanup relied on enumerating the system
process list, which is so slow on Windows that the enumeration hit its
timeout and the cleanup was silently skipped
[#&#8203;12406](https://redirect.github.com/pnpm/pnpm/issues/12406).

- `pnpm pack` now respects workspace-root `.npmignore` and `.gitignore`
files when packing workspace packages.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.12.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.12.0):
pnpm 11.12

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.11.0...v11.12.0)

#### Minor Changes

- [`a897ef7`](https://redirect.github.com/pnpm/pnpm/commit/a897ef7):
Custom fetchers exported from a pnpmfile can now delegate by returning a
`{ delegate: <resolution> }` envelope: pnpm rewrites the package's
resolution to the delegated shape and runs the built-in fetcher on it.
This is the portable delegation form that also works in pacquet, where
`cafs` and `fetchers` cannot be passed to the hook. Related to
[pnpm/pnpm#11685](https://redirect.github.com/pnpm/pnpm/issues/11685).

#### Patch Changes

- [`2b02764`](https://redirect.github.com/pnpm/pnpm/commit/2b02764): The
changed-packages filter (`--filter "...[<since>]"`) no longer allows an
option-like `<since>` value (such as `--output=<path>`) to be
interpreted as a git option — git now rejects it as a bad revision. The
repository root is also resolved to the nearest `.git` entry, so the
filter works in a git worktree checked out inside another repository's
tree.

- [`43711ce`](https://redirect.github.com/pnpm/pnpm/commit/43711ce):
`pnpm outdated` no longer checks the registry for dependencies that are
resolved from local `link:`, `file:`, or `workspace:` references in the
lockfile
[#&#8203;12827](https://redirect.github.com/pnpm/pnpm/issues/12827).

- [`3c6718b`](https://redirect.github.com/pnpm/pnpm/commit/3c6718b):
Fixed a deadlock in peer dependency resolution: `pnpm install` hung
forever when a peer dependency cycle spanned a project's own
dependencies and auto-installed peer providers, for example when
installing `electron-builder@26.15.3`
[#&#8203;12921](https://redirect.github.com/pnpm/pnpm/issues/12921).

- [`252f15e`](https://redirect.github.com/pnpm/pnpm/commit/252f15e):
Fixed peer dependency auto-install picking a version the peer range
rejects. In a workspace with several projects, a package declaring a
peer dependency with a semver range (for example `^1.0.0`) could get the
highest version found anywhere in the workspace (for example a `2.0.0`
resolved for another project) instead of a version that satisfies the
range. Peers are now deduplicated onto the highest preferred version
that satisfies the declared range, and when none does, the range is
resolved from the registry.

Also fixed re-resolving with an existing lockfile hoisting a different
peer version than a fresh install of the same manifest: root
dependencies reused from the lockfile were invisible to peer hoisting,
so a peer that a root dependency provides could be bound to another
version.

- [`a38adda`](https://redirect.github.com/pnpm/pnpm/commit/a38adda):
`pnpm self-update <version>` now installs the requested pnpm version
when it matches the currently running version but is missing from the
global self-update directory.

- [`6a85968`](https://redirect.github.com/pnpm/pnpm/commit/6a85968):
`pnpm stage list` now stops paginating after a fail-safe cap of 1000
pages, so a misbehaving registry cannot keep the command looping
forever.

- [`eee7c9a`](https://redirect.github.com/pnpm/pnpm/commit/eee7c9a):
`verify-deps-before-run` no longer spawns a `pnpm install` when pnpm is
executed in a directory that has no `package.json`. A mistyped command
run outside a project (for example `pnpm witch 10 login`) used to crash
with a confusing error from the spawned install; now it fails with the
regular "no package.json found" error.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.11.0`](https://redirect.github.com/pnpm/pnpm/blob/HEAD/pnpm11/pnpm/CHANGELOG.md#11110)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.10.0...v11.11.0)

##### Minor Changes

- [`508b8c2`](https://redirect.github.com/pnpm/pnpm/commit/508b8c2):
Added the `pnpm access` command for managing package access and
visibility on the registry, supporting listing packages and
collaborators, getting and setting package status and MFA requirements,
and granting or revoking team access.

##### Patch Changes

- [`c70e33e`](https://redirect.github.com/pnpm/pnpm/commit/c70e33e):
Allow `allowBuilds` entries for git-hosted packages to match by
repository URL without pinning the resolved commit hash. This lets
trusted git repositories keep running their build scripts after branch
updates without approving each new commit, while package-name-only rules
still do not approve git-hosted artifacts.
- [`3067e4f`](https://redirect.github.com/pnpm/pnpm/commit/3067e4f):
Reduced peak memory usage during cold-cache dependency resolution. The
metadata fetch is memoized for the whole resolution phase, and it was
retaining each package's raw registry response body (used only to mirror
the response to disk) for that entire time. The memoized cache now holds
a body-less copy, so the raw body only lives as long as the call that
writes the disk mirror. On large graphs that fetch full metadata (e.g.
with `minimumReleaseAge` or `trustPolicy` enabled) this cuts peak RSS by
roughly 30%, back in line with pnpm 10. The resolved lockfile is
unchanged.
- [`51300fd`](https://redirect.github.com/pnpm/pnpm/commit/51300fd):
Prevent a crafted `pnpm-lock.yaml` from writing package content outside
the virtual store. A dependency path key whose name reconstructs to a
path-traversal sequence (e.g. `../../../tmp/x@1.0.0`) is now rejected by
the isolated (virtual-store) linker and the Plug'n'Play resolver map,
matching the containment already applied to the hoisted linker. Under
the global virtual store, a traversal in the version-derived path
segment (e.g. a snapshot `version: "../../x"`) is now rejected at
`formatGlobalVirtualStorePath`, the single point every
global-virtual-store slot path funnels through — closing the same escape
in the isolated linker, the resolver's dependency-graph builder, and the
config-dependency installer.
- [`f8058eb`](https://redirect.github.com/pnpm/pnpm/commit/f8058eb):
Reject symlinked `pnpm-lock.yaml` files when reading or writing the env
lockfile document.
- [`9318a11`](https://redirect.github.com/pnpm/pnpm/commit/9318a11):
Allow `registries` and `namedRegistries` to be configured in the global
`config.yaml` file.
- [`51300fd`](https://redirect.github.com/pnpm/pnpm/commit/51300fd):
Fixed a path traversal vulnerability where a dependency whose manifest
`name` was a scoped path traversal (e.g. `@x/../../../<path>`) could be
written outside `node_modules` to an attacker-controlled location during
`pnpm install`, even with `--ignore-scripts`. The isolated linker now
validates the package name before using it as a directory name, matching
the existing protection in the hoisted linker.
- [`14332f0`](https://redirect.github.com/pnpm/pnpm/commit/14332f0):
Fail instead of silently removing an optional dependency's locked
entries from `pnpm-lock.yaml` when the registry cannot resolve it.
Previously, when registry metadata lacked a version that the lockfile
already pinned (for example, a mirror that had not synced a recent
release yet), `pnpm install` and `pnpm dedupe` silently dropped the
optional dependency's entries — emptying maps such as the platform
binaries of `@napi-rs/canvas` — so the lockfile differed between
machines and frozen installs on other hosts had nothing to link
[#&#8203;12853](https://redirect.github.com/pnpm/pnpm/issues/12853).
- [`fecfe83`](https://redirect.github.com/pnpm/pnpm/commit/fecfe83):
Fixed peer dependency resolution with `autoInstallPeers` when a
workspace package depends on a version of a package that a transitive
dependency's self-contained closure also provides for itself. The peer
providers that are attached to the root project for reuse are no longer
peer-resolved a second time in the root context, so packages inside such
a closure no longer get their peers bound to the root project's
incompatible version
[#&#8203;4993](https://redirect.github.com/pnpm/pnpm/issues/4993).
- [`5a4daec`](https://redirect.github.com/pnpm/pnpm/commit/5a4daec):
`${...}` environment-variable placeholders in the `httpProxy`,
`httpsProxy`, `noProxy`, `proxy`, and `noproxy` settings are no longer
expanded when these settings come from a project's
`pnpm-workspace.yaml`. They now receive the same protection already
applied to `registry`, `namedRegistries`, and `pnprServer`.
- [`d1da02e`](https://redirect.github.com/pnpm/pnpm/commit/d1da02e):
`pnpm publish` no longer prints credentials when the target registry is
configured with inline `user:pass@` credentials (e.g.
`registry=https://user:pass@example.com/`). They are now redacted both
from the "publishing to registry" line and from the OIDC (trusted
publishing) failure messages.
- [`dcfc611`](https://redirect.github.com/pnpm/pnpm/commit/dcfc611):
`pnpm self-update` now honors `trustPolicy=no-downgrade`. It resolves
the target pnpm version against full registry metadata, so it refuses to
switch to a version whose supply-chain trust evidence is weaker than an
earlier-published one, the same way a regular install does.
- [`a8ad82d`](https://redirect.github.com/pnpm/pnpm/commit/a8ad82d):
Register the `pn` alias in generated shell completion scripts.
- [`25bd5c3`](https://redirect.github.com/pnpm/pnpm/commit/25bd5c3):
Fixed standalone installer downgrades from pnpm v12 to v11.
- [`23996e9`](https://redirect.github.com/pnpm/pnpm/commit/23996e9):
`pnpm runtime set <name> <version>` now validates its arguments: the
name must be `node`, `deno`, or `bun`, and the version must not contain
a comma. Previously these were interpolated straight into a `pnpm add`
selector, where an unsupported name or a comma (e.g. `node
22,is-positive`) could be misread as a list of packages or a local
directory and install unintended packages or bins.

###
[`v11.10.0`](https://redirect.github.com/pnpm/pnpm/blob/HEAD/pnpm11/pnpm/CHANGELOG.md#11100)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.9.0...v11.10.0)

##### Minor Changes

- [`e2e3c81`](https://redirect.github.com/pnpm/pnpm/commit/e2e3c81):
Added the `issues` command as an alias of `bugs`, so `pnpm issues` opens
the package's bug tracker URL in the browser.

- [`8491f8e`](https://redirect.github.com/pnpm/pnpm/commit/8491f8e):
Added the `prefix` command which prints the current package prefix
directory (or global prefix directory if `-g` / `--global` is used).

- [`3425e80`](https://redirect.github.com/pnpm/pnpm/commit/3425e80):
Added an `_auth` setting for configuring registry authentication as a
single structured (URL-keyed) value. It can be set in the **global**
pnpm config (`config.yaml`) or, for CI, via the `pnpm_config__auth`
environment variable. The env form sidesteps the GitHub Actions / bash /
zsh limitation that broke the existing
`pnpm_config_//host/:_authToken=…` form (env var names containing `/`,
`:`, or `.` are silently dropped). Closes
[#&#8203;12314](https://redirect.github.com/pnpm/pnpm/issues/12314).

The value is keyed by registry URL so each secret is explicitly bound to
the host that may receive it. Registry URL keys must use `http` or
`https` and must not include credentials, query strings, or fragments:

  ```sh
export
pnpm_config__auth='{"https://registry.npmjs.org":{"@&#8203;":{"authToken":"npm-token"},"@&#8203;org":{"authToken":"org-token"}}}'
  ```

  The equivalent in the global `config.yaml`:

  ```yaml
  _auth:
    https://registry.npmjs.org:
      "@&#8203;":
        authToken: npm-token
      "@&#8203;org":
        authToken: org-token
  ```

Within each registry URL, `@` means registry-wide/default credentials
and package scopes like `@org` bind credentials to that scope on the
same host. The only supported credential field is `authToken` (maps to
`_authToken` / bearer auth); the deprecated `basicAuth` / `username` +
`password` forms are intentionally not accepted here.

Each entry also infers a trusted registry route: `@` routes the default
registry (and `pnpm add <pkg>` resolves there), and `@org` routes that
scope. Because the credential and destination host arrive in one trusted
value, repo-controlled `pnpm-workspace.yaml` or project `.npmrc` cannot
redirect the token to a different host. `_auth` is honored **only** from
the env var and the global config — it is ignored in a project
`pnpm-workspace.yaml` / `.npmrc`, so repo-controlled config can never
supply registry auth. Precedence: CLI flags (`--registry`,
`--@&#8203;scope:registry`) > `pnpm_config__auth` > global `config.yaml`
`_auth` > `pnpm-workspace.yaml`.

Both `pnpm_config__auth` (lowercase, documented form) and
`PNPM_CONFIG__AUTH` (all-caps, the shell convention some CI runners
apply) are honored. If both are set, lowercase wins unless it is empty,
in which case uppercase is used. The env var wins over the global
`config.yaml` `_auth` on a conflicting key. `tokenHelper` is not
supported in `_auth`. Parsing is strict: a malformed value (bad JSON,
wrong shape, invalid registry URL or scope, an unsupported credential
field) fails fast with an error rather than being silently dropped.

**Pacquet parity note:** the pacquet (Rust) port supports the same
single credential field as the TS CLI: `authToken`.

- [`a33eeec`](https://redirect.github.com/pnpm/pnpm/commit/a33eeec):
`pnpm self-update` and `packageManager` version-switching can now
install and link pnpm v12 (the Rust port), published with equal content
under both the `pnpm` and `@pnpm/exe` names on the `next-12` dist-tag.
Its native binaries ship as `@pnpm/exe.<platform>-<arch>` packages,
which pnpm's built-in installer links directly — no Node.js launcher, so
the command pays no Node startup cost. v12 is initialized exactly like
`@pnpm/exe`, including per-platform global-virtual-store hashing. From
v12 onward the install converges on the unscoped `pnpm` package (the
Rust exe) — even when updating from the SEA `@pnpm/exe` build.

- [`1dd12bd`](https://redirect.github.com/pnpm/pnpm/commit/1dd12bd):
When resolving through a pnpr install-accelerator server, pnpm no longer
forwards its own upstream registry credentials in the resolve request.
Only the `Authorization` header identifying the caller to pnpr is sent.
The pnpr server now selects upstream credentials from its own route
policy (operator-configured upstream credential aliases), so private
dependencies resolve through a pnpr-managed alias the caller is
authorized to use, rather than by sending the client's registry tokens
to the server.

- [`1e81761`](https://redirect.github.com/pnpm/pnpm/commit/1e81761):
Expose web authentication `authUrl` and `doneUrl` in JSON error output
when OTP is required in a non-interactive terminal
[#&#8203;12724](https://redirect.github.com/pnpm/pnpm/issues/12724).

##### Patch Changes

- [`2f389d6`](https://redirect.github.com/pnpm/pnpm/commit/2f389d6):
Added the Node.js release team's new signing key (Stewart X Addison,
`655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD`) to the embedded Node.js
release keys, so runtimes whose `SHASUMS256.txt` is signed by the new
releaser verify successfully.

- [`acbdb94`](https://redirect.github.com/pnpm/pnpm/commit/acbdb94):
Fixed shell tab completion not suggesting workspaces after the `-F`
alias for `--filter` option.

- [`dcabb78`](https://redirect.github.com/pnpm/pnpm/commit/dcabb78):
Fixed `pnpm up -r <pkg>` bumping unrelated packages that have open
semver ranges. Previously, any update mutation nullified the
lockfile-derived `preferredVersions` globally, so packages with `^x.y.z`
ranges could re-resolve to newer compatible versions even though the
user only asked to update a specific package. The install layer now
always seeds `preferredVersions` from the lockfile, and caller-supplied
preferred versions (such as the vulnerability penalties of `pnpm audit
--fix`) layer on top of the seed instead of replacing it. The targeted
package still bumps: the per-resolve `updateRequested` flag makes the
resolver ignore the target's own lockfile pins.

Closes
[#&#8203;10662](https://redirect.github.com/pnpm/pnpm/issues/10662).

- [`d539172`](https://redirect.github.com/pnpm/pnpm/commit/d539172):
Fixed pnpm pack and pnpm publish failing when prepack generates files
that are included in the package and postpack cleans them up.

- [`be6505a`](https://redirect.github.com/pnpm/pnpm/commit/be6505a):
Hardened global package management:

- On Windows, removing or updating a global package now also cleans up
the `node.exe` flavor of a bin, so a stale `node.exe` no longer survives
on `PATH` after uninstall, and a new global install no longer silently
overwrites an existing `node.exe`.
- `pnpm add -g pnpm@<version>` (and `@pnpm/exe@<version>`) is now
rejected like the bare `pnpm` form, pointing to `pnpm self-update`.
- Dependency aliases read from a global package's manifest are validated
before being joined onto `node_modules` paths, preventing a tampered
manifest from escaping the install directory.
- Each global install group is created in its own freshly-made directory
(no longer reusing a colliding or pre-existing path).
- Removing or updating a global package no longer unlinks a bin that
belongs to a different globally installed package.

- [`25c7388`](https://redirect.github.com/pnpm/pnpm/commit/25c7388):
pnpm now rejects `jsr:` specifiers whose package name is not a valid npm
package name — an empty scope or name (e.g. `jsr:@&#8203;scope/`), path
separators inside the name, or any other shape
`validate-npm-package-name` rejects — with
`ERR_PNPM_INVALID_JSR_PACKAGE_NAME` instead of silently converting them
into a malformed `@jsr/...` npm package name.

- [`25c7388`](https://redirect.github.com/pnpm/pnpm/commit/25c7388):
pnpm now rejects named-registry specifiers (e.g. `gh:`) whose package
name is not a valid npm package name — an empty scope (e.g.
`gh:@&#8203;/bar`), path separators inside the name (e.g.
`gh:@&#8203;scope/../name`), or any other shape
`validate-npm-package-name` rejects — with
`ERR_PNPM_INVALID_NAMED_REGISTRY_PACKAGE_NAME` instead of passing the
name through to registry URLs and metadata cache file paths.

- [`96da7c5`](https://redirect.github.com/pnpm/pnpm/commit/96da7c5):
node-gyp's `gyp_main.py` and `gyp` entrypoints are now packed with the
executable bit in the `pnpm` and `@pnpm/exe` tarballs. Without it,
building native addons from source could fail with a permission error.

- [`99982b9`](https://redirect.github.com/pnpm/pnpm/commit/99982b9):
Sped up resolution and reduced memory use against registries that ignore
npm's abbreviated metadata format and always return the full package
document (for example, Azure DevOps Artifacts). pnpm now strips such
documents down to the abbreviated field set before caching them.
Resolution output is unchanged, and registries that honor the
abbreviated format (such as the npm registry) pay no extra cost.

- [`11a7fdd`](https://redirect.github.com/pnpm/pnpm/commit/11a7fdd):
Sped up offline and `--prefer-offline` resolution on large workspaces
(e.g. `pnpm dedupe --offline`, `pnpm install --offline`). Package
metadata loaded from the local cache is now kept in memory, so each
package's metadata is parsed once per command instead of once per
dependent that references it.

- [`2c7369d`](https://redirect.github.com/pnpm/pnpm/commit/2c7369d):
`pnpm pack-app` now rejects `--entry` / `pnpm.app.entry` and
`--output-dir` / `pnpm.app.outputDir` values that are absolute paths or
escape the project directory via `..` (or a symlink that resolves
outside it), and refuses to write the produced executable when its
target path already exists as a symlink (or other non-regular file).
This prevents a repository-controlled `package.json` from embedding host
files (such as an SSH key) into the produced executable, writing build
artifacts outside the project, or overwriting an arbitrary file through
a committed symlink. The new error codes are
`ERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT`,
`ERR_PNPM_PACK_APP_OUTPUT_DIR_OUTSIDE_PROJECT`, and
`ERR_PNPM_PACK_APP_OUTPUT_FILE_NOT_REGULAR`.

When ad-hoc signing macOS targets, `pnpm pack-app` now runs the system
`codesign` by absolute path an

> ✂ **Note**
> 
> PR body was truncated to here.


</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/sveltejs/kit).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjUuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI2NS4xIiwidGFyZ2V0QnJhbmNoIjoidmVyc2lvbi0zIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
`pnpm-workspace.yaml` ends with an `overrides` key holding only
comments, which YAML parses as `null`. pnpm ignores that, but Renovate's
schema rejects it ("expected record, received null") and discards the
whole file, so the `catalog:` entries are invisible to it. That is the
"Failed to parse pnpm-workspace.yaml file" warning in sveltejs#3256, and the
reason catalog deps stopped getting update PRs after sveltejs#15597 in March.
`{}` passes the schema (verified against
[schema.ts#L53-L67](https://github.com/renovatebot/renovate/blob/8e6a7fc2e660/lib/modules/manager/npm/schema.ts#L53-L67)),
and the CI yq step overwrites the key either way.

After this merges the non-major group also needs its "recreate" checkbox
ticked on sveltejs#3256, since Renovate suppresses the group while sveltejs#16180 stays
closed.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
…sveltejs#16403)

`normalize_param_definition` checks for a function before checking for
`~standard`, but standard schemas can themselves be callable. ArkType's
`type()` returns one, so it gets wrapped as a plain function matcher and
its own validation never runs. The wrapper then treats whatever the call
returns as the parsed value, and ArkType returns an `ArkErrors` instance
rather than throwing:

```js
const matcher = normalize_param_definition(type('string.numeric'));
matcher['~standard'].validate('not-a-number');
// { value: ArkErrors } so the route matches, with an ArkErrors instance as the param
```

Checking `~standard` first fixes this, verified against arktype 2.x
(invalid values now produce `issues`, so the route no longer matches).
It also matches `ParamEntry` in `public.d.ts`, which has resolved
callable schemas to the schema branch since sveltejs#16189. Same discriminator
fix as sveltejs#16402.

The new test fails on `version-3`.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
)

As requested in
[sveltejs#16195](sveltejs#16195 (comment)),
the missing-value check in `validate` is now `value === undefined`, so
an empty string counts as set. Also updates the `EnvVarConfig.schema`
JSDoc, which documented the old check, and adds a spec for `validate`
whose empty-string test fails without the fix.

Function validators will be a separate PR.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
…s#16400)

This PR resolves two TODOs surrounding page node configs:
1. Verified that we should return `undefined` if there are no page
`config` keys
2. Standardised the `+page.server.js` exports taking precedence over the
`+page.js` ones (this matches how we resolve all the other page options)

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
…s#16397)

closes sveltejs#14896

The `router.resolution` docs say the server "has an opportunity to
intercept each navigation (for example through a middleware)". sveltejs#14896
read that as "the `handle` hook runs", which it does not. Route
resolution requests are answered as soon as the route has been looked up
([respond.js#L323-L324](https://github.com/sveltejs/kit/blob/1406668dbc9c18928dabeff9d15ec756d6d455b3/packages/kit/src/runtime/server/respond.js#L323-L324)),
before `handle` is invoked and after `reroute` has run
([respond.js#L249](https://github.com/sveltejs/kit/blob/1406668dbc9c18928dabeff9d15ec756d6d455b3/packages/kit/src/runtime/server/respond.js#L249)).
Verified empirically in dev and in preview after a production build,
details in
sveltejs#14896 (comment).
The wording dates to sveltejs#13379, which introduced server-side route
resolution.

The new sentence is scoped to the route lookup rather than stating a
blanket "handle never runs", because there is one path where it does. A
pathname that fails to decode falls through to normal request handling
([respond.js#L272-L277](https://github.com/sveltejs/kit/blob/1406668dbc9c18928dabeff9d15ec756d6d455b3/packages/kit/src/runtime/server/respond.js#L272-L277)),
deliberate behavior from sveltejs#15744 so that malformed URLs render the
default error page. In production `GET /%c0/__route.js` therefore
reaches `handle` with pathname `/%c0` before being rejected with a 400.
Dev masks this because the dev middleware rejects malformed URIs
earlier, which sveltejs#15744 also notes.

Two changes to the option's JSDoc. "Middleware" now says what it refers
to, and a sentence states which hooks run for resolution requests.
`types/index.d.ts` regenerated.

Note on sequencing, sveltejs#16396 also touches `public.d.ts` (different lines)
and regenerates `types/index.d.ts`; whichever merges second needs a
trivial rebase and regeneration.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Nic Polumeyv <nicolas.polum@gmail.com>
…#16402)

As invited in
[sveltejs#16195](sveltejs#16195 (comment)),
`defineEnvVars` now accepts a function in place of a Standard Schema.
The contract mirrors `defineParams`: the function returns the (possibly
transformed) value, or `undefined` if the value is invalid. It can also
throw, in which case the error's message appears in the startup report,
since a bare `undefined` can't carry one.

Throwing is the only rejection path, returning any value including
`undefined` accepts it, so a function validator can describe an optional
variable without a fallback.

`defineEnvVars` normalizes functions to standard schemas, so `validate`
and the generated `env.d.ts` types are unchanged (the return type is
mapped like `DefinedParams`). Also adds the `@sveltejs/kit/env` tsconfig
paths entry that sveltejs#16378 didn't need yet.

Built on top of sveltejs#16401.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
Nic-Polumeyv and others added 26 commits August 11, 2026 12:44
version-3 lint-all is red since sveltejs#16716. The new `@sveltejs/kit/params`
module was missing from the tsconfig `paths` map, and one import still
pointed at the old location.

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
Inspired by sveltejs/svelte#18538 , this aims
for a one-to-one migration of the current config; it doesn’t enable
additonal features like jsdoc formatting, import sorting, etc.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
fixes one of the migration guide's links
 (sveltejs#16725)

`error(status, message, properties)` rejected custom optional
`App.Error` fields because the overload treated all default-compatible
error shapes as having no properties.

Fix: Enable the third argument when `App.Error` has any custom keys,
including optional ones.
- Keep the overload unavailable for the unaugmented default `App.Error`.


Fixes sveltejs#16722

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: dummdidumm <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
this hopefully fixes our release action on the version-3 branch.
minimumAgeExcludes list is ugly but it's probably fine for a short
period
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.19

### Major Changes

- breaking: move `defineParams` and associated types to
`@sveltejs/kit/params`
([sveltejs#16716](sveltejs#16716))

- breaking: run all errors through the `handleError` hook
([sveltejs#16664](sveltejs#16664))

- breaking: move `Page`, `ReadonlyURL` and `ReadonlyURLSearchParams`
from `@sveltejs/kit` to `$app/state`
([sveltejs#16694](sveltejs#16694))

- breaking: move `BeforeNavigate`, `OnNavigate`, `AfterNavigate`,
`Navigation`, `NavigationTarget`, `NavigationType`, `GotoOptions` and
the `Navigation*` variant types from `@sveltejs/kit` to
`$app/navigation` ([sveltejs#16694](sveltejs#16694))

- breaking: move `ActionResult` and `SubmitFunction` from
`@sveltejs/kit` to `$app/forms`
([sveltejs#16694](sveltejs#16694))

- breaking: remove `handleValidationError` and pass remote function
validation errors to `handleError` with `kind: 'validation'`
([sveltejs#16672](sveltejs#16672))

### Minor Changes

- feat: ignore files with + prefix if they contain test/spec/stories
([sveltejs#16715](sveltejs#16715))

### Patch Changes

- fix: rebuild the dev manifest when route files disappear during an
incremental update
([sveltejs#16643](sveltejs#16643))

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([sveltejs#16302](sveltejs#16302))

- fix: surface prerender errors during development
([sveltejs#16507](sveltejs#16507))
## @sveltejs/adapter-node@6.0.0-next.9

### Patch Changes

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([sveltejs#16302](sveltejs#16302))
- Updated dependencies
[[`04f9ab4`](sveltejs@04f9ab4),
[`1e198bd`](sveltejs@1e198bd),
[`813726d`](sveltejs@813726d),
[`a115a7b`](sveltejs@a115a7b),
[`031ac69`](sveltejs@031ac69),
[`dc7442c`](sveltejs@dc7442c),
[`19c4478`](sveltejs@19c4478),
[`dc7442c`](sveltejs@dc7442c),
[`dc7442c`](sveltejs@dc7442c),
[`0b3e2b3`](sveltejs@0b3e2b3)]:
  - @sveltejs/kit@3.0.0-next.19

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
changesets was trying to format the changelog files but we have ignored
them in the oxfmt config
https://github.com/sveltejs/kit/actions/runs/31478406211/job/93737461629#step:6:129

This PR disables the "auto-detect formatter and format" steps changesets
tries to execute. Docs here https://changesets.dev/guide/config#format
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.19

### Major Changes

- breaking: move `defineParams` and associated types to
`@sveltejs/kit/params`
([sveltejs#16716](sveltejs#16716))

- breaking: run all errors through the `handleError` hook
([sveltejs#16664](sveltejs#16664))

- breaking: move `Page`, `ReadonlyURL` and `ReadonlyURLSearchParams`
from `@sveltejs/kit` to `$app/state`
([sveltejs#16694](sveltejs#16694))

- breaking: move `BeforeNavigate`, `OnNavigate`, `AfterNavigate`,
`Navigation`, `NavigationTarget`, `NavigationType`, `GotoOptions` and
the `Navigation*` variant types from `@sveltejs/kit` to
`$app/navigation` ([sveltejs#16694](sveltejs#16694))

- breaking: move `ActionResult` and `SubmitFunction` from
`@sveltejs/kit` to `$app/forms`
([sveltejs#16694](sveltejs#16694))

- breaking: remove `handleValidationError` and pass remote function
validation errors to `handleError` with `kind: 'validation'`
([sveltejs#16672](sveltejs#16672))

### Minor Changes

- feat: ignore files with + prefix if they contain test/spec/stories
([sveltejs#16715](sveltejs#16715))

### Patch Changes

- fix: rebuild the dev manifest when route files disappear during an
incremental update
([sveltejs#16643](sveltejs#16643))

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([sveltejs#16302](sveltejs#16302))

- fix: surface prerender errors during development
([sveltejs#16507](sveltejs#16507))

- fix: adjust error overload for optional `App.Error` parameters
([sveltejs#16725](sveltejs#16725))
## @sveltejs/adapter-node@6.0.0-next.9

### Patch Changes

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([sveltejs#16302](sveltejs#16302))
- Updated dependencies
[[`04f9ab4`](sveltejs@04f9ab4),
[`1e198bd`](sveltejs@1e198bd),
[`813726d`](sveltejs@813726d),
[`a115a7b`](sveltejs@a115a7b),
[`031ac69`](sveltejs@031ac69),
[`dc7442c`](sveltejs@dc7442c),
[`19c4478`](sveltejs@19c4478),
[`dc7442c`](sveltejs@dc7442c),
[`dc7442c`](sveltejs@dc7442c),
[`0b3e2b3`](sveltejs@0b3e2b3),
[`c5d0ce2`](sveltejs@c5d0ce2)]:
  - @sveltejs/kit@3.0.0-next.19

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The build error tests are already run on linux in the `test-kit` job.
There's no need to run them again on linux with the cross-platform
firefox build job

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
fixes sveltejs#16624

Few changes were required:
- we need to correctly handle the result of `builder.build` which can
return a watcher instead of the build chunks. Added a normaliser to
handle that. Unfortunately, the bundle has to be taken from the
`generateBundle` hook.
- ignore generated files during a build when the watch mode is enabled.
Copied the config from the dev server watch config option
- move build logic into a function and re-run that in a watcher listener
since the `buildApp` hook doesn't re-run on watch
- reset variables since Vite's watch mode doesn't rerun plugin
initialisation

This only fixes the regression. There were additional existing bugs I've
listed in sveltejs#16708 but I don't think
it's a high priority to fix them now when Vite's build watch mode
support itself wasn't fully thought out

Questions:
- this remains unfixed in v2. Do we need to fix it there too?
- no test added because it seems more trouble than it's worth. That
said, it _did_ regress. I think we can add a test where we monitor the
logs of the ongoing `build --watch` process and end it if the assertions
pass? with a timeout so it doesn't go on indefinitely?
i guess this is another `oxfmt`-related thing
More harm than good as we realized; in cases where things don't go
through Vite (e.g. when esbuild bundles things) it'll break in weird
ways.
Another part of sveltejs#16676

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
not sure how it got out of sync again

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
another part of sveltejs#16676

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: teemingc <chewteeming01@gmail.com>
…#16737)

Another part of sveltejs#16676. @dummdidumm will this need changes to the
auto-injected types?

The diff is larger than it needs to be, presumably because of
formatting-related changes after switching to `oxfmt`

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
small quality of life improvement — response logging is a bit quieter,
especially when prerendering lots of stuff (as we do on svelte.dev for
example)

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.20

### Major Changes

- breaking: move remote function types to `$app/server`
([sveltejs#16740](sveltejs#16740))

- breaking: remove `#lib` definition from `paths`; requires explicit
module extensions as a result
([sveltejs#16736](sveltejs#16736))

- breaking: move hooks-related types to `@sveltejs/kit/hooks`
([sveltejs#16737](sveltejs#16737))

- breaking: move env-related types to `@sveltejs/kit/env`
([sveltejs#16739](sveltejs#16739))

### Minor Changes

- feat: better response logging
([sveltejs#16744](sveltejs#16744))

### Patch Changes

- chore: bump `mrmime` to 2.0.1
([sveltejs#16745](sveltejs#16745))

- chore: bump `@sveltejs/acorn-typescript` to 1.0.12
([sveltejs#16745](sveltejs#16745))

- chore: bump `magic-string` to 1.1.0
([sveltejs#16745](sveltejs#16745))

- chore: bump `devalue` to 5.9.0
([sveltejs#16745](sveltejs#16745))

- chore: bump `cookie` to 2.0.1
([sveltejs#16745](sveltejs#16745))

- chore: bump `acorn` to 8.18.0
([sveltejs#16745](sveltejs#16745))

- fix: avoid infinite loop when building with `--watch` flag
([sveltejs#16632](sveltejs#16632))
## @sveltejs/adapter-cloudflare@8.0.0-next.6

### Patch Changes

- chore: bump `@cloudflare/worker-types` to 5.20260809.1
([sveltejs#16745](sveltejs#16745))
- Updated dependencies
[[`1742811`](sveltejs@1742811),
[`1611c61`](sveltejs@1611c61),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`13e7b18`](sveltejs@13e7b18),
[`529346d`](sveltejs@529346d),
[`b361b81`](sveltejs@b361b81),
[`81d6319`](sveltejs@81d6319),
[`b361b81`](sveltejs@b361b81),
[`69a5bdf`](sveltejs@69a5bdf)]:
  - @sveltejs/kit@3.0.0-next.20
## @sveltejs/adapter-netlify@7.0.0-next.8

### Patch Changes

- chore: bump `rolldown` to 1.2.3
([sveltejs#16745](sveltejs#16745))
- Updated dependencies
[[`1742811`](sveltejs@1742811),
[`1611c61`](sveltejs@1611c61),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`13e7b18`](sveltejs@13e7b18),
[`529346d`](sveltejs@529346d),
[`b361b81`](sveltejs@b361b81),
[`81d6319`](sveltejs@81d6319),
[`b361b81`](sveltejs@b361b81),
[`69a5bdf`](sveltejs@69a5bdf)]:
  - @sveltejs/kit@3.0.0-next.20
## @sveltejs/adapter-node@6.0.0-next.10

### Patch Changes

- chore: bump `rolldown` to 1.2.3
([sveltejs#16745](sveltejs#16745))
- Updated dependencies
[[`1742811`](sveltejs@1742811),
[`1611c61`](sveltejs@1611c61),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`b361b81`](sveltejs@b361b81),
[`13e7b18`](sveltejs@13e7b18),
[`529346d`](sveltejs@529346d),
[`b361b81`](sveltejs@b361b81),
[`81d6319`](sveltejs@81d6319),
[`b361b81`](sveltejs@b361b81),
[`69a5bdf`](sveltejs@69a5bdf)]:
  - @sveltejs/kit@3.0.0-next.20
## @sveltejs/enhanced-img@1.0.0-next.5

### Patch Changes

- chore: bump `magic-string` to 1.1.0
([sveltejs#16745](sveltejs#16745))

- chore: bump `zimmerframe` to 1.1.4
([sveltejs#16745](sveltejs#16745))
## @sveltejs/package@3.0.0-next.6

### Patch Changes

- chore: bump `svelte2tsx` to 0.7.59
([sveltejs#16745](sveltejs#16745))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There's no reason to run all these `prepare` scripts on every `pnpm i`.
Our `check` CI action already runs `svelte-kit sync` before type
checking.

This PR removes them and ignores the `postinstall` scripts from packages
which only use them to emit warnings. Cuts 8s from `pnpm i` on my M1
Pro; ~maybe it's a little more in CI for each job~ seems to cut about 19
seconds from the install step.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
@tsushanth tsushanth reopened this Aug 12, 2026
@tsushanth

Copy link
Copy Markdown
Author

Reopening — you're right that this is still live, and I shouldn't have auto-closed a thread with active review engagement. The liveness-probe fix from the last commit should be safe for the PM2 cluster-mode case you're describing (it stats+probes the socket rather than trusting cluster.isWorker), but let me know if your repro still trips it and I'll dig further.

@tsushanth
tsushanth force-pushed the fix/16230-adapter-node-cluster-socket-deletion branch from 55c2f0c to 4a54700 Compare August 12, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

adapter-node 5.5.7: "delete existing socket file on startup" (#15449) breaks SOCKET_PATH under Node cluster / PM2 cluster mode