Commit a43bfb5bb27 for nodejs

commit a43bfb5bb27fd0338258aef1adecc0fc355c6b85
Author: npm team <ops+robot@npmjs.com>
Date:   Fri Nov 6 16:35:47 2026 -0800

    deps: upgrade npm to 12.2.2

    PR-URL: https://github.com/nodejs/node/pull/67265
    Reviewed-By: Mike McCready <66998419+MikeMcC399@users.noreply.github.com>
    Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
    Reviewed-By: Luigi Pinca <luigipinca@gmail.com>

diff --git a/deps/npm/docs/content/commands/npm-ls.md b/deps/npm/docs/content/commands/npm-ls.md
index 222e62cb8cf..7a0a37f855b 100644
--- a/deps/npm/docs/content/commands/npm-ls.md
+++ b/deps/npm/docs/content/commands/npm-ls.md
@@ -23,7 +23,7 @@ Note that nested packages will *also* show the paths to the specified packages.
 For example, running `npm ls promzard` in npm's source tree will show:

 ```bash
-npm@12.1.0 /path/to/npm
+npm@12.2.2 /path/to/npm
 └─┬ init-package-json@0.0.4
   └── promzard@0.1.5
 ```
diff --git a/deps/npm/docs/content/commands/npm-stage.md b/deps/npm/docs/content/commands/npm-stage.md
index 4228a43cce7..e4154e82b78 100644
--- a/deps/npm/docs/content/commands/npm-stage.md
+++ b/deps/npm/docs/content/commands/npm-stage.md
@@ -40,6 +40,7 @@ Key behaviors:
   version for that package.
 * You can still publish packages normally while you have staged packages
   pending.
+* Staged publishing will allow you to create a new package if it does not exist.
 * You can stage multiple versions of the same package.
 * `npm stage publish` has parity with `npm publish` and will respect
   `"private": true` in `package.json`, refusing to stage the package.
@@ -50,8 +51,6 @@ Before using `npm stage` commands, ensure the following requirements are met:

 * **Write permissions on the package:** You must have write access to the
   package you're configuring.
-* **Package must exist:** The package you're configuring must already exist
-  on the npm registry.
 * **2FA enabled on your account:** Commands that require 2FA will prompt you
   to authenticate. If you don't already have 2FA enabled on your account,
   you must enable it before using these commands.
diff --git a/deps/npm/docs/content/commands/npm.md b/deps/npm/docs/content/commands/npm.md
index e67492993a0..a8717a3a14d 100644
--- a/deps/npm/docs/content/commands/npm.md
+++ b/deps/npm/docs/content/commands/npm.md
@@ -14,7 +14,7 @@ Note: This command is unaware of workspaces.

 ### Version

-12.1.0
+12.2.2

 ### Description

diff --git a/deps/npm/docs/output/commands/npm-access.html b/deps/npm/docs/output/commands/npm-access.html
index f1145dca357..e8bc244d780 100644
--- a/deps/npm/docs/output/commands/npm-access.html
+++ b/deps/npm/docs/output/commands/npm-access.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-access----1210">
+<h1 id="----npm-access----1222">
     <span>npm-access</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Set access level on published packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-approve-scripts.html b/deps/npm/docs/output/commands/npm-approve-scripts.html
index dfa9da343fb..25de4b91fc2 100644
--- a/deps/npm/docs/output/commands/npm-approve-scripts.html
+++ b/deps/npm/docs/output/commands/npm-approve-scripts.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-approve-scripts----1210">
+<h1 id="----npm-approve-scripts----1222">
     <span>npm-approve-scripts</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Approve install scripts for specific dependencies</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-audit.html b/deps/npm/docs/output/commands/npm-audit.html
index 580a501c913..af1a3c82a9a 100644
--- a/deps/npm/docs/output/commands/npm-audit.html
+++ b/deps/npm/docs/output/commands/npm-audit.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-audit----1210">
+<h1 id="----npm-audit----1222">
     <span>npm-audit</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Run a security audit</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-bugs.html b/deps/npm/docs/output/commands/npm-bugs.html
index f5fbbb0bc50..b51e7d05a90 100644
--- a/deps/npm/docs/output/commands/npm-bugs.html
+++ b/deps/npm/docs/output/commands/npm-bugs.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-bugs----1210">
+<h1 id="----npm-bugs----1222">
     <span>npm-bugs</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Report bugs for a package in a web browser</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-cache.html b/deps/npm/docs/output/commands/npm-cache.html
index 2d30ca6fea1..1e786028ba5 100644
--- a/deps/npm/docs/output/commands/npm-cache.html
+++ b/deps/npm/docs/output/commands/npm-cache.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-cache----1210">
+<h1 id="----npm-cache----1222">
     <span>npm-cache</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manipulates packages cache</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-ci.html b/deps/npm/docs/output/commands/npm-ci.html
index ddd06430b22..5ad424ab03c 100644
--- a/deps/npm/docs/output/commands/npm-ci.html
+++ b/deps/npm/docs/output/commands/npm-ci.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-ci----1210">
+<h1 id="----npm-ci----1222">
     <span>npm-ci</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Clean install a project</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-completion.html b/deps/npm/docs/output/commands/npm-completion.html
index 09a6210f9eb..1cf6ffa7c6f 100644
--- a/deps/npm/docs/output/commands/npm-completion.html
+++ b/deps/npm/docs/output/commands/npm-completion.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-completion----1210">
+<h1 id="----npm-completion----1222">
     <span>npm-completion</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Tab Completion for npm</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-config.html b/deps/npm/docs/output/commands/npm-config.html
index 53289aa4feb..6cb35feff11 100644
--- a/deps/npm/docs/output/commands/npm-config.html
+++ b/deps/npm/docs/output/commands/npm-config.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-config----1210">
+<h1 id="----npm-config----1222">
     <span>npm-config</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage the npm configuration files</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-dedupe.html b/deps/npm/docs/output/commands/npm-dedupe.html
index 057d7f9a63c..f7e29d2ba60 100644
--- a/deps/npm/docs/output/commands/npm-dedupe.html
+++ b/deps/npm/docs/output/commands/npm-dedupe.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-dedupe----1210">
+<h1 id="----npm-dedupe----1222">
     <span>npm-dedupe</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Reduce duplication in the package tree</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-deny-scripts.html b/deps/npm/docs/output/commands/npm-deny-scripts.html
index e11a5f0283c..deb3085d2e1 100644
--- a/deps/npm/docs/output/commands/npm-deny-scripts.html
+++ b/deps/npm/docs/output/commands/npm-deny-scripts.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-deny-scripts----1210">
+<h1 id="----npm-deny-scripts----1222">
     <span>npm-deny-scripts</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Deny install scripts for specific dependencies</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-deprecate.html b/deps/npm/docs/output/commands/npm-deprecate.html
index 15df0c2668a..abd3039a41c 100644
--- a/deps/npm/docs/output/commands/npm-deprecate.html
+++ b/deps/npm/docs/output/commands/npm-deprecate.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-deprecate----1210">
+<h1 id="----npm-deprecate----1222">
     <span>npm-deprecate</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Deprecate a version of a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-diff.html b/deps/npm/docs/output/commands/npm-diff.html
index a1b38379951..801877eecd9 100644
--- a/deps/npm/docs/output/commands/npm-diff.html
+++ b/deps/npm/docs/output/commands/npm-diff.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-diff----1210">
+<h1 id="----npm-diff----1222">
     <span>npm-diff</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">The registry diff command</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-dist-tag.html b/deps/npm/docs/output/commands/npm-dist-tag.html
index 060b6745444..066ade7afb7 100644
--- a/deps/npm/docs/output/commands/npm-dist-tag.html
+++ b/deps/npm/docs/output/commands/npm-dist-tag.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-dist-tag----1210">
+<h1 id="----npm-dist-tag----1222">
     <span>npm-dist-tag</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Modify package distribution tags</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-docs.html b/deps/npm/docs/output/commands/npm-docs.html
index 561371f59c1..a799607fc29 100644
--- a/deps/npm/docs/output/commands/npm-docs.html
+++ b/deps/npm/docs/output/commands/npm-docs.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-docs----1210">
+<h1 id="----npm-docs----1222">
     <span>npm-docs</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Open documentation for a package in a web browser</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-doctor.html b/deps/npm/docs/output/commands/npm-doctor.html
index 1a2b4ee0c02..6c8a259191c 100644
--- a/deps/npm/docs/output/commands/npm-doctor.html
+++ b/deps/npm/docs/output/commands/npm-doctor.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-doctor----1210">
+<h1 id="----npm-doctor----1222">
     <span>npm-doctor</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Check the health of your npm environment</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-edit.html b/deps/npm/docs/output/commands/npm-edit.html
index 563b42bb7f3..d1d51c0425f 100644
--- a/deps/npm/docs/output/commands/npm-edit.html
+++ b/deps/npm/docs/output/commands/npm-edit.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-edit----1210">
+<h1 id="----npm-edit----1222">
     <span>npm-edit</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Edit an installed package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-exec.html b/deps/npm/docs/output/commands/npm-exec.html
index b2995a0e15a..6aed95ce18e 100644
--- a/deps/npm/docs/output/commands/npm-exec.html
+++ b/deps/npm/docs/output/commands/npm-exec.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-exec----1210">
+<h1 id="----npm-exec----1222">
     <span>npm-exec</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Run a command from a local or remote npm package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-explain.html b/deps/npm/docs/output/commands/npm-explain.html
index 7faddfe0822..602b4ecd715 100644
--- a/deps/npm/docs/output/commands/npm-explain.html
+++ b/deps/npm/docs/output/commands/npm-explain.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-explain----1210">
+<h1 id="----npm-explain----1222">
     <span>npm-explain</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Explain installed packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-explore.html b/deps/npm/docs/output/commands/npm-explore.html
index d7ece3306b0..e0aed4e1fa5 100644
--- a/deps/npm/docs/output/commands/npm-explore.html
+++ b/deps/npm/docs/output/commands/npm-explore.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-explore----1210">
+<h1 id="----npm-explore----1222">
     <span>npm-explore</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Browse an installed package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-find-dupes.html b/deps/npm/docs/output/commands/npm-find-dupes.html
index 92666ec12dc..1544c271508 100644
--- a/deps/npm/docs/output/commands/npm-find-dupes.html
+++ b/deps/npm/docs/output/commands/npm-find-dupes.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-find-dupes----1210">
+<h1 id="----npm-find-dupes----1222">
     <span>npm-find-dupes</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Find duplication in the package tree</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-fund.html b/deps/npm/docs/output/commands/npm-fund.html
index 9d6d709b5fc..78b38fd33cb 100644
--- a/deps/npm/docs/output/commands/npm-fund.html
+++ b/deps/npm/docs/output/commands/npm-fund.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-fund----1210">
+<h1 id="----npm-fund----1222">
     <span>npm-fund</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Retrieve funding information</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-get.html b/deps/npm/docs/output/commands/npm-get.html
index 673a11ba40e..a56684a1b2c 100644
--- a/deps/npm/docs/output/commands/npm-get.html
+++ b/deps/npm/docs/output/commands/npm-get.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-get----1210">
+<h1 id="----npm-get----1222">
     <span>npm-get</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Get a value from the npm configuration</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-help-search.html b/deps/npm/docs/output/commands/npm-help-search.html
index 9d9d013eaf2..7b8dc4930ad 100644
--- a/deps/npm/docs/output/commands/npm-help-search.html
+++ b/deps/npm/docs/output/commands/npm-help-search.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-help-search----1210">
+<h1 id="----npm-help-search----1222">
     <span>npm-help-search</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Search npm help documentation</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-help.html b/deps/npm/docs/output/commands/npm-help.html
index 60ed1a93011..63a2f3a65ac 100644
--- a/deps/npm/docs/output/commands/npm-help.html
+++ b/deps/npm/docs/output/commands/npm-help.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-help----1210">
+<h1 id="----npm-help----1222">
     <span>npm-help</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Get help on npm</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-init.html b/deps/npm/docs/output/commands/npm-init.html
index bf0036a128d..592eef7a233 100644
--- a/deps/npm/docs/output/commands/npm-init.html
+++ b/deps/npm/docs/output/commands/npm-init.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-init----1210">
+<h1 id="----npm-init----1222">
     <span>npm-init</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Create a package.json file</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-install-ci-test.html b/deps/npm/docs/output/commands/npm-install-ci-test.html
index 0c575108842..7cfe3a02120 100644
--- a/deps/npm/docs/output/commands/npm-install-ci-test.html
+++ b/deps/npm/docs/output/commands/npm-install-ci-test.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-install-ci-test----1210">
+<h1 id="----npm-install-ci-test----1222">
     <span>npm-install-ci-test</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Install a project with a clean slate and run tests</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-install-scripts.html b/deps/npm/docs/output/commands/npm-install-scripts.html
index 5060355e377..03e65461f59 100644
--- a/deps/npm/docs/output/commands/npm-install-scripts.html
+++ b/deps/npm/docs/output/commands/npm-install-scripts.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-install-scripts----1210">
+<h1 id="----npm-install-scripts----1222">
     <span>npm-install-scripts</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage install-script approvals for dependencies</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-install-test.html b/deps/npm/docs/output/commands/npm-install-test.html
index 119d6f406c8..81f401fb63e 100644
--- a/deps/npm/docs/output/commands/npm-install-test.html
+++ b/deps/npm/docs/output/commands/npm-install-test.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-install-test----1210">
+<h1 id="----npm-install-test----1222">
     <span>npm-install-test</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Install package(s) and run tests</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-install.html b/deps/npm/docs/output/commands/npm-install.html
index cb348fd03d8..f8debaf29c7 100644
--- a/deps/npm/docs/output/commands/npm-install.html
+++ b/deps/npm/docs/output/commands/npm-install.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-install----1210">
+<h1 id="----npm-install----1222">
     <span>npm-install</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Install a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-link.html b/deps/npm/docs/output/commands/npm-link.html
index 14648f939fd..bd5868e09b5 100644
--- a/deps/npm/docs/output/commands/npm-link.html
+++ b/deps/npm/docs/output/commands/npm-link.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-link----1210">
+<h1 id="----npm-link----1222">
     <span>npm-link</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Symlink a package folder</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-ll.html b/deps/npm/docs/output/commands/npm-ll.html
index edaa98e8843..f52019a5dd1 100644
--- a/deps/npm/docs/output/commands/npm-ll.html
+++ b/deps/npm/docs/output/commands/npm-ll.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-ll----1210">
+<h1 id="----npm-ll----1222">
     <span>npm-ll</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">List installed packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-login.html b/deps/npm/docs/output/commands/npm-login.html
index 30dca5d0862..11acf310b47 100644
--- a/deps/npm/docs/output/commands/npm-login.html
+++ b/deps/npm/docs/output/commands/npm-login.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-login----1210">
+<h1 id="----npm-login----1222">
     <span>npm-login</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Login to a registry user account</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-logout.html b/deps/npm/docs/output/commands/npm-logout.html
index b88deae7077..464313e2adb 100644
--- a/deps/npm/docs/output/commands/npm-logout.html
+++ b/deps/npm/docs/output/commands/npm-logout.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-logout----1210">
+<h1 id="----npm-logout----1222">
     <span>npm-logout</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Log out of the registry</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html
index 4b65c5e8636..a8a8831640c 100644
--- a/deps/npm/docs/output/commands/npm-ls.html
+++ b/deps/npm/docs/output/commands/npm-ls.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-ls----1210">
+<h1 id="----npm-ls----1222">
     <span>npm-ls</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">List installed packages</span>
 </header>
@@ -209,7 +209,7 @@ alias: list
 <p>Positional arguments are <code>name@version-range</code> identifiers, which will limit the results to only the paths to the packages named.
 Note that nested packages will <em>also</em> show the paths to the specified packages.
 For example, running <code>npm ls promzard</code> in npm's source tree will show:</p>
-<pre><code class="language-bash">npm@12.1.0 /path/to/npm
+<pre><code class="language-bash">npm@12.2.2 /path/to/npm
 └─┬ init-package-json@0.0.4
   └── promzard@0.1.5
 </code></pre>
diff --git a/deps/npm/docs/output/commands/npm-org.html b/deps/npm/docs/output/commands/npm-org.html
index 075e12018f8..99cb4339b16 100644
--- a/deps/npm/docs/output/commands/npm-org.html
+++ b/deps/npm/docs/output/commands/npm-org.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-org----1210">
+<h1 id="----npm-org----1222">
     <span>npm-org</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage orgs</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-outdated.html b/deps/npm/docs/output/commands/npm-outdated.html
index a3045a6ec76..613b24e8bd6 100644
--- a/deps/npm/docs/output/commands/npm-outdated.html
+++ b/deps/npm/docs/output/commands/npm-outdated.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-outdated----1210">
+<h1 id="----npm-outdated----1222">
     <span>npm-outdated</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Check for outdated packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-owner.html b/deps/npm/docs/output/commands/npm-owner.html
index 6f2220a9d7e..9af22b69a86 100644
--- a/deps/npm/docs/output/commands/npm-owner.html
+++ b/deps/npm/docs/output/commands/npm-owner.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-owner----1210">
+<h1 id="----npm-owner----1222">
     <span>npm-owner</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage package owners</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-pack.html b/deps/npm/docs/output/commands/npm-pack.html
index a58f0d925bf..c970b43b5bb 100644
--- a/deps/npm/docs/output/commands/npm-pack.html
+++ b/deps/npm/docs/output/commands/npm-pack.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-pack----1210">
+<h1 id="----npm-pack----1222">
     <span>npm-pack</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Create a tarball from a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-patch.html b/deps/npm/docs/output/commands/npm-patch.html
index 37e99ca958f..95f8ca03ed3 100644
--- a/deps/npm/docs/output/commands/npm-patch.html
+++ b/deps/npm/docs/output/commands/npm-patch.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-patch----1210">
+<h1 id="----npm-patch----1222">
     <span>npm-patch</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Apply local patches to installed dependencies</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-ping.html b/deps/npm/docs/output/commands/npm-ping.html
index cd16085a33f..2eb84b18721 100644
--- a/deps/npm/docs/output/commands/npm-ping.html
+++ b/deps/npm/docs/output/commands/npm-ping.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-ping----1210">
+<h1 id="----npm-ping----1222">
     <span>npm-ping</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Ping npm registry</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-pkg.html b/deps/npm/docs/output/commands/npm-pkg.html
index c0370531f9e..4e0e78e8a0d 100644
--- a/deps/npm/docs/output/commands/npm-pkg.html
+++ b/deps/npm/docs/output/commands/npm-pkg.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-pkg----1210">
+<h1 id="----npm-pkg----1222">
     <span>npm-pkg</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manages your package.json</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-prefix.html b/deps/npm/docs/output/commands/npm-prefix.html
index be2b1f263c5..4754a80148c 100644
--- a/deps/npm/docs/output/commands/npm-prefix.html
+++ b/deps/npm/docs/output/commands/npm-prefix.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-prefix----1210">
+<h1 id="----npm-prefix----1222">
     <span>npm-prefix</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Display prefix</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-profile.html b/deps/npm/docs/output/commands/npm-profile.html
index 9965a851aec..a04049fa44b 100644
--- a/deps/npm/docs/output/commands/npm-profile.html
+++ b/deps/npm/docs/output/commands/npm-profile.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-profile----1210">
+<h1 id="----npm-profile----1222">
     <span>npm-profile</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Change settings on your registry profile</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-prune.html b/deps/npm/docs/output/commands/npm-prune.html
index 2a029255b86..8a5965e94fe 100644
--- a/deps/npm/docs/output/commands/npm-prune.html
+++ b/deps/npm/docs/output/commands/npm-prune.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-prune----1210">
+<h1 id="----npm-prune----1222">
     <span>npm-prune</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Remove extraneous packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-publish.html b/deps/npm/docs/output/commands/npm-publish.html
index 5669c4329d4..850f8ea16f8 100644
--- a/deps/npm/docs/output/commands/npm-publish.html
+++ b/deps/npm/docs/output/commands/npm-publish.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-publish----1210">
+<h1 id="----npm-publish----1222">
     <span>npm-publish</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Publish a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-query.html b/deps/npm/docs/output/commands/npm-query.html
index 1cc69249ccd..fc702828c7d 100644
--- a/deps/npm/docs/output/commands/npm-query.html
+++ b/deps/npm/docs/output/commands/npm-query.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-query----1210">
+<h1 id="----npm-query----1222">
     <span>npm-query</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Dependency selector query</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-rebuild.html b/deps/npm/docs/output/commands/npm-rebuild.html
index 6752812a8b6..a37087eee82 100644
--- a/deps/npm/docs/output/commands/npm-rebuild.html
+++ b/deps/npm/docs/output/commands/npm-rebuild.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-rebuild----1210">
+<h1 id="----npm-rebuild----1222">
     <span>npm-rebuild</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Rebuild a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-repo.html b/deps/npm/docs/output/commands/npm-repo.html
index 9cc209cdb62..02f51b1f96a 100644
--- a/deps/npm/docs/output/commands/npm-repo.html
+++ b/deps/npm/docs/output/commands/npm-repo.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-repo----1210">
+<h1 id="----npm-repo----1222">
     <span>npm-repo</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Open package repository page in the browser</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-restart.html b/deps/npm/docs/output/commands/npm-restart.html
index cf71fecbd44..62d66243bb6 100644
--- a/deps/npm/docs/output/commands/npm-restart.html
+++ b/deps/npm/docs/output/commands/npm-restart.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-restart----1210">
+<h1 id="----npm-restart----1222">
     <span>npm-restart</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Restart a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-root.html b/deps/npm/docs/output/commands/npm-root.html
index c347f124e45..791f77c7a1d 100644
--- a/deps/npm/docs/output/commands/npm-root.html
+++ b/deps/npm/docs/output/commands/npm-root.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-root----1210">
+<h1 id="----npm-root----1222">
     <span>npm-root</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Display npm root</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-run.html b/deps/npm/docs/output/commands/npm-run.html
index c0cc6c4102d..4a893229f5f 100644
--- a/deps/npm/docs/output/commands/npm-run.html
+++ b/deps/npm/docs/output/commands/npm-run.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-run----1210">
+<h1 id="----npm-run----1222">
     <span>npm-run</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Run arbitrary package scripts</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-sbom.html b/deps/npm/docs/output/commands/npm-sbom.html
index fa5f951401c..4b740785316 100644
--- a/deps/npm/docs/output/commands/npm-sbom.html
+++ b/deps/npm/docs/output/commands/npm-sbom.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-sbom----1210">
+<h1 id="----npm-sbom----1222">
     <span>npm-sbom</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Generate a Software Bill of Materials (SBOM)</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-search.html b/deps/npm/docs/output/commands/npm-search.html
index 3c1bdd66f9e..e812a0e6287 100644
--- a/deps/npm/docs/output/commands/npm-search.html
+++ b/deps/npm/docs/output/commands/npm-search.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-search----1210">
+<h1 id="----npm-search----1222">
     <span>npm-search</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Search for packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-set.html b/deps/npm/docs/output/commands/npm-set.html
index c3e4d258187..d980e7d7bd1 100644
--- a/deps/npm/docs/output/commands/npm-set.html
+++ b/deps/npm/docs/output/commands/npm-set.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-set----1210">
+<h1 id="----npm-set----1222">
     <span>npm-set</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Set a value in the npm configuration</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-stage.html b/deps/npm/docs/output/commands/npm-stage.html
index f127dbea3b9..af9b075b529 100644
--- a/deps/npm/docs/output/commands/npm-stage.html
+++ b/deps/npm/docs/output/commands/npm-stage.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-stage----1210">
+<h1 id="----npm-stage----1222">
     <span>npm-stage</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Stage packages for publishing</span>
 </header>
@@ -226,6 +226,7 @@ packages — you cannot publish a version that already exists as a staged
 version for that package.</li>
 <li>You can still publish packages normally while you have staged packages
 pending.</li>
+<li>Staged publishing will allow you to create a new package if it does not exist.</li>
 <li>You can stage multiple versions of the same package.</li>
 <li><code>npm stage publish</code> has parity with <code>npm publish</code> and will respect
 <code>"private": true</code> in <code>package.json</code>, refusing to stage the package.</li>
@@ -235,8 +236,6 @@ pending.</li>
 <ul>
 <li><strong>Write permissions on the package:</strong> You must have write access to the
 package you're configuring.</li>
-<li><strong>Package must exist:</strong> The package you're configuring must already exist
-on the npm registry.</li>
 <li><strong>2FA enabled on your account:</strong> Commands that require 2FA will prompt you
 to authenticate. If you don't already have 2FA enabled on your account,
 you must enable it before using these commands.</li>
diff --git a/deps/npm/docs/output/commands/npm-start.html b/deps/npm/docs/output/commands/npm-start.html
index 4a2ea8acc75..77de290c499 100644
--- a/deps/npm/docs/output/commands/npm-start.html
+++ b/deps/npm/docs/output/commands/npm-start.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-start----1210">
+<h1 id="----npm-start----1222">
     <span>npm-start</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Start a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-stop.html b/deps/npm/docs/output/commands/npm-stop.html
index 4af840d6c4d..3054cf5502c 100644
--- a/deps/npm/docs/output/commands/npm-stop.html
+++ b/deps/npm/docs/output/commands/npm-stop.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-stop----1210">
+<h1 id="----npm-stop----1222">
     <span>npm-stop</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Stop a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-team.html b/deps/npm/docs/output/commands/npm-team.html
index d9234d26591..8b2f9e77434 100644
--- a/deps/npm/docs/output/commands/npm-team.html
+++ b/deps/npm/docs/output/commands/npm-team.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-team----1210">
+<h1 id="----npm-team----1222">
     <span>npm-team</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage organization teams and team memberships</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-test.html b/deps/npm/docs/output/commands/npm-test.html
index 56d5f356abe..88b28fc373c 100644
--- a/deps/npm/docs/output/commands/npm-test.html
+++ b/deps/npm/docs/output/commands/npm-test.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-test----1210">
+<h1 id="----npm-test----1222">
     <span>npm-test</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Test a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-token.html b/deps/npm/docs/output/commands/npm-token.html
index 8aa1c136181..7b939a21559 100644
--- a/deps/npm/docs/output/commands/npm-token.html
+++ b/deps/npm/docs/output/commands/npm-token.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-token----1210">
+<h1 id="----npm-token----1222">
     <span>npm-token</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage your authentication tokens</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-trust.html b/deps/npm/docs/output/commands/npm-trust.html
index 3ddacb29564..707ed794b10 100644
--- a/deps/npm/docs/output/commands/npm-trust.html
+++ b/deps/npm/docs/output/commands/npm-trust.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-trust----1210">
+<h1 id="----npm-trust----1222">
     <span>npm-trust</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Manage trusted publishing relationships between packages and CI/CD providers</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-undeprecate.html b/deps/npm/docs/output/commands/npm-undeprecate.html
index ce42db0b19b..1b35b155ec1 100644
--- a/deps/npm/docs/output/commands/npm-undeprecate.html
+++ b/deps/npm/docs/output/commands/npm-undeprecate.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-undeprecate----1210">
+<h1 id="----npm-undeprecate----1222">
     <span>npm-undeprecate</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Undeprecate a version of a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-uninstall.html b/deps/npm/docs/output/commands/npm-uninstall.html
index 4a67748cb04..dcb9c30a4d7 100644
--- a/deps/npm/docs/output/commands/npm-uninstall.html
+++ b/deps/npm/docs/output/commands/npm-uninstall.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-uninstall----1210">
+<h1 id="----npm-uninstall----1222">
     <span>npm-uninstall</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Remove a package</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-unpublish.html b/deps/npm/docs/output/commands/npm-unpublish.html
index 8c53acd5dd4..52fc59ffb7a 100644
--- a/deps/npm/docs/output/commands/npm-unpublish.html
+++ b/deps/npm/docs/output/commands/npm-unpublish.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-unpublish----1210">
+<h1 id="----npm-unpublish----1222">
     <span>npm-unpublish</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Remove a package from the registry</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-update.html b/deps/npm/docs/output/commands/npm-update.html
index db6463c2b47..43c33121620 100644
--- a/deps/npm/docs/output/commands/npm-update.html
+++ b/deps/npm/docs/output/commands/npm-update.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-update----1210">
+<h1 id="----npm-update----1222">
     <span>npm-update</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Update packages</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-version.html b/deps/npm/docs/output/commands/npm-version.html
index 3afedb515df..6062c22b56e 100644
--- a/deps/npm/docs/output/commands/npm-version.html
+++ b/deps/npm/docs/output/commands/npm-version.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-version----1210">
+<h1 id="----npm-version----1222">
     <span>npm-version</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Bump a package version</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-view.html b/deps/npm/docs/output/commands/npm-view.html
index 6507648475c..1d80c87ab45 100644
--- a/deps/npm/docs/output/commands/npm-view.html
+++ b/deps/npm/docs/output/commands/npm-view.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-view----1210">
+<h1 id="----npm-view----1222">
     <span>npm-view</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">View registry info</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm-whoami.html b/deps/npm/docs/output/commands/npm-whoami.html
index 0f6128a5abe..03727c5291d 100644
--- a/deps/npm/docs/output/commands/npm-whoami.html
+++ b/deps/npm/docs/output/commands/npm-whoami.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-whoami----1210">
+<h1 id="----npm-whoami----1222">
     <span>npm-whoami</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Display npm username</span>
 </header>
diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html
index f2c1114e3b5..798e831ae48 100644
--- a/deps/npm/docs/output/commands/npm.html
+++ b/deps/npm/docs/output/commands/npm.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm----1210">
+<h1 id="----npm----1222">
     <span>npm</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">javascript package manager</span>
 </header>
@@ -203,7 +203,7 @@ npm command-line interface
 </code></pre>
 <p>Note: This command is unaware of workspaces.</p>
 <h3 id="version">Version</h3>
-<p>12.1.0</p>
+<p>12.2.2</p>
 <h3 id="description">Description</h3>
 <p>npm is the package manager for the Node JavaScript platform.
 It puts modules in place so that node can find them, and manages dependency conflicts intelligently.</p>
diff --git a/deps/npm/docs/output/commands/npx.html b/deps/npm/docs/output/commands/npx.html
index ad3401fc1f5..d72a03612b8 100644
--- a/deps/npm/docs/output/commands/npx.html
+++ b/deps/npm/docs/output/commands/npx.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npx----1210">
+<h1 id="----npx----1222">
     <span>npx</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Run a command from a local or remote npm package</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/folders.html b/deps/npm/docs/output/configuring-npm/folders.html
index 16ec237c7cf..32236027996 100644
--- a/deps/npm/docs/output/configuring-npm/folders.html
+++ b/deps/npm/docs/output/configuring-npm/folders.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----folders----1210">
+<h1 id="----folders----1222">
     <span>Folders</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Folder structures used by npm</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/install.html b/deps/npm/docs/output/configuring-npm/install.html
index 7fc1b0835af..fda1dbc96d4 100644
--- a/deps/npm/docs/output/configuring-npm/install.html
+++ b/deps/npm/docs/output/configuring-npm/install.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----install----1210">
+<h1 id="----install----1222">
     <span>Install</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Download and install node and npm</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/npm-extension.html b/deps/npm/docs/output/configuring-npm/npm-extension.html
index 477d79a1651..7de5b85b562 100644
--- a/deps/npm/docs/output/configuring-npm/npm-extension.html
+++ b/deps/npm/docs/output/configuring-npm/npm-extension.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npm-extension----1210">
+<h1 id="----npm-extension----1222">
     <span>.npm-extension</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Imperative, root-owned manifest repairs</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/npm-global.html b/deps/npm/docs/output/configuring-npm/npm-global.html
index 16ec237c7cf..32236027996 100644
--- a/deps/npm/docs/output/configuring-npm/npm-global.html
+++ b/deps/npm/docs/output/configuring-npm/npm-global.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----folders----1210">
+<h1 id="----folders----1222">
     <span>Folders</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Folder structures used by npm</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/npm-json.html b/deps/npm/docs/output/configuring-npm/npm-json.html
index 148a01c926b..bd54796a986 100644
--- a/deps/npm/docs/output/configuring-npm/npm-json.html
+++ b/deps/npm/docs/output/configuring-npm/npm-json.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----packagejson----1210">
+<h1 id="----packagejson----1222">
     <span>package.json</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Specifics of npm's package.json handling</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/npmrc.html b/deps/npm/docs/output/configuring-npm/npmrc.html
index 5ac70ba1ba7..7a8494a8e2b 100644
--- a/deps/npm/docs/output/configuring-npm/npmrc.html
+++ b/deps/npm/docs/output/configuring-npm/npmrc.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----npmrc----1210">
+<h1 id="----npmrc----1222">
     <span>.npmrc</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">The npm config files</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/package-json.html b/deps/npm/docs/output/configuring-npm/package-json.html
index 148a01c926b..bd54796a986 100644
--- a/deps/npm/docs/output/configuring-npm/package-json.html
+++ b/deps/npm/docs/output/configuring-npm/package-json.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----packagejson----1210">
+<h1 id="----packagejson----1222">
     <span>package.json</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Specifics of npm's package.json handling</span>
 </header>
diff --git a/deps/npm/docs/output/configuring-npm/package-lock-json.html b/deps/npm/docs/output/configuring-npm/package-lock-json.html
index 487bc1eef8f..d5464d7c276 100644
--- a/deps/npm/docs/output/configuring-npm/package-lock-json.html
+++ b/deps/npm/docs/output/configuring-npm/package-lock-json.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----package-lockjson----1210">
+<h1 id="----package-lockjson----1222">
     <span>package-lock.json</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">A manifestation of the manifest</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/config.html b/deps/npm/docs/output/using-npm/config.html
index d95fa275dff..df5cf69f13b 100644
--- a/deps/npm/docs/output/using-npm/config.html
+++ b/deps/npm/docs/output/using-npm/config.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----config----1210">
+<h1 id="----config----1222">
     <span>Config</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">About npm configuration</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/dependency-selectors.html b/deps/npm/docs/output/using-npm/dependency-selectors.html
index fd33213840f..7dc55a54dae 100644
--- a/deps/npm/docs/output/using-npm/dependency-selectors.html
+++ b/deps/npm/docs/output/using-npm/dependency-selectors.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----dependency-selectors----1210">
+<h1 id="----dependency-selectors----1222">
     <span>Dependency Selectors</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Dependency Selector Syntax &amp; Querying</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/developers.html b/deps/npm/docs/output/using-npm/developers.html
index 3c262b7d975..c89c0dcbf93 100644
--- a/deps/npm/docs/output/using-npm/developers.html
+++ b/deps/npm/docs/output/using-npm/developers.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----developers----1210">
+<h1 id="----developers----1222">
     <span>Developers</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Developer guide</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/logging.html b/deps/npm/docs/output/using-npm/logging.html
index 29a4b046477..352752b2507 100644
--- a/deps/npm/docs/output/using-npm/logging.html
+++ b/deps/npm/docs/output/using-npm/logging.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----logging----1210">
+<h1 id="----logging----1222">
     <span>Logging</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Why, What &amp; How we Log</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/orgs.html b/deps/npm/docs/output/using-npm/orgs.html
index ac10041d0e7..26ee0603d67 100644
--- a/deps/npm/docs/output/using-npm/orgs.html
+++ b/deps/npm/docs/output/using-npm/orgs.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----organizations----1210">
+<h1 id="----organizations----1222">
     <span>Organizations</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Working with teams &amp; organizations</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/package-spec.html b/deps/npm/docs/output/using-npm/package-spec.html
index 6b414770b89..e25f71a8e1e 100644
--- a/deps/npm/docs/output/using-npm/package-spec.html
+++ b/deps/npm/docs/output/using-npm/package-spec.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----package-spec----1210">
+<h1 id="----package-spec----1222">
     <span>Package spec</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Package name specifier</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/registry.html b/deps/npm/docs/output/using-npm/registry.html
index 11050d44bf8..3139f4ea305 100644
--- a/deps/npm/docs/output/using-npm/registry.html
+++ b/deps/npm/docs/output/using-npm/registry.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----registry----1210">
+<h1 id="----registry----1222">
     <span>Registry</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">The JavaScript Package Registry</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/removal.html b/deps/npm/docs/output/using-npm/removal.html
index 3f26061b997..b11487ded28 100644
--- a/deps/npm/docs/output/using-npm/removal.html
+++ b/deps/npm/docs/output/using-npm/removal.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----removal----1210">
+<h1 id="----removal----1222">
     <span>Removal</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Cleaning the slate</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/scope.html b/deps/npm/docs/output/using-npm/scope.html
index 548495818de..684642f50a7 100644
--- a/deps/npm/docs/output/using-npm/scope.html
+++ b/deps/npm/docs/output/using-npm/scope.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----scope----1210">
+<h1 id="----scope----1222">
     <span>Scope</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Scoped packages</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html
index f0a3b967dc3..cb78e8f079c 100644
--- a/deps/npm/docs/output/using-npm/scripts.html
+++ b/deps/npm/docs/output/using-npm/scripts.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----scripts----1210">
+<h1 id="----scripts----1222">
     <span>Scripts</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">How npm handles the "scripts" field</span>
 </header>
diff --git a/deps/npm/docs/output/using-npm/workspaces.html b/deps/npm/docs/output/using-npm/workspaces.html
index 048ee835c87..b34d4b7e98a 100644
--- a/deps/npm/docs/output/using-npm/workspaces.html
+++ b/deps/npm/docs/output/using-npm/workspaces.html
@@ -186,9 +186,9 @@ npm command-line interface

 <section id="content">
 <header class="title">
-<h1 id="----workspaces----1210">
+<h1 id="----workspaces----1222">
     <span>Workspaces</span>
-    <span class="version">@12.1.0</span>
+    <span class="version">@12.2.2</span>
 </h1>
 <span class="description">Working with workspaces</span>
 </header>
diff --git a/deps/npm/lib/cli/entry.js b/deps/npm/lib/cli/entry.js
index 962c62a5766..fb15683f48e 100644
--- a/deps/npm/lib/cli/entry.js
+++ b/deps/npm/lib/cli/entry.js
@@ -26,7 +26,7 @@ module.exports = async (process, validateEngines) => {

   // It is now safe to log a warning if they are using a version of node that is not going to fail on syntax errors but is still unsupported and untested and might not work reliably.
   // This is safe to use the logger now which we want since this will show up in the error log too.
-  if (!satisfies(validateEngines.node, validateEngines.engines)) {
+  if (!satisfies(validateEngines.node, validateEngines.engines, { includePrerelease: true })) {
     log.warn('cli', validateEngines.unsupportedMessage)
   }

diff --git a/deps/npm/lib/commands/dist-tag.js b/deps/npm/lib/commands/dist-tag.js
index 4b51e839d78..fe4b4c8e809 100644
--- a/deps/npm/lib/commands/dist-tag.js
+++ b/deps/npm/lib/commands/dist-tag.js
@@ -3,6 +3,7 @@ const npmFetch = require('npm-registry-fetch')
 const semver = require('semver')
 const { log, output } = require('proc-log')
 const { otplease } = require('../utils/auth.js')
+const { oidc } = require('../utils/oidc.js')
 const pkgJson = require('@npmcli/package-json')
 const BaseCommand = require('../base-cmd.js')

@@ -101,6 +102,7 @@ class DistTag extends BaseCommand {
       throw new Error('Tag name must not be a valid SemVer range: ' + t)
     }

+    await this.#oidc(spec, opts)
     const tags = await this.fetchTags(spec, opts)
     if (tags[t] === version) {
       log.warn('dist-tag add', t, 'is already set to version', version)
@@ -130,6 +132,7 @@ class DistTag extends BaseCommand {
       throw this.usageError()
     }

+    await this.#oidc(spec, opts)
     const tags = await this.fetchTags(spec, opts)
     if (!tags[tag]) {
       log.info('dist-tag del', tag, 'is not a dist-tag on', spec.name)
@@ -163,6 +166,7 @@ class DistTag extends BaseCommand {
     spec = npa(spec)

     try {
+      await this.#oidc(spec, opts)
       const tags = await this.fetchTags(spec, opts)
       const msg =
         Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n')
@@ -202,6 +206,16 @@ class DistTag extends BaseCommand {

     return data
   }
+
+  async #oidc (spec, opts) {
+    const registry = npmFetch.pickRegistry(spec, opts)
+    await oidc({
+      packageName: spec.name,
+      registry,
+      opts,
+      config: this.npm.config,
+    })
+  }
 }

 module.exports = DistTag
diff --git a/deps/npm/lib/commands/patch.js b/deps/npm/lib/commands/patch.js
index 67b8bc45555..b8960a2d35c 100644
--- a/deps/npm/lib/commands/patch.js
+++ b/deps/npm/lib/commands/patch.js
@@ -408,7 +408,7 @@ class Patch extends BaseCommand {
         pkgJson, patched, entry, name: entry.name, newVersion, newKey, diff, installedVersions,
       })
     } finally {
-      await rm(rebase.work, { recursive: true, force: true })
+      await this.#removeWork(rebase.work)
     }
   }

@@ -561,13 +561,24 @@ class Patch extends BaseCommand {
       }
       return { work, repo, newDir, conflicted }
     } catch (er) {
-      await rm(work, { recursive: true, force: true })
+      await this.#removeWork(work)
       throw er
     }
   }

+  // Remove the throwaway rebase workdir.
+  // Retries because git can briefly hold files there, and never throws so a cleanup failure cannot mask the real error.
+  async #removeWork (work) {
+    try {
+      await rm(work, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 })
+    } catch (er) {
+      log.verbose('patch', `could not remove ${work}: ${er.message}`)
+    }
+  }
+
   #git (args, cwd) {
-    return git.spawn(args, {
+    // The throwaway repo never needs maintenance and a detached auto-gc would race the workdir cleanup.
+    return git.spawn(['-c', 'gc.auto=0', '-c', 'maintenance.auto=false', ...args], {
       cwd,
       env: { ...process.env, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null' },
     })
diff --git a/deps/npm/lib/commands/publish.js b/deps/npm/lib/commands/publish.js
index f13bc026f32..a18b6f0c81b 100644
--- a/deps/npm/lib/commands/publish.js
+++ b/deps/npm/lib/commands/publish.js
@@ -149,7 +149,13 @@ class Publish extends BaseCommand {

     const registry = npmFetch.pickRegistry(resolved, opts)

-    await oidc({ packageName: manifest.name, registry, opts, config: this.npm.config })
+    await oidc({
+      packageName: manifest.name,
+      registry,
+      opts,
+      config: this.npm.config,
+      enableProvenanceAutoConfiguration: true,
+    })

     const creds = this.npm.config.getCredentialsByURI(registry)
     const noCreds = !(creds.token || creds.username || creds.certfile && creds.keyfile)
diff --git a/deps/npm/lib/utils/allow-scripts-cmd.js b/deps/npm/lib/utils/allow-scripts-cmd.js
index f07dc8d1dc5..9292d5e6df9 100644
--- a/deps/npm/lib/utils/allow-scripts-cmd.js
+++ b/deps/npm/lib/utils/allow-scripts-cmd.js
@@ -221,15 +221,13 @@ class AllowScriptsCmd extends BaseCommand {
     // edge name. A version or range on the arg narrows the match to installed
     // versions that satisfy it. Bundled deps are excluded for the same reason
     // as --all. Args that match nothing are returned in `unmatched`.
+    // Links stay matchable by their edge name (e.g. `foo` -> `file:./local-foo`), but each match is dereferenced to its target and deduplicated, since scripts only run on the target and keying policy off a Link's resolved spec writes store paths under install-strategy=linked (npm/cli#9939).
     const matched = []
     const unmatched = []
     for (const arg of args) {
       const { name: wantName, range } = parsePositional(arg)
-      const found = []
+      const found = new Set()
       for (const node of arb.actualTree.inventory.values()) {
-        if (node.isProjectRoot || node.isWorkspace || node.inBundle) {
-          continue
-        }
         const { name, version } = trustedDisplay(node)
         if (!name || name !== wantName) {
           continue
@@ -237,9 +235,13 @@ class AllowScriptsCmd extends BaseCommand {
         if (range && (!version || !semver.satisfies(version, range, { loose: true }))) {
           continue
         }
-        found.push(node)
+        const target = node.isLink ? node.target : node
+        if (!target || target.isProjectRoot || target.isWorkspace || target.inBundle) {
+          continue
+        }
+        found.add(target)
       }
-      if (found.length === 0) {
+      if (found.size === 0) {
         unmatched.push(arg)
       } else {
         matched.push(...found)
diff --git a/deps/npm/lib/utils/allow-scripts-prune.js b/deps/npm/lib/utils/allow-scripts-prune.js
index 1111b45d9ca..264ad6dcc96 100644
--- a/deps/npm/lib/utils/allow-scripts-prune.js
+++ b/deps/npm/lib/utils/allow-scripts-prune.js
@@ -29,7 +29,8 @@ const classifyUnusedEntries = (allowScripts, nodes) => {
       continue
     }

-    const matching = nodes.filter(({ node }) => matches(node, key))
+    // Pass deny intent so an unverifiable version fails closed: an active versioned deny must not be classified as unused while its broad allow survives.
+    const matching = nodes.filter(({ node }) => matches(node, key, value === false))
     if (matching.length === 0) {
       removed.push({ key, value, reason: 'not-installed' })
       continue
diff --git a/deps/npm/lib/utils/oidc.js b/deps/npm/lib/utils/oidc.js
index 203aaf3143a..7f18170b1b0 100644
--- a/deps/npm/lib/utils/oidc.js
+++ b/deps/npm/lib/utils/oidc.js
@@ -5,6 +5,62 @@ const fetch = require('make-fetch-happen')
 const npa = require('npm-package-arg')
 const libaccess = require('libnpmaccess')

+/**
+ * Caches the runtime state of the active OIDC token exchange
+ * so it can be cleared on subsequent OIDC attempts in workflows
+ * that run OIDC multiple times within one runtime execution,
+ * preventing the previous exchange token from being reused.
+ */
+let activeExchangeRecord
+
+const setOidcToken = ({ config, opts, authTokenKey, token }) => {
+  activeExchangeRecord = {
+    config,
+    authTokenKey,
+    token,
+    previousCliToken: config.get(authTokenKey, 'cli'),
+    opts,
+    previousOptsToken: opts[authTokenKey],
+  }
+  opts[authTokenKey] = token
+  config.set(authTokenKey, token, 'cli')
+  log.verbose('oidc', 'Successfully retrieved and set token')
+}
+
+const clearOidcToken = ({ config, opts }) => {
+  if (!activeExchangeRecord) {
+    return
+  }
+
+  const {
+    config: previousConfig,
+    authTokenKey,
+    token,
+    previousCliToken,
+    opts: previousOpts,
+    previousOptsToken,
+  } = activeExchangeRecord
+  if (previousConfig.get(authTokenKey, 'cli') === token) {
+    if (previousCliToken === undefined) {
+      previousConfig.delete(authTokenKey, 'cli')
+    } else {
+      previousConfig.set(authTokenKey, previousCliToken, 'cli')
+    }
+  }
+  for (const requestOpts of new Set([previousOpts, opts])) {
+    if (requestOpts[authTokenKey] === token) {
+      const fallback = requestOpts === previousOpts ? previousOptsToken : config.get(authTokenKey)
+      if (fallback === undefined) {
+        delete requestOpts[authTokenKey]
+      } else {
+        requestOpts[authTokenKey] = fallback
+      }
+    }
+  }
+  activeExchangeRecord = undefined
+  log.verbose('oidc', 'Cleared previous exchange token')
+}
+
 /**
  * Handles OpenID Connect (OIDC) token retrieval and exchange for CI environments.
  *
@@ -13,18 +69,35 @@ const libaccess = require('libnpmaccess')
  *
  * This function is intended to never throw, as it mutates the state of the `opts` and `config` objects on success.
  * OIDC is always an optional feature, and the function should not throw if OIDC is not configured by the registry.
+ * Before each attempt, it restores credentials replaced by the previous exchange so package-specific tokens are never used as fallback credentials.
  *
  * @see https://github.com/watson/ci-info for CI environment detection.
  * @see https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect for GitHub Actions OIDC.
  * @see https://circleci.com/docs/openid-connect-tokens/ for CircleCI OIDC.
  */
-async function oidc ({ packageName, registry, opts, config }) {
+async function oidc ({
+  // Selects the package-specific npm token exchange endpoint.
+  packageName,
+  // Determines the OIDC audience, exchange host, and registry-scoped auth key.
+  registry,
+  // Mutable request options for the current command, often called flatOptions.
+  // The exchanged token is added here so subsequent registry requests use it immediately.
+  opts,
+  // npm's live configuration state. This is also updated so credential lookups see the token.
+  config,
+  // Publish and stage publish can infer provenance from trusted-publishing claims and package
+  // visibility so users do not need to set --provenance. Other commands that use OIDC, such as
+  // npm dist-tag, only need token exchange and must not enable unrelated publish provenance.
+  enableProvenanceAutoConfiguration = false,
+}) {
   /*
    * This code should never run when people try to publish locally on their machines.
    * It is designed to execute only in Continuous Integration (CI) environments.
    */

   try {
+    clearOidcToken({ config, opts })
+
     if (!(
       /** @see https://github.com/watson/ci-info/blob/v4.2.0/vendors.json#L152 */
       ciInfo.GITHUB_ACTIONS ||
@@ -133,13 +206,17 @@ async function oidc ({ packageName, registry, opts, config }) {
     }

     /*
-     * The "opts" object is a clone of npm.flatOptions and is passed through the `publish` command, eventually reaching `otplease`.
-     * To ensure the token is accessible during the publishing process, it must be directly attached to the `opts` object.
-     * Additionally, the token is required by the "live" configuration or getters within `config`.
+     * `opts` is derived from npm.flatOptions and carried through the current command.
+     * Publish and dist-tag pass it to later registry requests, including mutations wrapped by
+     * `otplease`, so the exchanged token must be attached directly to this object.
+     * The non-persistable cli layer also makes the token available to credential lookups without
+     * modifying any file-backed configuration.
      */
-    opts[authTokenKey] = response.token
-    config.set(authTokenKey, response.token, 'user')
-    log.verbose('oidc', `Successfully retrieved and set token`)
+    setOidcToken({ config, opts, authTokenKey, token: response.token })
+
+    if (!enableProvenanceAutoConfiguration) {
+      return undefined
+    }

     try {
       const isDefaultProvenance = config.isDefault('provenance')
diff --git a/deps/npm/man/man1/npm-access.1 b/deps/npm/man/man1/npm-access.1
index ea2124af3a2..324c220e5f9 100644
--- a/deps/npm/man/man1/npm-access.1
+++ b/deps/npm/man/man1/npm-access.1
@@ -1,4 +1,4 @@
-.TH "NPM-ACCESS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-ACCESS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-access\fR - Set access level on published packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-approve-scripts.1 b/deps/npm/man/man1/npm-approve-scripts.1
index 21ab5382ca4..afd31482a63 100644
--- a/deps/npm/man/man1/npm-approve-scripts.1
+++ b/deps/npm/man/man1/npm-approve-scripts.1
@@ -1,4 +1,4 @@
-.TH "NPM-APPROVE-SCRIPTS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-APPROVE-SCRIPTS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-approve-scripts\fR - Approve install scripts for specific dependencies
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1
index d6751bf0d47..1f1e65aca70 100644
--- a/deps/npm/man/man1/npm-audit.1
+++ b/deps/npm/man/man1/npm-audit.1
@@ -1,4 +1,4 @@
-.TH "NPM-AUDIT" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-AUDIT" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-audit\fR - Run a security audit
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-bugs.1 b/deps/npm/man/man1/npm-bugs.1
index 28877e4200d..ce79290f603 100644
--- a/deps/npm/man/man1/npm-bugs.1
+++ b/deps/npm/man/man1/npm-bugs.1
@@ -1,4 +1,4 @@
-.TH "NPM-BUGS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-BUGS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-bugs\fR - Report bugs for a package in a web browser
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-cache.1 b/deps/npm/man/man1/npm-cache.1
index 00837aa6e97..b0b872ea888 100644
--- a/deps/npm/man/man1/npm-cache.1
+++ b/deps/npm/man/man1/npm-cache.1
@@ -1,4 +1,4 @@
-.TH "NPM-CACHE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-CACHE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-cache\fR - Manipulates packages cache
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1
index 86d0233e032..602bac82785 100644
--- a/deps/npm/man/man1/npm-ci.1
+++ b/deps/npm/man/man1/npm-ci.1
@@ -1,4 +1,4 @@
-.TH "NPM-CI" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-CI" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-ci\fR - Clean install a project
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-completion.1 b/deps/npm/man/man1/npm-completion.1
index 07114f3f03f..a1d2038a9fc 100644
--- a/deps/npm/man/man1/npm-completion.1
+++ b/deps/npm/man/man1/npm-completion.1
@@ -1,4 +1,4 @@
-.TH "NPM-COMPLETION" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-COMPLETION" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-completion\fR - Tab Completion for npm
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1
index d49fee95a85..442a17aca7f 100644
--- a/deps/npm/man/man1/npm-config.1
+++ b/deps/npm/man/man1/npm-config.1
@@ -1,4 +1,4 @@
-.TH "NPM-CONFIG" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-CONFIG" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-config\fR - Manage the npm configuration files
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-dedupe.1 b/deps/npm/man/man1/npm-dedupe.1
index 1e80269a54b..861a94c8657 100644
--- a/deps/npm/man/man1/npm-dedupe.1
+++ b/deps/npm/man/man1/npm-dedupe.1
@@ -1,4 +1,4 @@
-.TH "NPM-DEDUPE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DEDUPE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-dedupe\fR - Reduce duplication in the package tree
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-deny-scripts.1 b/deps/npm/man/man1/npm-deny-scripts.1
index b893be41f70..7250da8e247 100644
--- a/deps/npm/man/man1/npm-deny-scripts.1
+++ b/deps/npm/man/man1/npm-deny-scripts.1
@@ -1,4 +1,4 @@
-.TH "NPM-DENY-SCRIPTS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DENY-SCRIPTS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-deny-scripts\fR - Deny install scripts for specific dependencies
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-deprecate.1 b/deps/npm/man/man1/npm-deprecate.1
index bfcf2fdd2a3..781c3119b7b 100644
--- a/deps/npm/man/man1/npm-deprecate.1
+++ b/deps/npm/man/man1/npm-deprecate.1
@@ -1,4 +1,4 @@
-.TH "NPM-DEPRECATE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DEPRECATE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-deprecate\fR - Deprecate a version of a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-diff.1 b/deps/npm/man/man1/npm-diff.1
index 2301d2b6334..b9a9edc6285 100644
--- a/deps/npm/man/man1/npm-diff.1
+++ b/deps/npm/man/man1/npm-diff.1
@@ -1,4 +1,4 @@
-.TH "NPM-DIFF" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DIFF" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-diff\fR - The registry diff command
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-dist-tag.1 b/deps/npm/man/man1/npm-dist-tag.1
index 81dbdf11ea2..0e22a5cdf8c 100644
--- a/deps/npm/man/man1/npm-dist-tag.1
+++ b/deps/npm/man/man1/npm-dist-tag.1
@@ -1,4 +1,4 @@
-.TH "NPM-DIST-TAG" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DIST-TAG" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-dist-tag\fR - Modify package distribution tags
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-docs.1 b/deps/npm/man/man1/npm-docs.1
index 26956eddf9c..bd38207633f 100644
--- a/deps/npm/man/man1/npm-docs.1
+++ b/deps/npm/man/man1/npm-docs.1
@@ -1,4 +1,4 @@
-.TH "NPM-DOCS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DOCS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-docs\fR - Open documentation for a package in a web browser
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-doctor.1 b/deps/npm/man/man1/npm-doctor.1
index 53b32040526..730593799c1 100644
--- a/deps/npm/man/man1/npm-doctor.1
+++ b/deps/npm/man/man1/npm-doctor.1
@@ -1,4 +1,4 @@
-.TH "NPM-DOCTOR" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-DOCTOR" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-doctor\fR - Check the health of your npm environment
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-edit.1 b/deps/npm/man/man1/npm-edit.1
index 0455962bae3..85c48dd1806 100644
--- a/deps/npm/man/man1/npm-edit.1
+++ b/deps/npm/man/man1/npm-edit.1
@@ -1,4 +1,4 @@
-.TH "NPM-EDIT" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-EDIT" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-edit\fR - Edit an installed package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1
index 496f9f1d132..5ef7665a12f 100644
--- a/deps/npm/man/man1/npm-exec.1
+++ b/deps/npm/man/man1/npm-exec.1
@@ -1,4 +1,4 @@
-.TH "NPM-EXEC" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-EXEC" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-exec\fR - Run a command from a local or remote npm package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1
index 9d6cebd1f81..c915dd81707 100644
--- a/deps/npm/man/man1/npm-explain.1
+++ b/deps/npm/man/man1/npm-explain.1
@@ -1,4 +1,4 @@
-.TH "NPM-EXPLAIN" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-EXPLAIN" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-explain\fR - Explain installed packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-explore.1 b/deps/npm/man/man1/npm-explore.1
index c40059470a3..2b76b1d5520 100644
--- a/deps/npm/man/man1/npm-explore.1
+++ b/deps/npm/man/man1/npm-explore.1
@@ -1,4 +1,4 @@
-.TH "NPM-EXPLORE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-EXPLORE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-explore\fR - Browse an installed package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-find-dupes.1 b/deps/npm/man/man1/npm-find-dupes.1
index 9d4994e168f..16718ee7936 100644
--- a/deps/npm/man/man1/npm-find-dupes.1
+++ b/deps/npm/man/man1/npm-find-dupes.1
@@ -1,4 +1,4 @@
-.TH "NPM-FIND-DUPES" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-FIND-DUPES" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-find-dupes\fR - Find duplication in the package tree
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1
index f7a1ff8b5c6..74f81a6636c 100644
--- a/deps/npm/man/man1/npm-fund.1
+++ b/deps/npm/man/man1/npm-fund.1
@@ -1,4 +1,4 @@
-.TH "NPM-FUND" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-FUND" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-fund\fR - Retrieve funding information
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-get.1 b/deps/npm/man/man1/npm-get.1
index cab4e04b2be..46f9e70e174 100644
--- a/deps/npm/man/man1/npm-get.1
+++ b/deps/npm/man/man1/npm-get.1
@@ -1,4 +1,4 @@
-.TH "NPM-GET" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-GET" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-get\fR - Get a value from the npm configuration
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-help-search.1 b/deps/npm/man/man1/npm-help-search.1
index e2fc3a2c0bf..d38714cdda4 100644
--- a/deps/npm/man/man1/npm-help-search.1
+++ b/deps/npm/man/man1/npm-help-search.1
@@ -1,4 +1,4 @@
-.TH "NPM-HELP-SEARCH" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-HELP-SEARCH" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-help-search\fR - Search npm help documentation
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-help.1 b/deps/npm/man/man1/npm-help.1
index ea019db8185..6e3e7d450fe 100644
--- a/deps/npm/man/man1/npm-help.1
+++ b/deps/npm/man/man1/npm-help.1
@@ -1,4 +1,4 @@
-.TH "NPM-HELP" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-HELP" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-help\fR - Get help on npm
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-init.1 b/deps/npm/man/man1/npm-init.1
index 6b66d92d75d..48a63eb4bca 100644
--- a/deps/npm/man/man1/npm-init.1
+++ b/deps/npm/man/man1/npm-init.1
@@ -1,4 +1,4 @@
-.TH "NPM-INIT" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-INIT" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-init\fR - Create a package.json file
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-install-ci-test.1 b/deps/npm/man/man1/npm-install-ci-test.1
index fb1bdf1d589..db3b60c1fff 100644
--- a/deps/npm/man/man1/npm-install-ci-test.1
+++ b/deps/npm/man/man1/npm-install-ci-test.1
@@ -1,4 +1,4 @@
-.TH "NPM-INSTALL-CI-TEST" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-INSTALL-CI-TEST" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-install-ci-test\fR - Install a project with a clean slate and run tests
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-install-scripts.1 b/deps/npm/man/man1/npm-install-scripts.1
index d210ae1562c..c91c2f66d45 100644
--- a/deps/npm/man/man1/npm-install-scripts.1
+++ b/deps/npm/man/man1/npm-install-scripts.1
@@ -1,4 +1,4 @@
-.TH "NPM-INSTALL-SCRIPTS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-INSTALL-SCRIPTS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-install-scripts\fR - Manage install-script approvals for dependencies
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1
index 876911d59b7..00e1adced34 100644
--- a/deps/npm/man/man1/npm-install-test.1
+++ b/deps/npm/man/man1/npm-install-test.1
@@ -1,4 +1,4 @@
-.TH "NPM-INSTALL-TEST" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-INSTALL-TEST" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-install-test\fR - Install package(s) and run tests
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1
index e0cc75afa65..ebcdf8f33fc 100644
--- a/deps/npm/man/man1/npm-install.1
+++ b/deps/npm/man/man1/npm-install.1
@@ -1,4 +1,4 @@
-.TH "NPM-INSTALL" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-INSTALL" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-install\fR - Install a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1
index fbfbe2c1334..6e01fa12f7a 100644
--- a/deps/npm/man/man1/npm-link.1
+++ b/deps/npm/man/man1/npm-link.1
@@ -1,4 +1,4 @@
-.TH "NPM-LINK" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-LINK" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-link\fR - Symlink a package folder
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-ll.1 b/deps/npm/man/man1/npm-ll.1
index ae5351c9197..9a4c9dd4d96 100644
--- a/deps/npm/man/man1/npm-ll.1
+++ b/deps/npm/man/man1/npm-ll.1
@@ -1,4 +1,4 @@
-.TH "NPM-LL" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-LL" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-ll\fR - List installed packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-login.1 b/deps/npm/man/man1/npm-login.1
index 7c97ebae364..528cbd6bd78 100644
--- a/deps/npm/man/man1/npm-login.1
+++ b/deps/npm/man/man1/npm-login.1
@@ -1,4 +1,4 @@
-.TH "NPM-LOGIN" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-LOGIN" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-login\fR - Login to a registry user account
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-logout.1 b/deps/npm/man/man1/npm-logout.1
index 75e1b4b31c2..9615a4d0627 100644
--- a/deps/npm/man/man1/npm-logout.1
+++ b/deps/npm/man/man1/npm-logout.1
@@ -1,4 +1,4 @@
-.TH "NPM-LOGOUT" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-LOGOUT" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-logout\fR - Log out of the registry
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1
index f805465a2d2..8e3cbf0f6cd 100644
--- a/deps/npm/man/man1/npm-ls.1
+++ b/deps/npm/man/man1/npm-ls.1
@@ -1,4 +1,4 @@
-.TH "NPM-LS" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-LS" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-ls\fR - List installed packages
 .SS "Synopsis"
@@ -20,7 +20,7 @@ Positional arguments are \fBname@version-range\fR identifiers, which will limit
 .P
 .RS 2
 .nf
-npm@12.1.0 /path/to/npm
+npm@12.2.2 /path/to/npm
 └─┬ init-package-json@0.0.4
   └── promzard@0.1.5
 .fi
diff --git a/deps/npm/man/man1/npm-org.1 b/deps/npm/man/man1/npm-org.1
index 8dbf5f5c7b0..43a33b5a80d 100644
--- a/deps/npm/man/man1/npm-org.1
+++ b/deps/npm/man/man1/npm-org.1
@@ -1,4 +1,4 @@
-.TH "NPM-ORG" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-ORG" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-org\fR - Manage orgs
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1
index 5bd59b029b5..088147b68da 100644
--- a/deps/npm/man/man1/npm-outdated.1
+++ b/deps/npm/man/man1/npm-outdated.1
@@ -1,4 +1,4 @@
-.TH "NPM-OUTDATED" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-OUTDATED" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-outdated\fR - Check for outdated packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-owner.1 b/deps/npm/man/man1/npm-owner.1
index cf2f1437674..341f0d86ff0 100644
--- a/deps/npm/man/man1/npm-owner.1
+++ b/deps/npm/man/man1/npm-owner.1
@@ -1,4 +1,4 @@
-.TH "NPM-OWNER" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-OWNER" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-owner\fR - Manage package owners
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-pack.1 b/deps/npm/man/man1/npm-pack.1
index 11ea867006b..efd0fe7e891 100644
--- a/deps/npm/man/man1/npm-pack.1
+++ b/deps/npm/man/man1/npm-pack.1
@@ -1,4 +1,4 @@
-.TH "NPM-PACK" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PACK" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-pack\fR - Create a tarball from a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-patch.1 b/deps/npm/man/man1/npm-patch.1
index ce137bf6c3f..8566db4005f 100644
--- a/deps/npm/man/man1/npm-patch.1
+++ b/deps/npm/man/man1/npm-patch.1
@@ -1,4 +1,4 @@
-.TH "NPM-PATCH" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PATCH" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-patch\fR - Apply local patches to installed dependencies
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-ping.1 b/deps/npm/man/man1/npm-ping.1
index a8d07fd4264..d7ea10b46e9 100644
--- a/deps/npm/man/man1/npm-ping.1
+++ b/deps/npm/man/man1/npm-ping.1
@@ -1,4 +1,4 @@
-.TH "NPM-PING" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PING" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-ping\fR - Ping npm registry
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-pkg.1 b/deps/npm/man/man1/npm-pkg.1
index 6bb01b3b514..a4ba9cff71d 100644
--- a/deps/npm/man/man1/npm-pkg.1
+++ b/deps/npm/man/man1/npm-pkg.1
@@ -1,4 +1,4 @@
-.TH "NPM-PKG" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PKG" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-pkg\fR - Manages your package.json
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-prefix.1 b/deps/npm/man/man1/npm-prefix.1
index 96cd2fd7492..b040821494d 100644
--- a/deps/npm/man/man1/npm-prefix.1
+++ b/deps/npm/man/man1/npm-prefix.1
@@ -1,4 +1,4 @@
-.TH "NPM-PREFIX" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PREFIX" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-prefix\fR - Display prefix
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-profile.1 b/deps/npm/man/man1/npm-profile.1
index c40afb995a5..8676592d547 100644
--- a/deps/npm/man/man1/npm-profile.1
+++ b/deps/npm/man/man1/npm-profile.1
@@ -1,4 +1,4 @@
-.TH "NPM-PROFILE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PROFILE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-profile\fR - Change settings on your registry profile
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-prune.1 b/deps/npm/man/man1/npm-prune.1
index 4989bdabc1c..3403426106d 100644
--- a/deps/npm/man/man1/npm-prune.1
+++ b/deps/npm/man/man1/npm-prune.1
@@ -1,4 +1,4 @@
-.TH "NPM-PRUNE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PRUNE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-prune\fR - Remove extraneous packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-publish.1 b/deps/npm/man/man1/npm-publish.1
index 67ef2babd8c..96fc7285c8d 100644
--- a/deps/npm/man/man1/npm-publish.1
+++ b/deps/npm/man/man1/npm-publish.1
@@ -1,4 +1,4 @@
-.TH "NPM-PUBLISH" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-PUBLISH" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-publish\fR - Publish a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-query.1 b/deps/npm/man/man1/npm-query.1
index 8fbce54d090..a21a449797d 100644
--- a/deps/npm/man/man1/npm-query.1
+++ b/deps/npm/man/man1/npm-query.1
@@ -1,4 +1,4 @@
-.TH "NPM-QUERY" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-QUERY" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-query\fR - Dependency selector query
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-rebuild.1 b/deps/npm/man/man1/npm-rebuild.1
index 0242f143473..af397b47dd0 100644
--- a/deps/npm/man/man1/npm-rebuild.1
+++ b/deps/npm/man/man1/npm-rebuild.1
@@ -1,4 +1,4 @@
-.TH "NPM-REBUILD" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-REBUILD" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-rebuild\fR - Rebuild a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-repo.1 b/deps/npm/man/man1/npm-repo.1
index ab28777a90b..2c9762dfaa1 100644
--- a/deps/npm/man/man1/npm-repo.1
+++ b/deps/npm/man/man1/npm-repo.1
@@ -1,4 +1,4 @@
-.TH "NPM-REPO" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-REPO" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-repo\fR - Open package repository page in the browser
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-restart.1 b/deps/npm/man/man1/npm-restart.1
index 2db4fbb40a0..60db8303f54 100644
--- a/deps/npm/man/man1/npm-restart.1
+++ b/deps/npm/man/man1/npm-restart.1
@@ -1,4 +1,4 @@
-.TH "NPM-RESTART" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-RESTART" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-restart\fR - Restart a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-root.1 b/deps/npm/man/man1/npm-root.1
index f1acff9f88e..a9992453f1b 100644
--- a/deps/npm/man/man1/npm-root.1
+++ b/deps/npm/man/man1/npm-root.1
@@ -1,4 +1,4 @@
-.TH "NPM-ROOT" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-ROOT" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-root\fR - Display npm root
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-run.1 b/deps/npm/man/man1/npm-run.1
index 2fb828a6fda..f47f81e3b7b 100644
--- a/deps/npm/man/man1/npm-run.1
+++ b/deps/npm/man/man1/npm-run.1
@@ -1,4 +1,4 @@
-.TH "NPM-RUN" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-RUN" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-run\fR - Run arbitrary package scripts
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-sbom.1 b/deps/npm/man/man1/npm-sbom.1
index c751d8470f1..7f0126d347e 100644
--- a/deps/npm/man/man1/npm-sbom.1
+++ b/deps/npm/man/man1/npm-sbom.1
@@ -1,4 +1,4 @@
-.TH "NPM-SBOM" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-SBOM" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-sbom\fR - Generate a Software Bill of Materials (SBOM)
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-search.1 b/deps/npm/man/man1/npm-search.1
index c26d0e703b2..08e58b7eba7 100644
--- a/deps/npm/man/man1/npm-search.1
+++ b/deps/npm/man/man1/npm-search.1
@@ -1,4 +1,4 @@
-.TH "NPM-SEARCH" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-SEARCH" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-search\fR - Search for packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-set.1 b/deps/npm/man/man1/npm-set.1
index 7b536646dbe..00f7d9362e6 100644
--- a/deps/npm/man/man1/npm-set.1
+++ b/deps/npm/man/man1/npm-set.1
@@ -1,4 +1,4 @@
-.TH "NPM-SET" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-SET" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-set\fR - Set a value in the npm configuration
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-stage.1 b/deps/npm/man/man1/npm-stage.1
index 57cd8428015..2485744883f 100644
--- a/deps/npm/man/man1/npm-stage.1
+++ b/deps/npm/man/man1/npm-stage.1
@@ -1,4 +1,4 @@
-.TH "NPM-STAGE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-STAGE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-stage\fR - Stage packages for publishing
 .SS "Synopsis"
@@ -25,6 +25,8 @@ Staged packages share the same semver version unique index as published packages
 .IP \(bu 4
 You can still publish packages normally while you have staged packages pending.
 .IP \(bu 4
+Staged publishing will allow you to create a new package if it does not exist.
+.IP \(bu 4
 You can stage multiple versions of the same package.
 .IP \(bu 4
 \fBnpm stage publish\fR has parity with \fBnpm publish\fR and will respect \fB"private": true\fR in \fBpackage.json\fR, refusing to stage the package.
@@ -37,8 +39,6 @@ Before using \fBnpm stage\fR commands, ensure the following requirements are met
 .IP \(bu 4
 \fBWrite permissions on the package:\fR You must have write access to the package you're configuring.
 .IP \(bu 4
-\fBPackage must exist:\fR The package you're configuring must already exist on the npm registry.
-.IP \(bu 4
 \fB2FA enabled on your account:\fR Commands that require 2FA will prompt you to authenticate. If you don't already have 2FA enabled on your account, you must enable it before using these commands.
 .RE 0

diff --git a/deps/npm/man/man1/npm-start.1 b/deps/npm/man/man1/npm-start.1
index 2df0631bb06..95ca202bc95 100644
--- a/deps/npm/man/man1/npm-start.1
+++ b/deps/npm/man/man1/npm-start.1
@@ -1,4 +1,4 @@
-.TH "NPM-START" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-START" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-start\fR - Start a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-stop.1 b/deps/npm/man/man1/npm-stop.1
index 1f5093a84c2..1bb7818e1f5 100644
--- a/deps/npm/man/man1/npm-stop.1
+++ b/deps/npm/man/man1/npm-stop.1
@@ -1,4 +1,4 @@
-.TH "NPM-STOP" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-STOP" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-stop\fR - Stop a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-team.1 b/deps/npm/man/man1/npm-team.1
index b5902750a31..52a32be20f8 100644
--- a/deps/npm/man/man1/npm-team.1
+++ b/deps/npm/man/man1/npm-team.1
@@ -1,4 +1,4 @@
-.TH "NPM-TEAM" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-TEAM" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-team\fR - Manage organization teams and team memberships
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-test.1 b/deps/npm/man/man1/npm-test.1
index ce579644d2d..5dcb59e605b 100644
--- a/deps/npm/man/man1/npm-test.1
+++ b/deps/npm/man/man1/npm-test.1
@@ -1,4 +1,4 @@
-.TH "NPM-TEST" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-TEST" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-test\fR - Test a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-token.1 b/deps/npm/man/man1/npm-token.1
index fcad022257f..c93b80fd6f1 100644
--- a/deps/npm/man/man1/npm-token.1
+++ b/deps/npm/man/man1/npm-token.1
@@ -1,4 +1,4 @@
-.TH "NPM-TOKEN" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-TOKEN" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-token\fR - Manage your authentication tokens
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-trust.1 b/deps/npm/man/man1/npm-trust.1
index 3d1c1712004..3db7dc8b88b 100644
--- a/deps/npm/man/man1/npm-trust.1
+++ b/deps/npm/man/man1/npm-trust.1
@@ -1,4 +1,4 @@
-.TH "NPM-TRUST" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-TRUST" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-trust\fR - Manage trusted publishing relationships between packages and CI/CD providers
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-undeprecate.1 b/deps/npm/man/man1/npm-undeprecate.1
index 7f789a42c7c..4b972298687 100644
--- a/deps/npm/man/man1/npm-undeprecate.1
+++ b/deps/npm/man/man1/npm-undeprecate.1
@@ -1,4 +1,4 @@
-.TH "NPM-UNDEPRECATE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-UNDEPRECATE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-undeprecate\fR - Undeprecate a version of a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-uninstall.1 b/deps/npm/man/man1/npm-uninstall.1
index 2a2fb75d2be..d02c219f6a4 100644
--- a/deps/npm/man/man1/npm-uninstall.1
+++ b/deps/npm/man/man1/npm-uninstall.1
@@ -1,4 +1,4 @@
-.TH "NPM-UNINSTALL" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-UNINSTALL" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-uninstall\fR - Remove a package
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-unpublish.1 b/deps/npm/man/man1/npm-unpublish.1
index f3c1b02fa77..c11c5de96e5 100644
--- a/deps/npm/man/man1/npm-unpublish.1
+++ b/deps/npm/man/man1/npm-unpublish.1
@@ -1,4 +1,4 @@
-.TH "NPM-UNPUBLISH" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-UNPUBLISH" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-unpublish\fR - Remove a package from the registry
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1
index 4e979a194e9..fb6a41bfb1c 100644
--- a/deps/npm/man/man1/npm-update.1
+++ b/deps/npm/man/man1/npm-update.1
@@ -1,4 +1,4 @@
-.TH "NPM-UPDATE" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-UPDATE" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-update\fR - Update packages
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-version.1 b/deps/npm/man/man1/npm-version.1
index 8e3286aabe1..76ae6378184 100644
--- a/deps/npm/man/man1/npm-version.1
+++ b/deps/npm/man/man1/npm-version.1
@@ -1,4 +1,4 @@
-.TH "NPM-VERSION" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-VERSION" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-version\fR - Bump a package version
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-view.1 b/deps/npm/man/man1/npm-view.1
index b49e0338bf7..49c3895db18 100644
--- a/deps/npm/man/man1/npm-view.1
+++ b/deps/npm/man/man1/npm-view.1
@@ -1,4 +1,4 @@
-.TH "NPM-VIEW" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-VIEW" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-view\fR - View registry info
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm-whoami.1 b/deps/npm/man/man1/npm-whoami.1
index b02182e3a90..00999cc8dbd 100644
--- a/deps/npm/man/man1/npm-whoami.1
+++ b/deps/npm/man/man1/npm-whoami.1
@@ -1,4 +1,4 @@
-.TH "NPM-WHOAMI" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM-WHOAMI" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm-whoami\fR - Display npm username
 .SS "Synopsis"
diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1
index 7f1e9889f7f..471b53d9a73 100644
--- a/deps/npm/man/man1/npm.1
+++ b/deps/npm/man/man1/npm.1
@@ -1,4 +1,4 @@
-.TH "NPM" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPM" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpm\fR - javascript package manager
 .SS "Synopsis"
@@ -12,7 +12,7 @@ npm
 Note: This command is unaware of workspaces.
 .SS "Version"
 .P
-12.1.0
+12.2.2
 .SS "Description"
 .P
 npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency conflicts intelligently.
diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1
index b4feebbdd0d..b578ba8b11b 100644
--- a/deps/npm/man/man1/npx.1
+++ b/deps/npm/man/man1/npx.1
@@ -1,4 +1,4 @@
-.TH "NPX" "1" "September 2026" "NPM@12.1.0" ""
+.TH "NPX" "1" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBnpx\fR - Run a command from a local or remote npm package
 .SS "Synopsis"
diff --git a/deps/npm/man/man5/folders.5 b/deps/npm/man/man5/folders.5
index a29476d81c2..5d4d531fa77 100644
--- a/deps/npm/man/man5/folders.5
+++ b/deps/npm/man/man5/folders.5
@@ -1,4 +1,4 @@
-.TH "FOLDERS" "5" "September 2026" "NPM@12.1.0" ""
+.TH "FOLDERS" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBFolders\fR - Folder structures used by npm
 .SS "Description"
diff --git a/deps/npm/man/man5/install.5 b/deps/npm/man/man5/install.5
index fc36a2fd531..746f0448b74 100644
--- a/deps/npm/man/man5/install.5
+++ b/deps/npm/man/man5/install.5
@@ -1,4 +1,4 @@
-.TH "INSTALL" "5" "September 2026" "NPM@12.1.0" ""
+.TH "INSTALL" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBInstall\fR - Download and install node and npm
 .SS "Description"
diff --git a/deps/npm/man/man5/npm-extension.5 b/deps/npm/man/man5/npm-extension.5
index 8d5c5cc3bbd..c8db8a2645b 100644
--- a/deps/npm/man/man5/npm-extension.5
+++ b/deps/npm/man/man5/npm-extension.5
@@ -1,4 +1,4 @@
-.TH ".NPM-EXTENSION" "5" "September 2026" "NPM@12.1.0" ""
+.TH ".NPM-EXTENSION" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fB.npm-extension\fR - Imperative, root-owned manifest repairs
 .SS "Description"
diff --git a/deps/npm/man/man5/npm-global.5 b/deps/npm/man/man5/npm-global.5
index a29476d81c2..5d4d531fa77 100644
--- a/deps/npm/man/man5/npm-global.5
+++ b/deps/npm/man/man5/npm-global.5
@@ -1,4 +1,4 @@
-.TH "FOLDERS" "5" "September 2026" "NPM@12.1.0" ""
+.TH "FOLDERS" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBFolders\fR - Folder structures used by npm
 .SS "Description"
diff --git a/deps/npm/man/man5/npm-json.5 b/deps/npm/man/man5/npm-json.5
index 89640b5abd9..85af518d6ed 100644
--- a/deps/npm/man/man5/npm-json.5
+++ b/deps/npm/man/man5/npm-json.5
@@ -1,4 +1,4 @@
-.TH "PACKAGE.JSON" "5" "September 2026" "NPM@12.1.0" ""
+.TH "PACKAGE.JSON" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBpackage.json\fR - Specifics of npm's package.json handling
 .SS "Description"
diff --git a/deps/npm/man/man5/npmrc.5 b/deps/npm/man/man5/npmrc.5
index 109edb999c2..333864f013d 100644
--- a/deps/npm/man/man5/npmrc.5
+++ b/deps/npm/man/man5/npmrc.5
@@ -1,4 +1,4 @@
-.TH ".NPMRC" "5" "September 2026" "NPM@12.1.0" ""
+.TH ".NPMRC" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fB.npmrc\fR - The npm config files
 .SS "Description"
diff --git a/deps/npm/man/man5/package-json.5 b/deps/npm/man/man5/package-json.5
index 89640b5abd9..85af518d6ed 100644
--- a/deps/npm/man/man5/package-json.5
+++ b/deps/npm/man/man5/package-json.5
@@ -1,4 +1,4 @@
-.TH "PACKAGE.JSON" "5" "September 2026" "NPM@12.1.0" ""
+.TH "PACKAGE.JSON" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBpackage.json\fR - Specifics of npm's package.json handling
 .SS "Description"
diff --git a/deps/npm/man/man5/package-lock-json.5 b/deps/npm/man/man5/package-lock-json.5
index 602e42bcebe..050024e3e14 100644
--- a/deps/npm/man/man5/package-lock-json.5
+++ b/deps/npm/man/man5/package-lock-json.5
@@ -1,4 +1,4 @@
-.TH "PACKAGE-LOCK.JSON" "5" "September 2026" "NPM@12.1.0" ""
+.TH "PACKAGE-LOCK.JSON" "5" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBpackage-lock.json\fR - A manifestation of the manifest
 .SS "Description"
diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7
index 424475b7a0c..c67a71ae67e 100644
--- a/deps/npm/man/man7/config.7
+++ b/deps/npm/man/man7/config.7
@@ -1,4 +1,4 @@
-.TH "CONFIG" "7" "September 2026" "NPM@12.1.0" ""
+.TH "CONFIG" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBConfig\fR - About npm configuration
 .SS "Description"
diff --git a/deps/npm/man/man7/dependency-selectors.7 b/deps/npm/man/man7/dependency-selectors.7
index 8332b010444..c074d387c2e 100644
--- a/deps/npm/man/man7/dependency-selectors.7
+++ b/deps/npm/man/man7/dependency-selectors.7
@@ -1,4 +1,4 @@
-.TH "SELECTORS" "7" "September 2026" "NPM@12.1.0" ""
+.TH "SELECTORS" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBSelectors\fR - Dependency Selector Syntax & Querying
 .SS "Description"
diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7
index 05a05a0b404..d559d9c8888 100644
--- a/deps/npm/man/man7/developers.7
+++ b/deps/npm/man/man7/developers.7
@@ -1,4 +1,4 @@
-.TH "DEVELOPERS" "7" "September 2026" "NPM@12.1.0" ""
+.TH "DEVELOPERS" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBDevelopers\fR - Developer guide
 .SS "Description"
diff --git a/deps/npm/man/man7/logging.7 b/deps/npm/man/man7/logging.7
index 68fc1eab610..ec1ee7e6f3a 100644
--- a/deps/npm/man/man7/logging.7
+++ b/deps/npm/man/man7/logging.7
@@ -1,4 +1,4 @@
-.TH "LOGGING" "7" "September 2026" "NPM@12.1.0" ""
+.TH "LOGGING" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBLogging\fR - Why, What & How we Log
 .SS "Description"
diff --git a/deps/npm/man/man7/orgs.7 b/deps/npm/man/man7/orgs.7
index 591a852e236..fed16a661cf 100644
--- a/deps/npm/man/man7/orgs.7
+++ b/deps/npm/man/man7/orgs.7
@@ -1,4 +1,4 @@
-.TH "ORGANIZATIONS" "7" "September 2026" "NPM@12.1.0" ""
+.TH "ORGANIZATIONS" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBOrganizations\fR - Working with teams & organizations
 .SS "Description"
diff --git a/deps/npm/man/man7/package-spec.7 b/deps/npm/man/man7/package-spec.7
index 85a71352446..e3dc2e778a1 100644
--- a/deps/npm/man/man7/package-spec.7
+++ b/deps/npm/man/man7/package-spec.7
@@ -1,4 +1,4 @@
-.TH "SPEC" "7" "September 2026" "NPM@12.1.0" ""
+.TH "SPEC" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBspec\fR - Package name specifier
 .SS "Description"
diff --git a/deps/npm/man/man7/registry.7 b/deps/npm/man/man7/registry.7
index 6dab903239f..63a92998e30 100644
--- a/deps/npm/man/man7/registry.7
+++ b/deps/npm/man/man7/registry.7
@@ -1,4 +1,4 @@
-.TH "REGISTRY" "7" "September 2026" "NPM@12.1.0" ""
+.TH "REGISTRY" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBRegistry\fR - The JavaScript Package Registry
 .SS "Description"
diff --git a/deps/npm/man/man7/removal.7 b/deps/npm/man/man7/removal.7
index 544909b02d0..15f712cf886 100644
--- a/deps/npm/man/man7/removal.7
+++ b/deps/npm/man/man7/removal.7
@@ -1,4 +1,4 @@
-.TH "REMOVAL" "7" "September 2026" "NPM@12.1.0" ""
+.TH "REMOVAL" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBRemoval\fR - Cleaning the slate
 .SS "Synopsis"
diff --git a/deps/npm/man/man7/scope.7 b/deps/npm/man/man7/scope.7
index b606850f25d..222a2057d82 100644
--- a/deps/npm/man/man7/scope.7
+++ b/deps/npm/man/man7/scope.7
@@ -1,4 +1,4 @@
-.TH "SCOPE" "7" "September 2026" "NPM@12.1.0" ""
+.TH "SCOPE" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBScope\fR - Scoped packages
 .SS "Description"
diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7
index 6c9017dade9..22825120fef 100644
--- a/deps/npm/man/man7/scripts.7
+++ b/deps/npm/man/man7/scripts.7
@@ -1,4 +1,4 @@
-.TH "SCRIPTS" "7" "September 2026" "NPM@12.1.0" ""
+.TH "SCRIPTS" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBScripts\fR - How npm handles the "scripts" field
 .SS "Description"
diff --git a/deps/npm/man/man7/workspaces.7 b/deps/npm/man/man7/workspaces.7
index 96c0881beaa..4f34d4ffb3d 100644
--- a/deps/npm/man/man7/workspaces.7
+++ b/deps/npm/man/man7/workspaces.7
@@ -1,4 +1,4 @@
-.TH "WORKSPACES" "7" "September 2026" "NPM@12.1.0" ""
+.TH "WORKSPACES" "7" "November 2026" "NPM@12.2.2" ""
 .SH "NAME"
 \fBWorkspaces\fR - Working with workspaces
 .SS "Description"
diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
index f7497c2bda4..536b0f8a48f 100644
--- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
+++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
@@ -1660,7 +1660,7 @@ This is a one-time fix-up, please be patient...
           // allow it.  either we're overriding, or it's not something
           // that will be installed by default anyway, and we'll fail when
           // we get to the point where we need to, if we need to.
-          if (conflictOK || !required.has(dep)) {
+          if (conflictOK || !required.has(dep) || this.#loadFailures.has(dep)) {
             edge.peerConflicted = true
             continue
           }
@@ -1694,7 +1694,7 @@ This is a one-time fix-up, please be patient...
       // isn't also required, then there's a good chance we won't need it,
       // so allow it for now and let it conflict if it turns out to actually
       // be necessary for the installation.
-      if (conflictOK || !required.has(edge.from)) {
+      if (conflictOK || !required.has(edge.from) || this.#loadFailures.has(current)) {
         continue
       }

diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/script-allowed.js b/deps/npm/node_modules/@npmcli/arborist/lib/script-allowed.js
index 629625f8e4f..b560884aac6 100644
--- a/deps/npm/node_modules/@npmcli/arborist/lib/script-allowed.js
+++ b/deps/npm/node_modules/@npmcli/arborist/lib/script-allowed.js
@@ -1,3 +1,4 @@
+const { resolve, sep } = require('node:path')
 const npa = require('npm-package-arg')
 const semver = require('semver')
 const versionFromTgz = require('./version-from-tgz.js')
@@ -99,6 +100,23 @@ const matches = (node, key, failClosed) => {
   }
 }

+// True when the node lives in the linked install strategy's `node_modules/.store` directory; such registry-managed packages must never derive identity from the store's internal `file:` link specs.
+const isStoreBacked = (node) => {
+  if (node?.isInStore) {
+    return true
+  }
+  // Nodes loaded from the hidden lockfile do not retain isInStore, so fall back to the path, anchored to this tree's own store so an unrelated project's `.store` never qualifies.
+  const paths = [node?.path, node?.realpath].filter(p => typeof p === 'string')
+  const roots = [node?.root?.path, node?.root?.realpath].filter(p => typeof p === 'string')
+  for (const root of roots) {
+    const store = resolve(root, 'node_modules', '.store')
+    if (paths.some(path => path.startsWith(`${store}${sep}`))) {
+      return true
+    }
+  }
+  return false
+}
+
 const resolvedSourceSpecs = (node) => {
   const specs = []
   const seen = new Set()
@@ -112,7 +130,8 @@ const resolvedSourceSpecs = (node) => {

   add(node?.resolved)

-  if (!node?.resolved && node?.linksIn && typeof node.linksIn[Symbol.iterator] === 'function') {
+  if (!node?.resolved && !isStoreBacked(node) &&
+      node?.linksIn && typeof node.linksIn[Symbol.iterator] === 'function') {
     let hasIncomingLink = false
     for (const link of node.linksIn) {
       hasIncomingLink = true
@@ -235,10 +254,32 @@ const getTrustedRegistryIdentity = (node) => {
 }

 const nameFromEdges = (node) => {
-  if (!node.edgesIn || typeof node.edgesIn[Symbol.iterator] !== 'function') {
+  const name = nameFromEdgeSet(node?.edgesIn)
+  if (name || !isStoreBacked(node) || node?.edgesIn?.size !== 0) {
+    return name
+  }
+  // A store-backed link target carries no edges of its own; they land on the incoming Links, so consult their edges instead, refusing when a Link is non-registry, unidentified, or disagrees with another Link.
+  let linkName = null
+  if (node?.linksIn && typeof node.linksIn[Symbol.iterator] === 'function') {
+    for (const link of node.linksIn) {
+      if (!link.isRegistryDependency) {
+        return null
+      }
+      const name = nameFromEdgeSet(link.edgesIn)
+      if (!name || (linkName && linkName !== name)) {
+        return null
+      }
+      linkName = name
+    }
+  }
+  return linkName
+}
+
+const nameFromEdgeSet = (edgesIn) => {
+  if (!edgesIn || typeof edgesIn[Symbol.iterator] !== 'function') {
     return null
   }
-  for (const edge of node.edgesIn) {
+  for (const edge of edgesIn) {
     let parsed
     try {
       parsed = npa.resolve(edge.name, edge.spec)
@@ -350,7 +391,14 @@ const isRegistryNode = (node) => {
   // edge resolves to a registry spec, which is much harder to spoof than
   // the URL.
   if (typeof node.isRegistryDependency === 'boolean') {
-    return node.isRegistryDependency
+    if (node.isRegistryDependency) {
+      return true
+    }
+    // A store-backed link target carries no edges of its own; they land on the incoming Links (npm/cli#9939), so delegate the edge-based check to them, but never for ordinary local symlink targets that share the same topology.
+    if (isStoreBacked(node) && node.edgesIn?.size === 0 && node.linksIn?.size > 0) {
+      return [...node.linksIn].every(link => link.isRegistryDependency)
+    }
+    return false
   }
   // Fall back to URL parsing for nodes without the arborist getter
   // (e.g. test fixtures, lockfiles with omit-lockfile-registry-resolved).
diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json
index 3a136df4f77..de1c6c97369 100644
--- a/deps/npm/node_modules/@npmcli/arborist/package.json
+++ b/deps/npm/node_modules/@npmcli/arborist/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@npmcli/arborist",
-  "version": "10.0.3",
+  "version": "10.0.4",
   "description": "Manage node_modules trees",
   "dependencies": {
     "@gar/promise-retry": "^1.0.0",
diff --git a/deps/npm/node_modules/@npmcli/config/README.md b/deps/npm/node_modules/@npmcli/config/README.md
index 6a948d9b11a..b86557d6b31 100644
--- a/deps/npm/node_modules/@npmcli/config/README.md
+++ b/deps/npm/node_modules/@npmcli/config/README.md
@@ -180,6 +180,8 @@ Set the key to the specified value, at the specified level in the config stack.

 Delete the configuration key from the specified level in the config stack.

+Deleting an override exposes the next applicable value from the lower-priority sources and invalidates cached flattened options.
+
 ### `config.validate(where)`

 Verify that all known configuration options are set to valid values, and log a warning if they are invalid.
diff --git a/deps/npm/node_modules/@npmcli/config/lib/index.js b/deps/npm/node_modules/@npmcli/config/lib/index.js
index 4121c2a7a38..37dfecf800d 100644
--- a/deps/npm/node_modules/@npmcli/config/lib/index.js
+++ b/deps/npm/node_modules/@npmcli/config/lib/index.js
@@ -240,6 +240,8 @@ class Config {
     if (['global', 'user', 'project'].includes(where)) {
       delete raw[key]
     }
+    this.data.get(where)[_valid] = null
+    this.#flatOptions = null
   }

   async load () {
diff --git a/deps/npm/node_modules/@npmcli/config/package.json b/deps/npm/node_modules/@npmcli/config/package.json
index 0380bd34800..06f9020a7e6 100644
--- a/deps/npm/node_modules/@npmcli/config/package.json
+++ b/deps/npm/node_modules/@npmcli/config/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@npmcli/config",
-  "version": "11.1.0",
+  "version": "11.2.0",
   "files": [
     "bin/",
     "lib/"
diff --git a/deps/npm/node_modules/@npmcli/promise-spawn/lib/index.js b/deps/npm/node_modules/@npmcli/promise-spawn/lib/index.js
index 1faf62c9157..d6d2c8cd048 100644
--- a/deps/npm/node_modules/@npmcli/promise-spawn/lib/index.js
+++ b/deps/npm/node_modules/@npmcli/promise-spawn/lib/index.js
@@ -83,20 +83,27 @@ const spawnWithShell = (cmd, args, opts, extra) => {
   if (isCmd) {
     let doubleEscape = false

-    // find the actual command we're running
+    // Decode the executable token so escaped batch shims still get double escaping.
     let initialCmd = ''
     let insideQuotes = false
     for (let i = 0; i < cmd.length; ++i) {
       const char = cmd.charAt(i)
+      if (char === '^' && !insideQuotes && i + 1 < cmd.length) {
+        initialCmd += cmd.charAt(++i)
+        continue
+      }
       if (char === ' ' && !insideQuotes) {
         break
       }

       initialCmd += char
-      if (char === '"' || char === "'") {
+      if (char === '"') {
         insideQuotes = !insideQuotes
       }
     }
+    if (initialCmd.startsWith('"') && initialCmd.endsWith('"')) {
+      initialCmd = initialCmd.slice(1, -1)
+    }

     let pathToInitial
     try {
diff --git a/deps/npm/node_modules/@npmcli/promise-spawn/package.json b/deps/npm/node_modules/@npmcli/promise-spawn/package.json
index b227171eebd..ca32578867a 100644
--- a/deps/npm/node_modules/@npmcli/promise-spawn/package.json
+++ b/deps/npm/node_modules/@npmcli/promise-spawn/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@npmcli/promise-spawn",
-  "version": "10.0.0",
+  "version": "10.0.1",
   "files": [
     "bin/",
     "lib/"
@@ -32,8 +32,8 @@
     ]
   },
   "devDependencies": {
-    "@npmcli/eslint-config": "^6.0.0",
-    "@npmcli/template-oss": "5.1.0",
+    "@npmcli/eslint-config": "^7.0.0",
+    "@npmcli/template-oss": "5.1.1",
     "spawk": "^1.7.1",
     "tap": "^16.0.1"
   },
@@ -42,7 +42,7 @@
   },
   "templateOSS": {
     "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
-    "version": "5.1.0",
+    "version": "5.1.1",
     "publish": true
   },
   "dependencies": {
diff --git a/deps/npm/node_modules/bin-links/lib/get-paths.js b/deps/npm/node_modules/bin-links/lib/get-paths.js
index b93e6982dce..871a9c4a812 100644
--- a/deps/npm/node_modules/bin-links/lib/get-paths.js
+++ b/deps/npm/node_modules/bin-links/lib/get-paths.js
@@ -5,11 +5,13 @@ const binTarget = require('./bin-target.js')
 const manTarget = require('./man-target.js')
 const { resolve, basename, extname } = require('path')
 const isWindows = require('./is-windows.js')
+const normalize = require('npm-normalize-package-bin')
 module.exports = ({ path, pkg, global, top }) => {
   if (top && !global) {
     return []
   }

+  pkg = normalize({ ...pkg })
   const binSet = []
   const binTarg = binTarget({ path, top })
   if (pkg.bin) {
diff --git a/deps/npm/node_modules/bin-links/package.json b/deps/npm/node_modules/bin-links/package.json
index a6d8ae82217..a265be3dd90 100644
--- a/deps/npm/node_modules/bin-links/package.json
+++ b/deps/npm/node_modules/bin-links/package.json
@@ -1,6 +1,6 @@
 {
   "name": "bin-links",
-  "version": "7.0.0",
+  "version": "7.0.1",
   "description": "JavaScript package binary linker",
   "main": "./lib/index.js",
   "scripts": {
@@ -31,8 +31,8 @@
     "write-file-atomic": "^8.0.0"
   },
   "devDependencies": {
-    "@npmcli/eslint-config": "^6.0.0",
-    "@npmcli/template-oss": "5.1.0",
+    "@npmcli/eslint-config": "^7.0.0",
+    "@npmcli/template-oss": "5.1.1",
     "require-inject": "^1.4.4",
     "tap": "^16.0.1"
   },
@@ -55,7 +55,7 @@
   "templateOSS": {
     "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
     "windowsCI": false,
-    "version": "5.1.0",
+    "version": "5.1.1",
     "publish": true,
     "updateNpm": false
   }
diff --git a/deps/npm/node_modules/brace-expansion/dist/commonjs/index.js b/deps/npm/node_modules/brace-expansion/dist/commonjs/index.js
index 869a6bee238..48cf0d3dabc 100644
--- a/deps/npm/node_modules/brace-expansion/dist/commonjs/index.js
+++ b/deps/npm/node_modules/brace-expansion/dist/commonjs/index.js
@@ -1,6 +1,6 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
+exports.EXPANSION_MAX_REWRITES = exports.EXPANSION_MAX_DEPTH = exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
 exports.expand = expand;
 const balanced_match_1 = require("balanced-match");
 const escSlash = '\0SLASH' + Math.random() + '\0';
@@ -30,6 +30,24 @@ exports.EXPANSION_MAX = 100_000;
 // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
 // characters) so legitimate input is unaffected.
 exports.EXPANSION_MAX_LENGTH = 4_000_000;
+// `expand_` recurses once per level of brace *nesting* - both when expanding a
+// set's comma members and when re-wrapping a set whose body is a single part.
+// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
+// level per chained group), which left nesting depth unbounded: about 3,100
+// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
+// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
+// will follow nesting. It sits far above any realistic pattern and well below
+// the depth at which the stack runs out.
+exports.EXPANSION_MAX_DEPTH = 1_000;
+// Bash keeps a quirk where a brace group followed by a comma set still expands
+// (`{a},b}`). The parser implements it by rewriting the string and restarting
+// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
+// full passes over a string that itself grows by one `escClose` sentinel each
+// time - quadratic in `n`, with a ~26x constant from the sentinel's length.
+// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
+// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
+// times the scan may restart. Real `{a},b}` input needs a handful.
+exports.EXPANSION_MAX_REWRITES = 1_000;
 function numeric(str) {
     return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
 }
@@ -49,37 +67,52 @@ function unescapeBraces(str) {
         .replace(escCommaPattern, ',')
         .replace(escPeriodPattern, '.');
 }
+// Like `target.push(...items)` but doesn't overflow the stack
+function pushAll(target, items) {
+    for (let i = 0; i < items.length; i++) {
+        target.push(items[i]);
+    }
+}
 /**
  * Basically just str.split(","), but handling cases
  * where we have nested braced sections, which should be
  * treated as individual members, like {a,{b,c},d}
  */
 function parseCommaParts(str) {
-    if (!str) {
-        return [''];
-    }
     const parts = [];
-    const m = (0, balanced_match_1.balanced)('{', '}', str);
-    if (!m) {
-        return str.split(',');
-    }
-    const { pre, body, post } = m;
-    const p = pre.split(',');
-    p[p.length - 1] += '{' + body + '}';
-    const postParts = parseCommaParts(post);
-    if (post.length) {
-        ;
-        p[p.length - 1] += postParts.shift();
-        p.push.apply(p, postParts);
+    // Walk the brace groups iteratively. Recursing on `post` once per group let a
+    // chain of them exhaust the stack - the parsing-side counterpart to
+    // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or
+    // `maxLength` can bound, since it happens before expansion.
+    //
+    // The part the next chunk continues
+    let carry = '';
+    for (;;) {
+        const m = (0, balanced_match_1.balanced)('{', '}', str);
+        if (!m) {
+            const tail = str.split(',');
+            tail[0] = carry + tail[0];
+            pushAll(parts, tail);
+            return parts;
+        }
+        const { pre, body, post } = m;
+        const p = pre.split(',');
+        p[0] = carry + p[0];
+        p[p.length - 1] += '{' + body + '}';
+        if (!post.length) {
+            pushAll(parts, p);
+            return parts;
+        }
+        carry = p.pop();
+        pushAll(parts, p);
+        str = post;
     }
-    parts.push.apply(parts, p);
-    return parts;
 }
 function expand(str, options = {}) {
     if (!str) {
         return [];
     }
-    const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options;
+    const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH, maxDepth = exports.EXPANSION_MAX_DEPTH, maxRewrites = exports.EXPANSION_MAX_REWRITES, } = options;
     // I don't know why Bash 4.3 does this, but it does.
     // Anything starting with {} will have the first two bytes preserved
     // but *only* at the top level, so {},a}b will not expand to anything,
@@ -89,7 +122,7 @@ function expand(str, options = {}) {
     if (str.slice(0, 2) === '{}') {
         str = '\\{\\}' + str.slice(2);
     }
-    return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
+    return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
 }
 function embrace(str) {
     return '{' + str + '}';
@@ -184,7 +217,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) {
     }
     return N;
 }
-function expand_(str, max, maxLength, isTop) {
+function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) {
+    // Too deeply nested to keep following: treat the rest as literal, the same
+    // way a group that cannot expand is already handled. Truncating rather than
+    // throwing keeps `expand` total, matching `max` and `maxLength`.
+    if (depth > maxDepth) {
+        return [str];
+    }
     // Consume the string's top-level brace groups left to right, threading a
     // running set of combined prefixes (`acc`). Expanding the tail iteratively -
     // rather than recursing on `m.post` once per group - keeps the native stack
@@ -196,6 +235,9 @@ function expand_(str, max, maxLength, isTop) {
     // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
     // is on the final strings, so it is applied to whichever `combine` produces
     // them (the one with no brace set left in the tail).
+    // How many times the `{a},b}` rewrite below has restarted the scan. Each pass
+    // re-reads the whole string, so leaving this unbounded is quadratic.
+    let rewrites = 0;
     let dropEmpties = false;
     let firstGroup = true;
     for (;;) {
@@ -220,7 +262,8 @@ function expand_(str, max, maxLength, isTop) {
         const isOptions = m.body.indexOf(',') >= 0;
         if (!isSequence && !isOptions) {
             // {a},b}
-            if (m.post.match(/,(?!,).*\}/)) {
+            if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
+                rewrites++;
                 str = m.pre + '{' + m.body + escClose + m.post;
                 isTop = true;
                 continue;
@@ -240,7 +283,7 @@ function expand_(str, max, maxLength, isTop) {
             let n = parseCommaParts(m.body);
             if (n.length === 1 && n[0] !== undefined) {
                 // x{{a,b}}y ==> x{a}y x{b}y
-                n = expand_(n[0], max, maxLength, false).map(embrace);
+                n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
                 //XXX is this necessary? Can't seem to hit it in tests.
                 /* c8 ignore start */
                 if (n.length === 1) {
@@ -266,12 +309,13 @@ function expand_(str, max, maxLength, isTop) {
             values = [];
             let valuesLength = 0;
             outer: for (let j = 0; j < n.length; j++) {
-                const expanded = expand_(n[j], max, maxLength, false);
+                const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
                 for (let k = 0; k < expanded.length; k++) {
                     const v = expanded[k];
                     if (dropsEmpties && !v)
                         continue;
-                    if (values.length >= max || valuesLength + v.length > maxLength) {
+                    if (values.length >= max ||
+                        valuesLength + v.length > maxLength) {
                         break outer;
                     }
                     values.push(v);
diff --git a/deps/npm/node_modules/brace-expansion/dist/esm/index.js b/deps/npm/node_modules/brace-expansion/dist/esm/index.js
index fd68f570292..0e0cc962307 100644
--- a/deps/npm/node_modules/brace-expansion/dist/esm/index.js
+++ b/deps/npm/node_modules/brace-expansion/dist/esm/index.js
@@ -26,6 +26,24 @@ export const EXPANSION_MAX = 100_000;
 // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M
 // characters) so legitimate input is unaffected.
 export const EXPANSION_MAX_LENGTH = 4_000_000;
+// `expand_` recurses once per level of brace *nesting* - both when expanding a
+// set's comma members and when re-wrapping a set whose body is a single part.
+// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
+// level per chained group), which left nesting depth unbounded: about 3,100
+// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
+// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
+// will follow nesting. It sits far above any realistic pattern and well below
+// the depth at which the stack runs out.
+export const EXPANSION_MAX_DEPTH = 1_000;
+// Bash keeps a quirk where a brace group followed by a comma set still expands
+// (`{a},b}`). The parser implements it by rewriting the string and restarting
+// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
+// full passes over a string that itself grows by one `escClose` sentinel each
+// time - quadratic in `n`, with a ~26x constant from the sentinel's length.
+// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
+// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
+// times the scan may restart. Real `{a},b}` input needs a handful.
+export const EXPANSION_MAX_REWRITES = 1_000;
 function numeric(str) {
     return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
 }
@@ -45,37 +63,52 @@ function unescapeBraces(str) {
         .replace(escCommaPattern, ',')
         .replace(escPeriodPattern, '.');
 }
+// Like `target.push(...items)` but doesn't overflow the stack
+function pushAll(target, items) {
+    for (let i = 0; i < items.length; i++) {
+        target.push(items[i]);
+    }
+}
 /**
  * Basically just str.split(","), but handling cases
  * where we have nested braced sections, which should be
  * treated as individual members, like {a,{b,c},d}
  */
 function parseCommaParts(str) {
-    if (!str) {
-        return [''];
-    }
     const parts = [];
-    const m = balanced('{', '}', str);
-    if (!m) {
-        return str.split(',');
-    }
-    const { pre, body, post } = m;
-    const p = pre.split(',');
-    p[p.length - 1] += '{' + body + '}';
-    const postParts = parseCommaParts(post);
-    if (post.length) {
-        ;
-        p[p.length - 1] += postParts.shift();
-        p.push.apply(p, postParts);
+    // Walk the brace groups iteratively. Recursing on `post` once per group let a
+    // chain of them exhaust the stack - the parsing-side counterpart to
+    // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or
+    // `maxLength` can bound, since it happens before expansion.
+    //
+    // The part the next chunk continues
+    let carry = '';
+    for (;;) {
+        const m = balanced('{', '}', str);
+        if (!m) {
+            const tail = str.split(',');
+            tail[0] = carry + tail[0];
+            pushAll(parts, tail);
+            return parts;
+        }
+        const { pre, body, post } = m;
+        const p = pre.split(',');
+        p[0] = carry + p[0];
+        p[p.length - 1] += '{' + body + '}';
+        if (!post.length) {
+            pushAll(parts, p);
+            return parts;
+        }
+        carry = p.pop();
+        pushAll(parts, p);
+        str = post;
     }
-    parts.push.apply(parts, p);
-    return parts;
 }
 export function expand(str, options = {}) {
     if (!str) {
         return [];
     }
-    const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options;
+    const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH, maxDepth = EXPANSION_MAX_DEPTH, maxRewrites = EXPANSION_MAX_REWRITES, } = options;
     // I don't know why Bash 4.3 does this, but it does.
     // Anything starting with {} will have the first two bytes preserved
     // but *only* at the top level, so {},a}b will not expand to anything,
@@ -85,7 +118,7 @@ export function expand(str, options = {}) {
     if (str.slice(0, 2) === '{}') {
         str = '\\{\\}' + str.slice(2);
     }
-    return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
+    return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
 }
 function embrace(str) {
     return '{' + str + '}';
@@ -180,7 +213,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) {
     }
     return N;
 }
-function expand_(str, max, maxLength, isTop) {
+function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) {
+    // Too deeply nested to keep following: treat the rest as literal, the same
+    // way a group that cannot expand is already handled. Truncating rather than
+    // throwing keeps `expand` total, matching `max` and `maxLength`.
+    if (depth > maxDepth) {
+        return [str];
+    }
     // Consume the string's top-level brace groups left to right, threading a
     // running set of combined prefixes (`acc`). Expanding the tail iteratively -
     // rather than recursing on `m.post` once per group - keeps the native stack
@@ -192,6 +231,9 @@ function expand_(str, max, maxLength, isTop) {
     // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop
     // is on the final strings, so it is applied to whichever `combine` produces
     // them (the one with no brace set left in the tail).
+    // How many times the `{a},b}` rewrite below has restarted the scan. Each pass
+    // re-reads the whole string, so leaving this unbounded is quadratic.
+    let rewrites = 0;
     let dropEmpties = false;
     let firstGroup = true;
     for (;;) {
@@ -216,7 +258,8 @@ function expand_(str, max, maxLength, isTop) {
         const isOptions = m.body.indexOf(',') >= 0;
         if (!isSequence && !isOptions) {
             // {a},b}
-            if (m.post.match(/,(?!,).*\}/)) {
+            if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
+                rewrites++;
                 str = m.pre + '{' + m.body + escClose + m.post;
                 isTop = true;
                 continue;
@@ -236,7 +279,7 @@ function expand_(str, max, maxLength, isTop) {
             let n = parseCommaParts(m.body);
             if (n.length === 1 && n[0] !== undefined) {
                 // x{{a,b}}y ==> x{a}y x{b}y
-                n = expand_(n[0], max, maxLength, false).map(embrace);
+                n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
                 //XXX is this necessary? Can't seem to hit it in tests.
                 /* c8 ignore start */
                 if (n.length === 1) {
@@ -262,12 +305,13 @@ function expand_(str, max, maxLength, isTop) {
             values = [];
             let valuesLength = 0;
             outer: for (let j = 0; j < n.length; j++) {
-                const expanded = expand_(n[j], max, maxLength, false);
+                const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false);
                 for (let k = 0; k < expanded.length; k++) {
                     const v = expanded[k];
                     if (dropsEmpties && !v)
                         continue;
-                    if (values.length >= max || valuesLength + v.length > maxLength) {
+                    if (values.length >= max ||
+                        valuesLength + v.length > maxLength) {
                         break outer;
                     }
                     values.push(v);
diff --git a/deps/npm/node_modules/brace-expansion/package.json b/deps/npm/node_modules/brace-expansion/package.json
index 4376400796c..a5c96ebe02f 100644
--- a/deps/npm/node_modules/brace-expansion/package.json
+++ b/deps/npm/node_modules/brace-expansion/package.json
@@ -1,7 +1,7 @@
 {
   "name": "brace-expansion",
   "description": "Brace expansion as known from sh/bash",
-  "version": "5.0.9",
+  "version": "5.0.12",
   "files": [
     "dist"
   ],
@@ -29,6 +29,7 @@
     "test": "tap",
     "snap": "tap",
     "format": "prettier --write .",
+    "format:check": "prettier --check .",
     "benchmark": "node benchmark/index.js",
     "typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts"
   },
diff --git a/deps/npm/node_modules/http-cache-semantics/index.js b/deps/npm/node_modules/http-cache-semantics/index.js
index f01e9a16b47..56c26025074 100644
--- a/deps/npm/node_modules/http-cache-semantics/index.js
+++ b/deps/npm/node_modules/http-cache-semantics/index.js
@@ -334,12 +334,13 @@ module.exports = class CachePolicy {

     /**
      * @param {{headers: Record<string, string>, synchronous: boolean}|undefined} revalidation - Revalidation information, if any.
-     * @returns {{response: {headers: Record<string, string>}, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object with a cached response headers and revalidation info.
+     * @returns {{response: HttpResponse, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object with a cached response headers and revalidation info.
      */
     _evaluateRequestHitResult(revalidation) {
         return {
             response: {
                 headers: this.responseHeaders(),
+                status: this._status,
             },
             revalidation,
         };
@@ -387,9 +388,9 @@ module.exports = class CachePolicy {
      * }
      * ```
      * @param {HttpRequest} req - new incoming HTTP request
-     * @returns {{response: {headers: Record<string, string>}|undefined, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object containing keys:
+     * @returns {{response: HttpResponse|undefined, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object containing keys:
      *   - revalidation: { headers: Record<string, string>, synchronous: boolean } Set if you should send this to the origin server
-     *   - response: { headers: Record<string, string> } Set if you can respond to the client with these cached headers
+     *   - response: HttpResponse Set if you can respond to the client with these cached headers
      */
     evaluateRequest(req) {
         this._assertRequestHasHeaders(req);
@@ -484,18 +485,32 @@ module.exports = class CachePolicy {
             return true;
         }

-        // A Vary header field-value of "*" always fails to match
-        if (this._resHeaders.vary === '*') {
-            return false;
-        }
-
         const fields = this._resHeaders.vary
             .trim()
             .toLowerCase()
             .split(/\s*,\s*/);
+
         for (const name of fields) {
-            if (req.headers[name] !== this._reqHeaders[name]) return false;
+            // A Vary header field-value of "*" always fails to match
+            if (name === '*') {
+                return false;
+            }
+
+            const newReq = Object.prototype.hasOwnProperty.call(
+                req.headers,
+                name
+            ) && req.headers[name];
+
+            const cachedReq = Object.prototype.hasOwnProperty.call(
+                this._reqHeaders,
+                name
+            ) && this._reqHeaders[name];
+
+            if (newReq !== cachedReq) {
+                return false;
+            }
         }
+
         return true;
     }

@@ -556,6 +571,14 @@ module.exports = class CachePolicy {
         return headers;
     }

+    /**
+     * Returns the status code of the cached response.
+     * @returns {number} The response status code.
+     */
+    status() {
+      return this._status;
+    }
+
     /**
      * Returns the Date header value from the response or the current time if invalid.
      * @returns {number} Timestamp (in milliseconds) representing the Date header or response time.
diff --git a/deps/npm/node_modules/http-cache-semantics/package.json b/deps/npm/node_modules/http-cache-semantics/package.json
index d45dfa1274e..06a565ffb7e 100644
--- a/deps/npm/node_modules/http-cache-semantics/package.json
+++ b/deps/npm/node_modules/http-cache-semantics/package.json
@@ -1,6 +1,6 @@
 {
     "name": "http-cache-semantics",
-    "version": "4.2.0",
+    "version": "4.3.0",
     "description": "Parses Cache-Control and other headers. Helps building correct HTTP caches and proxies",
     "repository": {
         "type": "git",
@@ -14,9 +14,9 @@
     "files": [
         "index.js"
     ],
-    "author": "Kornel Lesiński <npms2@geekhood.net> (https://kornel.ski/)",
+    "author": "Kornel Lesiński <kornel@geekhood.net> (https://kornel.ski/)",
     "license": "BSD-2-Clause",
     "devDependencies": {
-        "mocha": "^11.0"
+        "mocha": "^12.0"
     }
 }
diff --git a/deps/npm/node_modules/ip-address/dist/common.js b/deps/npm/node_modules/ip-address/dist/common.js
index 0c15d21e3a3..9c9ecf03ff2 100644
--- a/deps/npm/node_modules/ip-address/dist/common.js
+++ b/deps/npm/node_modules/ip-address/dist/common.js
@@ -2,6 +2,8 @@
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.isInSubnet = isInSubnet;
 exports.isHostInSubnet = isHostInSubnet;
+exports.isGloballyReachable = isGloballyReachable;
+exports.offsetBigInt = offsetBigInt;
 exports.isCorrect = isCorrect;
 exports.prefixLengthFromMask = prefixLengthFromMask;
 exports.assertByteArray = assertByteArray;
@@ -36,10 +38,56 @@ function isInSubnet(address) {
  * {@link isInSubnet} when classifying a single address — notably when the
  * address came from untrusted input and the result backs a trust-boundary
  * decision such as an SSRF allow/deny filter.
+ *
+ * An address of one family is never inside a network of the other, so an
+ * `Address4` against an `Address6` (or the reverse) is `false`. To compare
+ * across families, convert first: `Address6.fromAddress4()`, `to4()`, or
+ * `toAddress4Nat64()`.
  */
 function isHostInSubnet(address) {
+    // mask() is a bit string of the family's width, and the leading bits of a
+    // 32-bit string can coincide with those of a 128-bit one (a00::1 and
+    // 10.0.0.0/8 both mask to 00001010), so the widths must agree before the
+    // strings are compared.
+    if (this.binaryZeroPad().length !== address.binaryZeroPad().length) {
+        return false;
+    }
     return this.mask(address.subnetMask) === address.mask();
 }
+/**
+ * Returns whether the registry marks this address globally reachable: the
+ * answer of the most specific entry containing it that has one, or `true`
+ * when no entry contains it.
+ */
+function isGloballyReachable(entries) {
+    let best = null;
+    for (let i = 0; i < entries.length; i++) {
+        const entry = entries[i];
+        if (entry.reachable !== null &&
+            isHostInSubnet.call(this, entry.subnet) &&
+            (best === null || entry.subnet.subnetMask > best.subnet.subnetMask)) {
+            best = entry;
+        }
+    }
+    return best === null ? true : best.reachable;
+}
+/**
+ * Adds `n` to `value` and returns the result, throwing `AddressError` unless
+ * `n` is an integer and the result stays within `[0, 2**bits - 1]`.
+ */
+function offsetBigInt(value, n, bits, family) {
+    if (typeof n === 'number' && !Number.isSafeInteger(n)) {
+        throw new address_error_1.AddressError(`${family} offset must be an integer`);
+    }
+    if (typeof n !== 'number' && typeof n !== 'bigint') {
+        throw new address_error_1.AddressError(`${family} offset must be an integer`);
+    }
+    const result = value + BigInt(n);
+    if (result < BigInt(0) || result > (BigInt(1) << BigInt(bits)) - BigInt(1)) {
+        throw new address_error_1.AddressError(`${family} offset leaves the address space`);
+    }
+    return result;
+}
 function isCorrect(defaultBits) {
     return function isCorrectForm() {
         if (this.addressMinusSuffix !== this.correctForm()) {
@@ -97,10 +145,10 @@ function stringToPaddedHex(numberString) {
  */
 function testBit(binaryValue, position) {
     const { length } = binaryValue;
-    if (position > length) {
+    if (position >= length) {
         return false;
     }
-    const positionInString = length - position;
+    const positionInString = length - position - 1;
     return binaryValue.substring(positionInString, positionInString + 1) === '1';
 }
 //# sourceMappingURL=common.js.map
\ No newline at end of file
diff --git a/deps/npm/node_modules/ip-address/dist/ipv4.js b/deps/npm/node_modules/ip-address/dist/ipv4.js
index 1360e1836a0..4b9cf98b608 100644
--- a/deps/npm/node_modules/ip-address/dist/ipv4.js
+++ b/deps/npm/node_modules/ip-address/dist/ipv4.js
@@ -48,7 +48,9 @@ class Address4 {
          */
         this.isCorrect = isCorrect4;
         /**
-         * Returns true if the given address is in the subnet of the current address
+         * Returns true if the given address is in the subnet of the current address.
+         * An `Address6` is never in the subnet of an `Address4`; convert with
+         * `to4()` or `Address6.fromAddress4()` to compare across families.
          * @returns {boolean}
          */
         this.isInSubnet = common.isInSubnet;
@@ -58,6 +60,8 @@ class Address4 {
          * when classifying a single address, so the answer doesn't change with the
          * CIDR suffix the caller happened to write — notably when the address came
          * from untrusted input and the result backs a trust-boundary decision.
+         * An `Address6` is never in the subnet of an `Address4`; convert with
+         * `to4()` or `Address6.fromAddress4()` to compare across families.
          * @returns {boolean}
          */
         this.isHostInSubnet = common.isHostInSubnet;
@@ -72,6 +76,13 @@ class Address4 {
             }
             address = address.replace(constants.RE_SUBNET_STRING, '');
         }
+        // Four three-digit octets and three dots: the longest well-formed address
+        // is 15 characters. Longer input is rejected before parsing, as Address6
+        // does at its own limit.
+        const longest = constants.GROUPS * 4 - 1;
+        if (address.length > longest) {
+            throw new address_error_1.AddressError(`IPv4 addresses are at most ${longest} characters.`);
+        }
         this.addressMinusSuffix = address;
         this.parsedAddress = this.parse(address);
     }
@@ -213,16 +224,27 @@ class Address4 {
         return Address4.fromHex(integer.toString(16).padStart(8, '0'));
     }
     /**
-     * Return an address from in-addr.arpa form
+     * Return an address from in-addr.arpa form: the four octets reversed, with
+     * or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
+     * `AddressError` unless the reversed labels form a valid IPv4 address, so
+     * `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
      * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
      * @returns {Adress4}
      * @example
-     * var address = Address4.fromArpa(42.2.0.192.in-addr.arpa.)
+     * var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
      * address.correctForm(); // '192.0.2.42'
      */
     static fromArpa(arpaFormAddress) {
-        // remove ending ".in-addr.arpa." or just "."
-        const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, '');
+        // A 15-character address, a "/32" prefix length and ".in-addr.arpa.": the
+        // longest name is 32 characters. Longer input is rejected before its
+        // labels are split, as the constructor does at its own limit.
+        const longest = constants.GROUPS * 4 - 1 + '/32'.length + '.in-addr.arpa.'.length;
+        if (arpaFormAddress.length > longest) {
+            throw new address_error_1.AddressError(`in-addr.arpa names are at most ${longest} characters.`);
+        }
+        // remove an ending ".in-addr.arpa", in any case and with or without the
+        // root dot, as Address6.fromArpa does for ".ip6.arpa"
+        const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.?$/i, '');
         const address = leader.split('.').reverse().join('.');
         return new Address4(address);
     }
@@ -285,6 +307,33 @@ class Address4 {
         const adjust = BigInt('1');
         return Address4.fromBigInt(this._startAddress() + adjust);
     }
+    /**
+     * Returns the address `n` addresses after this one (or before, when `n` is
+     * negative), keeping this address's subnet mask. Throws `AddressError` when
+     * the result would fall outside the IPv4 address space or `n` is not an
+     * integer.
+     * @param {number | bigint} n
+     * @returns {Address4}
+     * @example
+     * new Address4('10.0.0.0/24').offset(1).correctForm(); // '10.0.0.1'
+     */
+    offset(n) {
+        return Address4.fromBigInt(common.offsetBigInt(this.bigInt(), n, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
+    }
+    /**
+     * Returns the network that follows this address's network: the address after
+     * {@link endAddress}, with the same subnet mask. Throws `AddressError` when
+     * this network is the last one in the address space.
+     * @returns {Address4}
+     * @example
+     * new Address4('10.0.0.0/24').nextNetwork().networkForm(); // '10.0.1.0/24'
+     */
+    nextNetwork() {
+        return Address4.fromBigInt(common.offsetBigInt(this._endAddress(), 1, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
+    }
+    withSubnetMask(subnetMask) {
+        return new Address4(`${this.correctForm()}/${subnetMask}`);
+    }
     /**
      * Helper function getting end address.
      * @returns {bigint}
@@ -462,6 +511,43 @@ class Address4 {
     isCGNAT() {
         return this.isHostInSubnet(CGNAT_V4);
     }
+    /**
+     * Returns true if the address is in one of the documentation ranges
+     * `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)).
+     * @returns {boolean}
+     */
+    isDocumentation() {
+        return DOCUMENTATION_V4.some((subnet) => this.isHostInSubnet(subnet));
+    }
+    /**
+     * Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)).
+     * @returns {boolean}
+     */
+    isBenchmarking() {
+        return this.isHostInSubnet(BENCHMARKING_V4);
+    }
+    /**
+     * Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)),
+     * which includes the limited broadcast address.
+     * @returns {boolean}
+     */
+    isReserved() {
+        return this.isHostInSubnet(RESERVED_V4);
+    }
+    /**
+     * Returns true if the address is globally reachable: not multicast, and not
+     * in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/)
+     * marks as not globally reachable. That covers everything the individual
+     * classifiers name (private, loopback, link-local, CGNAT, unspecified,
+     * broadcast, documentation, benchmarking, reserved) and the blocks they do
+     * not, such as `0.0.0.0/8` and the IETF protocol assignments in
+     * `192.0.0.0/24`. This is the single predicate to use where a request must
+     * not reach an internal or special-purpose destination; see SECURITY.md.
+     * @returns {boolean}
+     */
+    isGlobal() {
+        return !this.isMulticast() && common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V4);
+    }
     /**
      * Returns a zero-padded base-2 string representation of the address
      * @returns {string}
@@ -502,4 +588,15 @@ const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
 const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
 const BROADCAST_V4 = new Address4('255.255.255.255/32');
 const CGNAT_V4 = new Address4('100.64.0.0/10');
+const DOCUMENTATION_V4 = [
+    new Address4('192.0.2.0/24'),
+    new Address4('198.51.100.0/24'),
+    new Address4('203.0.113.0/24'),
+];
+const BENCHMARKING_V4 = new Address4('198.18.0.0/15');
+const RESERVED_V4 = new Address4('240.0.0.0/4');
+const SPECIAL_PURPOSE_V4 = constants.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
+    subnet: new Address4(cidr),
+    reachable,
+}));
 //# sourceMappingURL=ipv4.js.map
\ No newline at end of file
diff --git a/deps/npm/node_modules/ip-address/dist/ipv6.js b/deps/npm/node_modules/ip-address/dist/ipv6.js
index d5f4fdb9c87..e1c840c02b9 100644
--- a/deps/npm/node_modules/ip-address/dist/ipv6.js
+++ b/deps/npm/node_modules/ip-address/dist/ipv6.js
@@ -92,7 +92,9 @@ class Address6 {
         this.zone = '';
         // #region Attributes
         /**
-         * Returns true if the given address is in the subnet of the current address
+         * Returns true if the given address is in the subnet of the current address.
+         * An `Address4` is never in the subnet of an `Address6`; convert with
+         * `Address6.fromAddress4()` or `to4()` to compare across families.
          * @returns {boolean}
          */
         this.isInSubnet = common.isInSubnet;
@@ -102,6 +104,8 @@ class Address6 {
          * when classifying a single address, so the answer doesn't change with the
          * CIDR suffix the caller happened to write — notably when the address came
          * from untrusted input and the result backs a trust-boundary decision.
+         * An `Address4` is never in the subnet of an `Address6`; convert with
+         * `Address6.fromAddress4()` or `to4()` to compare across families.
          * @returns {boolean}
          */
         this.isHostInSubnet = common.isHostInSubnet;
@@ -135,10 +139,23 @@ class Address6 {
         if (/\//.test(address)) {
             throw new address_error_1.AddressError('Invalid subnet mask.');
         }
-        const zone = constants6.RE_ZONE_STRING.exec(address);
-        if (zone) {
-            this.zone = zone[0];
-            address = address.replace(constants6.RE_ZONE_STRING, '');
+        // A zone runs from the first `%` to the end of the input and holds no line
+        // terminator. Finding it by index reads the input once, where matching
+        // RE_ZONE_STRING retries from every `%` that a line terminator disqualifies.
+        const zoneStart = address.indexOf('%');
+        if (zoneStart !== -1 && /^.*$/.test(address.slice(zoneStart))) {
+            this.zone = address.slice(zoneStart);
+            address = address.slice(0, zoneStart);
+        }
+        // The longest well-formed address is all but the last two groups written
+        // as four hex digits with their colons, then a 15-character dotted quad:
+        // 5 * (groups - 2) + 15, which is 45 for eight groups, the same line
+        // CPython's ipaddress module draws. Rejecting longer input here keeps the
+        // parse diagnostics, which wrap every offending character in a span,
+        // proportional to an address rather than to whatever was passed in.
+        const longest = this.groups * 5 + 5;
+        if (address.length > longest) {
+            throw new address_error_1.AddressError(`IPv6 addresses are at most ${longest} characters.`);
         }
         this.addressMinusSuffix = address;
         this.parsedAddress = this.parse(this.addressMinusSuffix);
@@ -339,28 +356,32 @@ class Address6 {
         return new Address6(`::ffff:${address4.correctForm()}/${mask6}`);
     }
     /**
-     * Return an address from ip6.arpa form
+     * Return an address from ip6.arpa form. A full 32-nibble name gives a /128
+     * address; a shorter name, as used for a delegated reverse zone, gives the
+     * network it covers, with a subnet mask of four bits per nibble, so
+     * `fromArpa(x.reverseForm())` round-trips {@link reverseForm} for any prefix.
      * @param {string} arpaFormAddress - an 'ip6.arpa' form address
      * @returns {Adress6}
      * @example
      * var address = Address6.fromArpa(e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.)
      * address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe'
+     * Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa.').networkForm(); // '2001:db8::/32'
      */
     static fromArpa(arpaFormAddress) {
-        // remove ending ".ip6.arpa." or just "."
-        let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, '');
-        const semicolonAmount = 7;
-        // correct ip6.arpa form with ending removed will be 63 characters
-        if (address.length !== 63) {
+        // remove an ending ".ip6.arpa", in any case and with or without the root
+        // dot
+        const nibbles = arpaFormAddress.replace(/(\.ip6\.arpa)?\.?$/i, '');
+        if (!/^[0-9a-f](\.[0-9a-f]){0,31}$/i.test(nibbles)) {
             throw new address_error_1.AddressError("Invalid 'ip6.arpa' form.");
         }
-        const parts = address.split('.').reverse();
-        for (let i = semicolonAmount; i > 0; i--) {
-            const insertIndex = i * 4;
-            parts.splice(insertIndex, 0, ':');
+        const reversed = nibbles.split('.').reverse();
+        const subnetMask = reversed.length * 4;
+        const hex = reversed.join('').padEnd(32, '0');
+        const groups = [];
+        for (let i = 0; i < constants6.GROUPS; i++) {
+            groups.push(hex.slice(i * 4, (i + 1) * 4));
         }
-        address = parts.join('');
-        return new Address6(address);
+        return new Address6(`${groups.join(':')}/${subnetMask}`);
     }
     /**
      * Return the Microsoft UNC transcription of the address
@@ -424,22 +445,53 @@ class Address6 {
         return BigInt(`0b${this.mask() + '1'.repeat(constants6.BITS - this.subnetMask)}`);
     }
     /**
-     * The last address in the range given by this address' subnet
-     * Often referred to as the Broadcast
+     * The last address in the range given by this address's subnet. IPv6 has
+     * no broadcast address, so this is an ordinary assignable address (in a
+     * 64-bit-interface-identifier subnet it falls inside the reserved
+     * subnet-anycast block of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526)).
      * @returns {Address6}
      */
     endAddress() {
         return Address6.fromBigInt(this._endAddress());
     }
     /**
-     * The last host address in the range given by this address's subnet ie
-     * the last address prior to the Broadcast Address
+     * The address one before {@link endAddress}. This is the IPv6 counterpart
+     * of the IPv4 method that skips the broadcast address; IPv6 has no broadcast,
+     * so it drops exactly one address and does not model the 128 reserved
+     * subnet-anycast identifiers of [RFC 2526](https://datatracker.ietf.org/doc/html/rfc2526).
      * @returns {Address6}
      */
     endAddressExclusive() {
         const adjust = BigInt('1');
         return Address6.fromBigInt(this._endAddress() - adjust);
     }
+    /**
+     * Returns the address `n` addresses after this one (or before, when `n` is
+     * negative), keeping this address's subnet mask. Throws `AddressError` when
+     * the result would fall outside the IPv6 address space or `n` is not an
+     * integer.
+     * @param {number | bigint} n
+     * @returns {Address6}
+     * @example
+     * new Address6('2001:db8::/64').offset(1).correctForm(); // '2001:db8::1'
+     */
+    offset(n) {
+        return Address6.fromBigInt(common.offsetBigInt(this.bigInt(), n, constants6.BITS, 'IPv6')).withSubnetMask(this.subnetMask);
+    }
+    /**
+     * Returns the network that follows this address's network: the address after
+     * {@link endAddress}, with the same subnet mask. Throws `AddressError` when
+     * this network is the last one in the address space.
+     * @returns {Address6}
+     * @example
+     * new Address6('2001:db8::/64').nextNetwork().networkForm(); // '2001:db8:0:1::/64'
+     */
+    nextNetwork() {
+        return Address6.fromBigInt(common.offsetBigInt(this._endAddress(), 1, constants6.BITS, 'IPv6')).withSubnetMask(this.subnetMask);
+    }
+    withSubnetMask(subnetMask) {
+        return new Address6(`${this.correctForm()}/${subnetMask}`);
+    }
     /**
      * The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
      * `/64`. Returns an `Address6`; call `.correctForm()` for the string.
@@ -1022,7 +1074,10 @@ class Address6 {
         return this.addressMinusSuffix === this.canonicalForm();
     }
     /**
-     * Returns true if the address is a link local address, false otherwise
+     * Returns true if the address is a link-local unicast address in `fe80::/10`
+     * ([RFC 4291 §2.4](https://datatracker.ietf.org/doc/html/rfc4291#section-2.4))
+     * or an IPv4-mapped / NAT64 address whose embedded IPv4 address is link-local
+     * (`169.254.0.0/16`, e.g. `::ffff:169.254.169.254`), false otherwise.
      * @returns {boolean}
      */
     isLinkLocal() {
@@ -1030,12 +1085,7 @@ class Address6 {
         if (embedded) {
             return embedded.isLinkLocal();
         }
-        // Zeroes are required, i.e. we can't check isHostInSubnet with 'fe80::/10'
-        if (this.getBitsBase2(0, 64) ===
-            '1111111010000000000000000000000000000000000000000000000000000000') {
-            return true;
-        }
-        return false;
+        return this.isHostInSubnet(LINK_LOCAL_SUBNET);
     }
     /**
      * Returns true if the address is a multicast address, false otherwise
@@ -1127,12 +1177,20 @@ class Address6 {
     }
     /**
      * Returns true if the address is private, i.e. a Unique Local Address in
-     * `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)) or an
-     * IPv4-mapped / NAT64 address whose embedded IPv4 address is in one of the
-     * [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private ranges
-     * (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to
+     * `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)), an
+     * address in the NAT64 local-use range `64:ff9b:1::/48`
+     * ([RFC 8215](https://datatracker.ietf.org/doc/html/rfc8215)), or an
+     * IPv4-mapped / NAT64 well-known address whose embedded IPv4 address is in
+     * one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918)
+     * private ranges (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to
      * {@link Address4.isPrivate}; use it instead of {@link isULA} when you need to
      * catch mapped RFC 1918 addresses as well as native ULAs.
+     *
+     * The local-use NAT64 range is reported private as a whole rather than by
+     * its embedded IPv4 address: an operator may carve a prefix of any RFC 6052
+     * length out of `64:ff9b:1::/48`, so the same bits decode to different IPv4
+     * addresses under different deployments and no single decoding is correct.
+     * Use {@link toAddress4Nat64} with the deployment's prefix to decode one.
      * @returns {boolean}
      */
     isPrivate() {
@@ -1140,7 +1198,7 @@ class Address6 {
         if (embedded) {
             return embedded.isPrivate();
         }
-        return this.isULA();
+        return this.isULA() || this.isHostInSubnet(NAT64_LOCAL_USE_SUBNET);
     }
     /**
      * Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
@@ -1188,7 +1246,49 @@ class Address6 {
      * @returns {boolean}
      */
     isDocumentation() {
-        return this.isHostInSubnet(DOCUMENTATION_SUBNET);
+        return DOCUMENTATION_SUBNETS.some((subnet) => this.isHostInSubnet(subnet));
+    }
+    /**
+     * Returns true if the address is in the benchmarking range `2001:2::/48`
+     * ([RFC 5180](https://datatracker.ietf.org/doc/html/rfc5180)) or is an
+     * IPv4-mapped / NAT64 address whose embedded IPv4 address is in
+     * `198.18.0.0/15`, false otherwise.
+     * @returns {boolean}
+     */
+    isBenchmarking() {
+        const embedded = this.embeddedIPv4();
+        if (embedded) {
+            return embedded.isBenchmarking();
+        }
+        return this.isHostInSubnet(BENCHMARKING_SUBNET);
+    }
+    /**
+     * Returns true if the address is globally reachable: inside the global
+     * unicast allocation `2000::/3` (the only range the [IANA IPv6 Address Space
+     * Registry](https://www.iana.org/assignments/ipv6-address-space/) assigns
+     * for global unicast; everything else is reserved, ULA, link-local, or
+     * multicast) and not in any block the [IANA IPv6 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv6-special-registry/)
+     * marks as not globally reachable. An IPv4-mapped or NAT64 well-known
+     * address answers for its embedded IPv4 address, so `::ffff:10.0.0.1` and
+     * `64:ff9b::7f00:1` are not global. Teredo (`2001::/32`) and 6to4
+     * (`2002::/16`) are not global either: the registry lists them as N/A and a
+     * packet to one needs a relay.
+     *
+     * This covers everything the individual classifiers name and the blocks they
+     * do not: the discard-only prefix `100::/64`, the IETF protocol assignments
+     * in `2001::/23`, the deprecated site-local `fec0::/10` and IPv4-compatible
+     * `::/96` ranges, and unallocated space such as `4000::/3`. It is the single
+     * predicate to use where a request must not reach an internal or
+     * special-purpose destination; see SECURITY.md.
+     * @returns {boolean}
+     */
+    isGlobal() {
+        const embedded = this.embeddedIPv4();
+        if (embedded) {
+            return embedded.isGlobal();
+        }
+        return (this.isHostInSubnet(GLOBAL_UNICAST_SUBNET) &&
+            common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V6));
     }
     // #endregion
     // #region HTML
@@ -1347,7 +1447,15 @@ const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
 const TEREDO_SUBNET = new Address6('2001::/32');
 const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
 const ULA_SUBNET = new Address6('fc00::/7');
-const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
+const LINK_LOCAL_SUBNET = new Address6('fe80::/10');
+const DOCUMENTATION_SUBNETS = [new Address6('2001:db8::/32'), new Address6('3fff::/20')];
+const BENCHMARKING_SUBNET = new Address6('2001:2::/48');
+const GLOBAL_UNICAST_SUBNET = new Address6('2000::/3');
+const SPECIAL_PURPOSE_V6 = constants6.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
+    subnet: new Address6(cidr),
+    reachable,
+}));
 const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
 const NAT64_WELL_KNOWN_SUBNET = new Address6('64:ff9b::/96');
+const NAT64_LOCAL_USE_SUBNET = new Address6('64:ff9b:1::/48');
 //# sourceMappingURL=ipv6.js.map
\ No newline at end of file
diff --git a/deps/npm/node_modules/ip-address/dist/v4/constants.js b/deps/npm/node_modules/ip-address/dist/v4/constants.js
index 158288b7de6..f25120d6068 100644
--- a/deps/npm/node_modules/ip-address/dist/v4/constants.js
+++ b/deps/npm/node_modules/ip-address/dist/v4/constants.js
@@ -1,6 +1,6 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
+exports.SPECIAL_PURPOSE = exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
 exports.BITS = 32;
 exports.GROUPS = 4;
 // Each octet is 0-255 written without a leading zero. A leading zero is
@@ -9,4 +9,43 @@ exports.GROUPS = 4;
 // disagree with the network stack about which host a string names.
 exports.RE_ADDRESS = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/g;
 exports.RE_SUBNET_STRING = /\/\d{1,2}$/;
+/**
+ * The IANA IPv4 Special-Purpose Address Registry
+ * (https://www.iana.org/assignments/iana-ipv4-special-registry/), one entry
+ * per block: `[cidr, name, globallyReachable]`. A `null` reachability means
+ * the registry leaves the column blank and the block inherits the answer of
+ * the block containing it (or is global when nothing contains it).
+ *
+ * `Address4.isGlobal()` answers from the most specific entry containing the
+ * address. `test/data/iana-corpus.json` is generated from the registry's CSV
+ * and pins this table to it.
+ */
+exports.SPECIAL_PURPOSE = [
+    ['0.0.0.0/8', 'This network', false],
+    ['0.0.0.0/32', 'This host on this network', false],
+    ['10.0.0.0/8', 'Private-Use', false],
+    ['100.64.0.0/10', 'Shared Address Space', false],
+    ['127.0.0.0/8', 'Loopback', false],
+    ['169.254.0.0/16', 'Link Local', false],
+    ['172.16.0.0/12', 'Private-Use', false],
+    ['192.0.0.0/24', 'IETF Protocol Assignments', false],
+    ['192.0.0.0/29', 'IPv4 Service Continuity Prefix', false],
+    ['192.0.0.8/32', 'IPv4 dummy address', false],
+    ['192.0.0.9/32', 'Port Control Protocol Anycast', true],
+    ['192.0.0.10/32', 'Traversal Using Relays around NAT Anycast', true],
+    ['192.0.0.170/32', 'NAT64/DNS64 Discovery', false],
+    ['192.0.0.171/32', 'NAT64/DNS64 Discovery', false],
+    ['192.0.2.0/24', 'Documentation (TEST-NET-1)', false],
+    ['192.31.196.0/24', 'AS112-v4', true],
+    ['192.52.193.0/24', 'AMT', true],
+    ['192.88.99.0/24', 'Deprecated (6to4 Relay Anycast)', null],
+    ['192.88.99.2/32', '6a44-relay anycast address', false],
+    ['192.168.0.0/16', 'Private-Use', false],
+    ['192.175.48.0/24', 'Direct Delegation AS112 Service', true],
+    ['198.18.0.0/15', 'Benchmarking', false],
+    ['198.51.100.0/24', 'Documentation (TEST-NET-2)', false],
+    ['203.0.113.0/24', 'Documentation (TEST-NET-3)', false],
+    ['240.0.0.0/4', 'Reserved', false],
+    ['255.255.255.255/32', 'Limited Broadcast', false],
+];
 //# sourceMappingURL=constants.js.map
\ No newline at end of file
diff --git a/deps/npm/node_modules/ip-address/dist/v6/constants.js b/deps/npm/node_modules/ip-address/dist/v6/constants.js
index 4616cad66b6..777146c1a1a 100644
--- a/deps/npm/node_modules/ip-address/dist/v6/constants.js
+++ b/deps/npm/node_modules/ip-address/dist/v6/constants.js
@@ -1,6 +1,6 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
+exports.SPECIAL_PURPOSE = exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
 exports.BITS = 128;
 exports.GROUPS = 8;
 /**
@@ -48,8 +48,14 @@ exports.TYPES = {
     'ff00::/8': 'Multicast',
     'fe80::/10': 'Link-local unicast',
     'fc00::/7': 'Unique local',
+    '2001::/32': 'Teredo',
+    '2001:2::/48': 'Benchmarking',
     '2002::/16': '6to4',
     '2001:db8::/32': 'Documentation',
+    '3fff::/20': 'Documentation',
+    '100::/64': 'Discard-only',
+    'fec0::/10': 'Site-local unicast (deprecated)',
+    '::/96': 'IPv4-compatible (deprecated)',
     '64:ff9b::/96': 'NAT64 (well-known)',
     '64:ff9b:1::/48': 'NAT64 (local-use)',
 };
@@ -75,8 +81,51 @@ exports.RE_SUBNET_STRING = /\/\d{1,3}(?=%|$)/;
  * A regular expression that matches an IPv6 zone
  * @memberof Address6
  * @static
+ * @deprecated Takes quadratic time on input holding many `%` characters
+ * followed by a line terminator. The library finds the zone by index, as
+ * `Address6`'s constructor shows, and 11.0.0 removes this export.
  */
 exports.RE_ZONE_STRING = /%.*$/;
 exports.RE_URL = /^(?:\[([0-9a-f:.]+)\]|([0-9a-f:.]+))(?:[/?#].*)?$/i;
 exports.RE_URL_WITH_PORT = /^\[([0-9a-f:.]+)\]:([0-9]{1,5})(?:[/?#].*)?$/i;
+/**
+ * The IANA IPv6 Special-Purpose Address Registry
+ * (https://www.iana.org/assignments/iana-ipv6-special-registry/), one entry
+ * per block: `[cidr, name, globallyReachable]`. A `null` reachability means
+ * the registry says N/A or leaves the column blank; N/A blocks (Teredo, 6to4)
+ * are treated as not globally reachable, since a packet to one needs a relay,
+ * and blank blocks inherit the answer of the block containing them.
+ *
+ * `Address6.isGlobal()` answers from the most specific entry containing the
+ * address, after delegating IPv4-mapped and NAT64 well-known addresses to the
+ * embedded IPv4 address. `test/data/iana-corpus.json` is generated from the
+ * registry's CSV and pins this table to it.
+ */
+exports.SPECIAL_PURPOSE = [
+    ['::1/128', 'Loopback Address', false],
+    ['::/128', 'Unspecified Address', false],
+    ['::ffff:0:0/96', 'IPv4-mapped Address', false],
+    ['64:ff9b::/96', 'IPv4-IPv6 Translat.', true],
+    ['64:ff9b:1::/48', 'IPv4-IPv6 Translat.', false],
+    ['100::/64', 'Discard-Only Address Block', false],
+    ['100:0:0:1::/64', 'Dummy IPv6 Prefix', false],
+    ['2001::/23', 'IETF Protocol Assignments', false],
+    ['2001::/32', 'TEREDO', false],
+    ['2001:1::1/128', 'Port Control Protocol Anycast', true],
+    ['2001:1::2/128', 'Traversal Using Relays around NAT Anycast', true],
+    ['2001:1::3/128', 'DNS-SD Service Registration Protocol Anycast', true],
+    ['2001:2::/48', 'Benchmarking', false],
+    ['2001:3::/32', 'AMT', true],
+    ['2001:4:112::/48', 'AS112-v6', true],
+    ['2001:10::/28', 'Deprecated (previously ORCHID)', null],
+    ['2001:20::/28', 'ORCHIDv2', true],
+    ['2001:30::/28', 'Drone Remote ID Protocol Entity Tags (DETs) Prefix', true],
+    ['2001:db8::/32', 'Documentation', false],
+    ['2002::/16', '6to4', false],
+    ['2620:4f:8000::/48', 'Direct Delegation AS112 Service', true],
+    ['3fff::/20', 'Documentation', false],
+    ['5f00::/16', 'Segment Routing (SRv6) SIDs', false],
+    ['fc00::/7', 'Unique-Local', false],
+    ['fe80::/10', 'Link-Local Unicast', false],
+];
 //# sourceMappingURL=constants.js.map
\ No newline at end of file
diff --git a/deps/npm/node_modules/ip-address/package.json b/deps/npm/node_modules/ip-address/package.json
index 6ea2d24bd62..ee0bdeca619 100644
--- a/deps/npm/node_modules/ip-address/package.json
+++ b/deps/npm/node_modules/ip-address/package.json
@@ -16,13 +16,14 @@
     "bigint",
     "browser"
   ],
-  "version": "10.5.0",
+  "version": "10.7.5",
   "author": "Beau Gunderson <beau@beaugunderson.com> (https://beaugunderson.com/)",
   "license": "MIT",
   "main": "dist/ip-address.js",
   "types": "dist/ip-address.d.ts",
   "scripts": {
     "docs": "tsx scripts/build-readme.ts",
+    "docs:check": "tsx scripts/build-readme.ts --check",
     "build": "rm -rf dist; mkdir dist; tsc",
     "prepack": "npm run docs && npm run build",
     "prepare": "git config core.hooksPath hooks || true",
@@ -79,7 +80,7 @@
     "eslint-plugin-import": "^2.32.0",
     "eslint-plugin-prettier": "^5.5.5",
     "eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
-    "mocha": "^11.7.5",
+    "mocha": "^12.0.3",
     "monocart-coverage-reports": "^2.12.11",
     "prettier": "^3.8.3",
     "source-map-support": "^0.5.21",
diff --git a/deps/npm/node_modules/libnpmdiff/package.json b/deps/npm/node_modules/libnpmdiff/package.json
index d36879f339b..8f6c89c9bd5 100644
--- a/deps/npm/node_modules/libnpmdiff/package.json
+++ b/deps/npm/node_modules/libnpmdiff/package.json
@@ -1,6 +1,6 @@
 {
   "name": "libnpmdiff",
-  "version": "9.0.3",
+  "version": "9.0.4",
   "description": "The registry diff",
   "repository": {
     "type": "git",
@@ -47,7 +47,7 @@
     "tap": "^16.3.8"
   },
   "dependencies": {
-    "@npmcli/arborist": "^10.0.3",
+    "@npmcli/arborist": "^10.0.4",
     "@npmcli/installed-package-contents": "^5.0.0",
     "binary-extensions": "^3.0.0",
     "diff": "^8.0.2",
diff --git a/deps/npm/node_modules/libnpmexec/README.md b/deps/npm/node_modules/libnpmexec/README.md
index 84512ac5904..59c35f8a639 100644
--- a/deps/npm/node_modules/libnpmexec/README.md
+++ b/deps/npm/node_modules/libnpmexec/README.md
@@ -28,7 +28,7 @@ await libexec({

 - `opts`:
   - `args`: List of pkgs to execute **Array<String>**, defaults to `[]`
-  - `call`: An alternative command to run when using `packages` option **String**, defaults to empty string.
+  - `call`: An alternative shell script to run when using `packages` option **String**, defaults to empty string. Unlike an executable selected from `args` or a package's `bin`, this is intentionally interpreted as shell syntax.
   - `cache`: The path location to where the npm cache folder is placed **String**
   - `npxCache`: The path location to where the npx cache folder is placed **String**
   - `chalk`: Chalk instance to use for colors? **Required**
@@ -42,6 +42,14 @@ await libexec({
   - `yes`: Should skip download confirmation prompt when fetching missing packages from the registry? **Boolean**
   - `registry`, `cache`, and more options that are forwarded to [@npmcli/arborist](https://github.com/npm/cli/blob/latest/workspaces/arborist/README.md) and [pacote](https://github.com/npm/pacote/#options) **Object**

+  Executable names are escaped for the selected shell, including POSIX shells and
+  PowerShell used on Windows. For inferred PowerShell invocations, arguments are
+  also escaped as literal strings. With `cmd.exe`, executable names containing double
+  quotes, percent signs, exclamation marks, or control characters are rejected
+  with `EINVALIDCOMMAND`. Use a bin name without these characters. On a matching
+  npx-cache hit, command selection uses the installed package's `bin` rather than
+  the registry's bin metadata.
+
 ## LICENSE

 [ISC](./LICENSE)
diff --git a/deps/npm/node_modules/libnpmexec/lib/index.js b/deps/npm/node_modules/libnpmexec/lib/index.js
index 4d7c1266546..56dcf7c7369 100644
--- a/deps/npm/node_modules/libnpmexec/lib/index.js
+++ b/deps/npm/node_modules/libnpmexec/lib/index.js
@@ -267,8 +267,8 @@ const exec = async (opts) => {
     })
     const lockPath = join(installDir, 'concurrency.lock')
     const npxTree = await withLock(lockPath, () => npxArb.loadActual())
-    await Promise.all(needInstall.map(async ({ spec }) => {
-      const { manifest } = await missingFromTree({
+    await Promise.all(needInstall.map(async ({ spec, manifest: requestedManifest }) => {
+      const { manifest, node } = await missingFromTree({
         spec,
         tree: npxTree,
         flatOptions,
@@ -281,6 +281,10 @@ const exec = async (opts) => {
         } else {
           add.push(manifest._id)
         }
+      } else if (needPackageCommandSwap && commandManifest === requestedManifest) {
+        // A cache hit must use the installed bin, not mutable registry metadata.
+        commandManifest = node.package
+        args[0] = getBinFromManifest(commandManifest)
       }
     }))

diff --git a/deps/npm/node_modules/libnpmexec/lib/run-script.js b/deps/npm/node_modules/libnpmexec/lib/run-script.js
index 2de40454f9d..a7ce6915c74 100644
--- a/deps/npm/node_modules/libnpmexec/lib/run-script.js
+++ b/deps/npm/node_modules/libnpmexec/lib/run-script.js
@@ -3,7 +3,10 @@ const runScript = require('@npmcli/run-script')
 const pkgJson = require('@npmcli/package-json')
 const { log, output } = require('proc-log')
 const noTTY = require('./no-tty.js')
-const isWindowsShell = require('./is-windows.js')
+const isWindows = require('./is-windows.js')
+
+const isCmd = shell => /(?:^|[\\/])cmd(?:\.exe)?$/i.test(shell)
+const isPowerShell = shell => /(?:^|[\\/])(?:powershell|pwsh)(?:\.exe)?$/i.test(shell)

 const run = async ({
   args,
@@ -15,10 +18,24 @@ const run = async ({
   runPath,
   scriptShell,
 }) => {
-  // escape executable path
-  // necessary for preventing bash/cmd keywords from overriding
-  if (!isWindowsShell) {
-    if (args.length > 0) {
+  if (!call && args.length > 0) {
+    const shell = scriptShell || (isWindows ? process.env.ComSpec || 'cmd' : 'sh')
+    if (isCmd(shell)) {
+      // Variable expansion (including delayed expansion) and embedded quotes
+      // cannot be safely escaped here. Control characters are invalid filenames.
+      if (/["%!]/.test(args[0]) || [...args[0]].some(c => c.charCodeAt(0) < 32)) {
+        throw Object.assign(
+          new Error(`Invalid executable name for cmd.exe: ${JSON.stringify(args[0])}`),
+          { code: 'EINVALIDCOMMAND' }
+        )
+      }
+      // Protect both cmd.exe's metacharacter parsing and executable-name parsing.
+      args[0] = `"${args[0]}"`.replace(/[ ^&()<>|";,*?=@]/g, '^$&')
+    } else if (isPowerShell(shell)) {
+      // Encode the whole invocation to avoid promise-spawn's POSIX argument escaping.
+      const quotedArgs = args.map(arg => `'${arg.replace(/['\u2018-\u201b]/g, '$&$&')}'`)
+      args = [`& ${quotedArgs.join(' ')}`]
+    } else {
       // single-quote so shell metacharacters in the executable name are taken
       // literally; double quotes still expand $(), backticks, $var and "
       args[0] = `'${args[0].replace(/'/g, `'\\''`)}'`
diff --git a/deps/npm/node_modules/libnpmexec/package.json b/deps/npm/node_modules/libnpmexec/package.json
index f7a5e16db36..0479de86500 100644
--- a/deps/npm/node_modules/libnpmexec/package.json
+++ b/deps/npm/node_modules/libnpmexec/package.json
@@ -1,6 +1,6 @@
 {
   "name": "libnpmexec",
-  "version": "11.0.3",
+  "version": "11.0.5",
   "files": [
     "bin/",
     "lib/"
@@ -65,7 +65,7 @@
   },
   "dependencies": {
     "@gar/promise-retry": "^1.0.0",
-    "@npmcli/arborist": "^10.0.3",
+    "@npmcli/arborist": "^10.0.4",
     "@npmcli/package-json": "^8.0.0",
     "@npmcli/run-script": "^11.0.0",
     "ci-info": "^4.0.0",
diff --git a/deps/npm/node_modules/libnpmfund/package.json b/deps/npm/node_modules/libnpmfund/package.json
index 7946efb2a22..1019a8a788a 100644
--- a/deps/npm/node_modules/libnpmfund/package.json
+++ b/deps/npm/node_modules/libnpmfund/package.json
@@ -1,6 +1,6 @@
 {
   "name": "libnpmfund",
-  "version": "8.0.3",
+  "version": "8.0.4",
   "main": "lib/index.js",
   "files": [
     "bin/",
@@ -46,7 +46,7 @@
     "tap": "^16.3.8"
   },
   "dependencies": {
-    "@npmcli/arborist": "^10.0.3"
+    "@npmcli/arborist": "^10.0.4"
   },
   "engines": {
     "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
diff --git a/deps/npm/node_modules/libnpmpack/package.json b/deps/npm/node_modules/libnpmpack/package.json
index fd5150a7b64..5a33b697646 100644
--- a/deps/npm/node_modules/libnpmpack/package.json
+++ b/deps/npm/node_modules/libnpmpack/package.json
@@ -1,6 +1,6 @@
 {
   "name": "libnpmpack",
-  "version": "10.0.3",
+  "version": "10.0.4",
   "description": "Programmatic API for the bits behind npm pack",
   "author": "GitHub Inc.",
   "main": "lib/index.js",
@@ -37,7 +37,7 @@
   "bugs": "https://github.com/npm/libnpmpack/issues",
   "homepage": "https://npmjs.com/package/libnpmpack",
   "dependencies": {
-    "@npmcli/arborist": "^10.0.3",
+    "@npmcli/arborist": "^10.0.4",
     "@npmcli/run-script": "^11.0.0",
     "npm-package-arg": "^14.0.0",
     "pacote": "^22.0.0"
diff --git a/deps/npm/node_modules/pacote/lib/registry.js b/deps/npm/node_modules/pacote/lib/registry.js
index f50b27956db..25278564da9 100644
--- a/deps/npm/node_modules/pacote/lib/registry.js
+++ b/deps/npm/node_modules/pacote/lib/registry.js
@@ -113,6 +113,70 @@ class RegistryFetcher extends Fetcher {
     }
   }

+  // Registry signatures and attestations authenticate `name@version`, so the
+  // manifest must claim the requested name and be listed under its own
+  // version.  Otherwise a registry could replay validly signed metadata from
+  // another package (or another version) and have it verify as this one.
+  #verifyManifestIdentity (packument, picked) {
+    const pickedId = `${picked.name}@${picked.version}`
+    if (picked.name !== this.spec.name) {
+      const message = [
+        `${this.spec.name} registry manifest has mismatched package name:`,
+        `expected ${this.spec.name} but got ${pickedId}`,
+      ].join(' ')
+      throw Object.assign(new Error(message), {
+        code: 'EMANIFESTMISMATCH',
+        expected: this.spec.name,
+        found: pickedId,
+      })
+    }
+    if (picked._id && picked._id !== pickedId) {
+      const message = [
+        `${pickedId} registry manifest has mismatched id:`,
+        `expected ${pickedId} but got ${picked._id}`,
+      ].join(' ')
+      throw Object.assign(new Error(message), {
+        code: 'EMANIFESTMISMATCH',
+        expected: pickedId,
+        found: picked._id,
+      })
+    }
+
+    // without dist there are no signatures or attestations to authenticate
+    if (!picked.dist) {
+      return
+    }
+
+    // npm-pick-manifest may return a shallow copy, so match on the dist object
+    const matchesPickedManifest = manifest => manifest.dist === picked.dist
+    const versionCollections = [
+      packument.versions,
+      packument.stagedVersions?.versions,
+      packument.policyRestrictions?.versions,
+    ]
+    const matchingVersionKeys = []
+    for (const manifestsByVersion of versionCollections) {
+      for (const versionKey in manifestsByVersion) {
+        if (Object.hasOwn(manifestsByVersion, versionKey) &&
+            matchesPickedManifest(manifestsByVersion[versionKey])) {
+          matchingVersionKeys.push(versionKey)
+        }
+      }
+    }
+
+    if (matchingVersionKeys.some(versionKey => versionKey !== picked.version)) {
+      const message = [
+        `${pickedId} registry manifest has mismatched version:`,
+        `listed in the packument as ${matchingVersionKeys.join(', ')}`,
+      ].join(' ')
+      throw Object.assign(new Error(message), {
+        code: 'EMANIFESTMISMATCH',
+        expected: matchingVersionKeys,
+        found: pickedId,
+      })
+    }
+  }
+
   async manifest () {
     if (this.package) {
       return this.package
@@ -127,11 +191,16 @@ class RegistryFetcher extends Fetcher {

     const packument = await this.packument()
     const steps = PackageJson.normalizeSteps.filter(s => s !== '_attributes')
-    const mani = await new PackageJson().fromContent(pickManifest(packument, this.spec.fetchSpec, {
+    const picked = pickManifest(packument, this.spec.fetchSpec, {
       ...this.opts,
       defaultTag: this.defaultTag,
       before: this.before,
-    })).normalize({ steps }).then(p => p.content)
+    })
+    if (this.opts.verifySignatures || this.opts.verifyAttestations) {
+      this.#verifyManifestIdentity(packument, picked)
+    }
+    const mani = await new PackageJson().fromContent(picked)
+      .normalize({ steps }).then(p => p.content)

     /* XXX add ETARGET and E403 revalidation of cached packuments here */

diff --git a/deps/npm/node_modules/pacote/package.json b/deps/npm/node_modules/pacote/package.json
index 2e544354ef8..44339363065 100644
--- a/deps/npm/node_modules/pacote/package.json
+++ b/deps/npm/node_modules/pacote/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pacote",
-  "version": "22.0.0",
+  "version": "22.0.1",
   "description": "JavaScript package downloader",
   "author": "GitHub Inc.",
   "bin": {
@@ -26,9 +26,9 @@
     ]
   },
   "devDependencies": {
-    "@npmcli/arborist": "^9.0.2",
+    "@npmcli/arborist": "^10.0.1",
     "@npmcli/eslint-config": "^7.0.0",
-    "@npmcli/template-oss": "5.1.0",
+    "@npmcli/template-oss": "5.1.1",
     "hosted-git-info": "^10.1.1",
     "mutate-fs": "^2.1.1",
     "nock": "^13.2.4",
@@ -73,7 +73,7 @@
   },
   "templateOSS": {
     "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
-    "version": "5.1.0",
+    "version": "5.1.1",
     "windowsCI": false,
     "publish": "true",
     "updateNpm": false
diff --git a/deps/npm/node_modules/postcss-selector-parser/dist/parser.js b/deps/npm/node_modules/postcss-selector-parser/dist/parser.js
index d462e71aad7..50cf16a86fe 100644
--- a/deps/npm/node_modules/postcss-selector-parser/dist/parser.js
+++ b/deps/npm/node_modules/postcss-selector-parser/dist/parser.js
@@ -154,8 +154,9 @@ function indexesOf(array, item) {
     return indexes;
 }
 function uniqs() {
-    var list = Array.prototype.concat.apply([], arguments);
-    return list.filter(function (item, i) { return i === list.indexOf(item); });
+    // A Set keeps the first-occurrence order the previous filter/indexOf pass
+    // produced, without its quadratic cost on long index lists.
+    return Array.from(new Set(Array.prototype.concat.apply([], arguments)));
 }
 var Parser = /** @class */ (function () {
     function Parser(rule, options) {
@@ -200,6 +201,11 @@ var Parser = /** @class */ (function () {
             attr.push(this.currToken);
             this.position++;
         }
+        if (!this.currToken) {
+            // Ran off the end of the token stream: the attribute was never closed.
+            // Point at the opening bracket, which is where the author needs to look.
+            return this.expected("closing square bracket", startingToken[tokenize_1.FIELDS.START_POS]);
+        }
         if (this.currToken[tokenize_1.FIELDS.TYPE] !== tokens.closeSquare) {
             return this.expected("closing square bracket", this.currToken[tokenize_1.FIELDS.START_POS]);
         }
@@ -260,7 +266,7 @@ var Parser = /** @class */ (function () {
                         }
                         if (commentBefore) {
                             (0, util_1.ensureObject)(node, "raws", "spaces", "attribute");
-                            node.raws.spaces.attribute.before = spaceBefore;
+                            node.raws.spaces.attribute.before = commentBefore;
                             commentBefore = "";
                         }
                         node.namespace = (node.namespace || "") + content;
@@ -686,7 +692,21 @@ var Parser = /** @class */ (function () {
         return this.error("Unexpected '|'.", this.currToken[tokenize_1.FIELDS.START_POS]);
     };
     Parser.prototype.namespace = function () {
-        var before = (this.prevToken && this.content(this.prevToken)) || true;
+        var prev = this.prevToken;
+        // Only treat the previous token as a namespace prefix when it can actually
+        // be one (a type/word or the universal `*`). A comment, comma, combinator
+        // or whitespace before `|` means an empty namespace, not a prefix.
+        var before = prev &&
+            (prev[tokenize_1.FIELDS.TYPE] === tokens.word ||
+                prev[tokenize_1.FIELDS.TYPE] === tokens.asterisk ||
+                prev[tokenize_1.FIELDS.TYPE] === tokens.ampersand)
+            ? this.content(prev)
+            : true;
+        if (!this.nextToken) {
+            // A trailing `|` with nothing after it. `unexpectedPipe` reports against
+            // `currToken`, which is the pipe itself and always present here.
+            return this.unexpectedPipe();
+        }
         if (this.nextToken[tokenize_1.FIELDS.TYPE] === tokens.word) {
             this.position++;
             return this.word(before);
@@ -716,6 +736,7 @@ var Parser = /** @class */ (function () {
     Parser.prototype.parentheses = function () {
         var last = this.current.last;
         var unbalanced = 1;
+        var openingToken = this.currToken;
         this.position++;
         if (last && last.type === types.PSEUDO) {
             var selector = new selector_1.default({
@@ -785,7 +806,9 @@ var Parser = /** @class */ (function () {
             }
         }
         if (unbalanced) {
-            return this.expected("closing parenthesis", this.currToken[tokenize_1.FIELDS.START_POS]);
+            // `currToken` is undefined when the token stream ran out before the
+            // parenthesis was closed; fall back to the opening one.
+            return this.expected("closing parenthesis", (this.currToken || openingToken)[tokenize_1.FIELDS.START_POS]);
         }
     };
     Parser.prototype.pseudo = function () {
@@ -890,8 +913,14 @@ var Parser = /** @class */ (function () {
         // Eliminate Sass interpolations from the list of id indexes
         var interpolations = indexesOf(word, "#{");
         if (interpolations.length) {
-            hasId = hasId.filter(function (hashIndex) { return !~interpolations.indexOf(hashIndex); });
+            var interpolationIndexes_1 = new Set(interpolations);
+            hasId = hasId.filter(function (hashIndex) { return !interpolationIndexes_1.has(hashIndex); });
         }
+        // Membership tests are built once. Scanning the arrays per index would make
+        // a flat selector such as `.a.a.a...` quadratic in its number of class/id
+        // indexes, which is enough to pin a CPU core on attacker-supplied input.
+        var classIndexes = new Set(hasClass);
+        var idIndexes = new Set(hasId);
         var indices = (0, sortAscending_1.default)(uniqs(__spreadArray(__spreadArray([0], __read(hasClass), false), __read(hasId), false)));
         indices.forEach(function (ind, i) {
             var index = indices[i + 1] || word.length;
@@ -903,7 +932,7 @@ var Parser = /** @class */ (function () {
             var current = _this.currToken;
             var sourceIndex = current[tokenize_1.FIELDS.START_POS] + indices[i];
             var source = getSource(current[1], current[2] + ind, current[3], current[2] + (index - 1));
-            if (~hasClass.indexOf(ind)) {
+            if (classIndexes.has(ind)) {
                 var classNameOpts = {
                     value: value.slice(1),
                     source: source,
@@ -911,7 +940,7 @@ var Parser = /** @class */ (function () {
                 };
                 node = new className_1.default(unescapeProp(classNameOpts, "value"));
             }
-            else if (~hasId.indexOf(ind)) {
+            else if (idIndexes.has(ind)) {
                 var idOpts = {
                     value: value.slice(1),
                     source: source,
diff --git a/deps/npm/node_modules/postcss-selector-parser/package.json b/deps/npm/node_modules/postcss-selector-parser/package.json
index 12b12199b43..5a7f19963ff 100644
--- a/deps/npm/node_modules/postcss-selector-parser/package.json
+++ b/deps/npm/node_modules/postcss-selector-parser/package.json
@@ -1,7 +1,7 @@
 {
   "name": "postcss-selector-parser",
   "description": "Selector parser with built in methods for working with selector strings.",
-  "version": "7.1.4",
+  "version": "7.1.6",
   "devDependencies": {
     "oxfmt": "^0.54.0",
     "oxlint": "^1.69.0",
@@ -45,6 +45,10 @@
   },
   "homepage": "https://github.com/postcss/postcss-selector-parser",
   "contributors": [
+    {
+      "name": "Maxime Thirouin",
+      "url": "https://moox.io"
+    },
     {
       "name": "Ben Briggs",
       "email": "beneb.info@gmail.com",
@@ -52,8 +56,7 @@
     },
     {
       "name": "Chris Eppstein",
-      "email": "chris@eppsteins.net",
-      "url": "http://twitter.com/chriseppstein"
+      "email": "chris@eppsteins.net"
     }
   ],
   "repository": {
diff --git a/deps/npm/node_modules/semver/classes/range.js b/deps/npm/node_modules/semver/classes/range.js
index a7d6556febb..a14845a9668 100644
--- a/deps/npm/node_modules/semver/classes/range.js
+++ b/deps/npm/node_modules/semver/classes/range.js
@@ -119,7 +119,7 @@ class Range {
     debug('hyphen replace', range)

     // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
-    range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
+    range = trimComparatorWhitespace(range)
     debug('comparator trim', range)

     // `~ 1.2.3` => `~1.2.3`
@@ -224,11 +224,11 @@ const parseOptions = require('../internal/parse-options')
 const Comparator = require('./comparator')
 const debug = require('../internal/debug')
 const SemVer = require('./semver')
+const trimComparatorWhitespace = require('../internal/trim-comparator-whitespace')
 const {
   safeRe: re,
   src,
   t,
-  comparatorTrimReplace,
   tildeTrimReplace,
   caretTrimReplace,
 } = require('../internal/re')
diff --git a/deps/npm/node_modules/semver/internal/constants.js b/deps/npm/node_modules/semver/internal/constants.js
index 6d1db915433..0c8d4ba26b1 100644
--- a/deps/npm/node_modules/semver/internal/constants.js
+++ b/deps/npm/node_modules/semver/internal/constants.js
@@ -15,6 +15,35 @@ const MAX_SAFE_COMPONENT_LENGTH = 16
 // the shortest version with a build 0.0.0+BUILD.
 const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6

+// ECMAScript whitespace and line terminators matched by \s.
+const WHITESPACE_CHARACTERS = [
+  '\t',
+  '\n',
+  '\v',
+  '\f',
+  '\r',
+  ' ',
+  '\u00a0',
+  '\u1680',
+  '\u2000',
+  '\u2001',
+  '\u2002',
+  '\u2003',
+  '\u2004',
+  '\u2005',
+  '\u2006',
+  '\u2007',
+  '\u2008',
+  '\u2009',
+  '\u200a',
+  '\u2028',
+  '\u2029',
+  '\u202f',
+  '\u205f',
+  '\u3000',
+  '\ufeff',
+]
+
 const RELEASE_TYPES = [
   'major',
   'premajor',
@@ -30,6 +59,7 @@ module.exports = {
   MAX_SAFE_COMPONENT_LENGTH,
   MAX_SAFE_BUILD_LENGTH,
   MAX_SAFE_INTEGER,
+  WHITESPACE_CHARACTERS,
   RELEASE_TYPES,
   SEMVER_SPEC_VERSION,
   FLAG_INCLUDE_PRERELEASE: 0b001,
diff --git a/deps/npm/node_modules/semver/internal/trim-comparator-whitespace.js b/deps/npm/node_modules/semver/internal/trim-comparator-whitespace.js
new file mode 100644
index 00000000000..de6e6387b6b
--- /dev/null
+++ b/deps/npm/node_modules/semver/internal/trim-comparator-whitespace.js
@@ -0,0 +1,438 @@
+// @ts-check
+'use strict'
+
+// Reproduce safeRe[COMPARATORTRIM] replacement boundaries, not version
+// validation. Each end-index finder returns an exclusive end, or its start
+// on no match.
+// Positions count from zero. An end of 3 means characters 0, 1, and 2 were read;
+// range.slice(start, end) gives the matched text, not a converted number.
+const {
+  MAX_LENGTH,
+  MAX_SAFE_BUILD_LENGTH,
+  WHITESPACE_CHARACTERS,
+} = require('./constants')
+
+/**
+ * Remembers the last two rows of digits so their characters need not be reread.
+ * Positions start at -1 until a row has been found.
+ *
+ * @typedef {object} DigitRunCache
+ * @property {number} start The first character of the most recently found row.
+ * @property {number} end The position after that row's last character.
+ * @property {number} previousStart The first character of the previous row.
+ * @property {number} previousEnd The position after the previous row.
+ */
+
+// One entry per UTF-16 code unit keeps membership checks constant-time.
+const whitespace = new Uint8Array(0x10000)
+for (const char of WHITESPACE_CHARACTERS) {
+  whitespace[char.charCodeAt(0)] = 1
+}
+
+/**
+ * Checks whether a character is whitespace, like a space, tab, or newline.
+ * Looking past the end of the string returns false.
+ *
+ * @param {string|undefined} char One character, or undefined past the string's end.
+ * @returns {boolean} Whether the character is whitespace.
+ * @example isWhitespace(' ') // true
+ * @example isWhitespace('1') // false
+ */
+const isWhitespace = char =>
+  char !== undefined && whitespace[char.charCodeAt(0)] === 1
+
+/**
+ * Checks for v, =, or whitespace before the version number.
+ * These are historical version prefixes, not range operators:
+ * < and > are handled separately, as are tilde and caret ranges.
+ *
+ * @param {string|undefined} char One character to check.
+ * @returns {boolean} Whether the character can belong to a version prefix.
+ * @example isVersionPrefix('=') // true
+ * @example isVersionPrefix('>') // false
+ */
+const isVersionPrefix = char =>
+  char === 'v' ||
+  char === '=' ||
+  isWhitespace(char)
+
+/**
+ * Checks whether a character is one of the digits 0 through 9.
+ *
+ * @param {string|undefined} char One character to check.
+ * @returns {boolean} Whether the character is an ASCII digit.
+ * @example isDigit('7') // true
+ * @example isDigit('.') // false
+ */
+const isDigit = char => char !== undefined && char >= '0' && char <= '9'
+
+/**
+ * Checks whether a character is an English letter, uppercase or lowercase.
+ *
+ * @param {string|undefined} char One character to check.
+ * @returns {boolean} Whether the character is an ASCII letter.
+ * @example isLetter('b') // true
+ * @example isLetter('7') // false
+ */
+const isLetter = char =>
+  char !== undefined && (
+    (char >= 'a' && char <= 'z') ||
+    (char >= 'A' && char <= 'Z')
+  )
+
+/**
+ * Checks for a letter, digit, or hyphen: the characters allowed inside
+ * prerelease and build names such as beta-1.
+ *
+ * @param {string|undefined} char One character to check.
+ * @returns {boolean} Whether the character can be part of an identifier.
+ * @example isIdentifierCharacter('-') // true
+ * @example isIdentifierCharacter('.') // false; dots separate identifiers
+ */
+const isIdentifierCharacter = char => isDigit(char) || isLetter(char) || char === '-'
+
+/**
+ * Checks whether a version component can begin here: with a digit or
+ * a wildcard such as x, X, or *.
+ *
+ * @param {string|undefined} char One character to check.
+ * @returns {boolean} Whether a number or wildcard can start with this character.
+ * @example isVersionStart('x') // true
+ * @example isVersionStart('v') // false; v belongs to the prefix
+ */
+const isVersionStart = char =>
+  isDigit(char) ||
+  char === 'x' ||
+  char === 'X' ||
+  char === '*'
+
+/**
+ * Finds the end of a row of digits, but returns no more than limit digits.
+ * Remembers the last two rows so looking at them again does not reread them.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position of the first character to check.
+ * @param {number} limit The most digit characters the returned match can include.
+ * @param {DigitRunCache} digitRuns Shared cache of digit-run positions, updated in place.
+ * @returns {number} The position after the matched digits, or start if none match.
+ * @example findDigitsEndIndex('123abc', 0, 10, digitRuns) // 3, pointing at a
+ * @example findDigitsEndIndex('123abc', 0, 2, digitRuns) // 2, pointing at the unread 3
+ */
+const findDigitsEndIndex = (range, start, limit, digitRuns) => {
+  if (!isDigit(range[start])) {
+    return start
+  }
+  if (start >= digitRuns.start && start < digitRuns.end) {
+    return Math.min(start + limit, digitRuns.end)
+  }
+  if (start >= digitRuns.previousStart && start < digitRuns.previousEnd) {
+    return Math.min(start + limit, digitRuns.previousEnd)
+  }
+  let end = start + 1
+  while (isDigit(range[end])) {
+    end++
+  }
+  // A failed full version can rewind from its second run to its first.
+  digitRuns.previousStart = digitRuns.start
+  digitRuns.previousEnd = digitRuns.end
+  digitRuns.start = start
+  digitRuns.end = end
+  return Math.min(start + limit, end)
+}
+
+/**
+ * Reads a number using the old regex's length and leading-zero rules.
+ * Strict mode reads just the first zero in 012; loose mode can read all three.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the number should begin.
+ * @param {boolean} loose Whether to allow leading zeros.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the matched digits, not their numeric value.
+ * @example findVersionNumberEndIndex('012', 0, false, digitRuns) // 1
+ * @example findVersionNumberEndIndex('012', 0, true, digitRuns) // 3
+ */
+const findVersionNumberEndIndex = (range, start, loose, digitRuns) => {
+  if (!loose && range[start] === '0') {
+    return start + 1
+  }
+  // Strict syntax allows an initial nonzero digit plus MAX_LENGTH digits.
+  return findDigitsEndIndex(range, start, loose ? MAX_LENGTH : MAX_LENGTH + 1, digitRuns)
+}
+
+/**
+ * Reads one piece of a prerelease name, such as beta or 1 in beta.1.
+ * Tries the letter-or-hyphen form first, then the number-only form.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the identifier should begin.
+ * @param {boolean} loose Whether numeric identifiers may have leading zeros.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the identifier, or start if none matches.
+ * @example findPrereleaseIdentifierEndIndex('beta.1', 0, false, digitRuns) // 4, at the dot
+ * @example findPrereleaseIdentifierEndIndex('001beta', 0, false, digitRuns) // 7
+ */
+const findPrereleaseIdentifierEndIndex = (range, start, loose, digitRuns) => {
+  const digitsEnd = findDigitsEndIndex(range, start, MAX_LENGTH, digitRuns)
+  // The legacy regex tries a nonnumeric identifier before a numeric one.
+  if (isLetter(range[digitsEnd]) || range[digitsEnd] === '-') {
+    let end = digitsEnd + 1
+    const limit = end + MAX_SAFE_BUILD_LENGTH
+    while (end < limit && isIdentifierCharacter(range[end])) {
+      end++
+    }
+    return end
+  }
+  return findVersionNumberEndIndex(range, start, loose, digitRuns)
+}
+
+/**
+ * Reads a prerelease suffix such as -beta.1, one dot-separated piece at a time.
+ * Loose mode also allows the name without its opening hyphen.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the suffix should begin, including -.
+ * @param {boolean} loose Whether the opening hyphen is optional and zeros allowed.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the matched suffix, or start if absent.
+ * @example findPrereleaseEndIndex('-beta.1+sha', 0, false, digitRuns) // 7, at the plus
+ * @example findPrereleaseEndIndex('beta', 0, false, digitRuns) // 0; no opening hyphen
+ */
+const findPrereleaseEndIndex = (range, start, loose, digitRuns) => {
+  const hyphen = range[start] === '-'
+  if (!loose && !hyphen) {
+    return start
+  }
+  const identifierStart = start + (hyphen ? 1 : 0)
+  let end = findPrereleaseIdentifierEndIndex(range, identifierStart, loose, digitRuns)
+  if (end === identifierStart) {
+    if (!loose || !hyphen) {
+      return start
+    }
+    // In loose syntax, a lone hyphen can itself be the identifier.
+    end = findPrereleaseIdentifierEndIndex(range, start, loose, digitRuns)
+  }
+  while (range[end] === '.') {
+    const next = findPrereleaseIdentifierEndIndex(range, end + 1, loose, digitRuns)
+    if (next === end + 1) {
+      break
+    }
+    end = next
+  }
+  return end
+}
+
+/**
+ * Reads one build-name piece, such as sha or 123 in +sha.123.
+ * Stops at a disallowed character or the old regex's length limit.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the identifier should begin.
+ * @returns {number} The position after the identifier, or start if none matches.
+ * @example findBuildIdentifierEndIndex('sha.123', 0) // 3, at the dot
+ * @example findBuildIdentifierEndIndex('001', 0) // 3; leading zeros are allowed
+ */
+const findBuildIdentifierEndIndex = (range, start) => {
+  let end = start
+  while (end - start < MAX_SAFE_BUILD_LENGTH && isIdentifierCharacter(range[end])) {
+    end++
+  }
+  return end
+}
+
+/**
+ * Reads optional build metadata such as +sha.123.
+ * Leaves the position unchanged if there is no plus sign followed by a name.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the opening + should be.
+ * @returns {number} The position after the matched metadata, or start if absent.
+ * @example findBuildEndIndex('+sha.123 <2', 0) // 8, at the space
+ * @example findBuildEndIndex('+', 0) // 0; a plus sign alone is not a match
+ */
+const findBuildEndIndex = (range, start) => {
+  if (range[start] !== '+') {
+    return start
+  }
+  let end = findBuildIdentifierEndIndex(range, start + 1)
+  if (end === start + 1) {
+    return start
+  }
+  while (range[end] === '.') {
+    const next = findBuildIdentifierEndIndex(range, end + 1)
+    if (next === end + 1) {
+      break
+    }
+    end = next
+  }
+  return end
+}
+
+/**
+ * Reads three numbers separated by dots, then any prerelease and build suffixes.
+ * Uses loose rules, so forms such as 01.02.03beta can match here.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position of the first number, after any prefix.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the version match, or start if none matches.
+ * @example findLooseFullVersionEndIndex('1.2.3-beta+sha <2', 0, digitRuns) // 14
+ * @example findLooseFullVersionEndIndex('1.2', 0, digitRuns) // 0; needs three numbers
+ */
+const findLooseFullVersionEndIndex = (range, start, digitRuns) => {
+  let end = start
+  for (let component = 0; component < 3; component++) {
+    const next = findVersionNumberEndIndex(range, end, true, digitRuns)
+    if (next === end) {
+      return start
+    }
+    end = next
+    if (component < 2) {
+      if (range[end] !== '.') {
+        return start
+      }
+      end++
+    }
+  }
+  const prereleaseEnd = findPrereleaseEndIndex(range, end, true, digitRuns)
+  return findBuildEndIndex(range, prereleaseEnd)
+}
+
+/**
+ * Reads one component of a partial or wildcard version, such as 2 or x in 2.x.
+ * Numbers use strict leading-zero rules; wildcards take up one character.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position where the component should begin.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the component, or start if none matches.
+ * @example findPartialVersionComponentEndIndex('2.x', 0, digitRuns) // 1, at the dot
+ * @example findPartialVersionComponentEndIndex('2.x', 2, digitRuns) // 3, after x
+ */
+const findPartialVersionComponentEndIndex = (range, start, digitRuns) => {
+  if (isDigit(range[start])) {
+    return findVersionNumberEndIndex(range, start, false, digitRuns)
+  }
+  return isVersionStart(range[start]) ? start + 1 : start
+}
+
+/**
+ * Reads up to three components, allowing forms such as 1, 1.2, or 1.x.
+ * After the third component, also reads any strict prerelease and build suffixes.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position of a number or wildcard, after any prefix.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position after the matched version text.
+ * @example findPartialVersionEndIndex('1.x <2', 0, digitRuns) // 3, at the space
+ * @example findPartialVersionEndIndex('1.', 0, digitRuns) // 1; the trailing dot is unread
+ */
+const findPartialVersionEndIndex = (range, start, digitRuns) => {
+  let end = findPartialVersionComponentEndIndex(range, start, digitRuns)
+  for (let component = 0; component < 2; component++) {
+    if (range[end] !== '.') {
+      return end
+    }
+    const next = findPartialVersionComponentEndIndex(range, end + 1, digitRuns)
+    if (next === end + 1) {
+      return end
+    }
+    end = next
+  }
+  const prereleaseEnd = findPrereleaseEndIndex(range, end, false, digitRuns)
+  return findBuildEndIndex(range, prereleaseEnd)
+}
+
+/**
+ * Finds where a version match ends, without deciding whether the range is valid.
+ * Tries a loose full version first, then a partial or wildcard version, just
+ * like the old regex's LOOSEPLAIN and XRANGEPLAIN alternatives.
+ *
+ * @param {string} range The text to read; it is not changed.
+ * @param {number} start The position of a number or wildcard, after any prefix.
+ * @param {DigitRunCache} digitRuns Shared digit-run cache, updated as needed.
+ * @returns {number} The position where scanning the next candidate can resume.
+ * @example findVersionEndIndex('1.2.3 <2', 0, digitRuns) // 5, at the space
+ * @example findVersionEndIndex('1.x <2', 0, digitRuns) // 3, at the space
+ */
+const findVersionEndIndex = (range, start, digitRuns) => {
+  const fullVersionEnd = findLooseFullVersionEndIndex(range, start, digitRuns)
+  return fullVersionEnd !== start
+    ? fullVersionEnd
+    : findPartialVersionEndIndex(range, start, digitRuns)
+}
+
+/**
+ * Finds the one whitespace character the old replacement would remove.
+ * Keeps leading whitespace, skips an optional operator, and checks immediately
+ * after it. Returns -1 if there is nothing to remove.
+ *
+ * @param {string} range The text containing a candidate already found by the caller.
+ * @param {number} matchStart The candidate's position, including leading whitespace.
+ * @returns {number} The position of the removable whitespace, or -1 if absent.
+ * @example findRemovableWhitespaceIndex(' > 1', 0) // 2; keep the space at position 0
+ * @example findRemovableWhitespaceIndex('>1', 0) // -1
+ */
+const findRemovableWhitespaceIndex = (range, matchStart) => {
+  let position = matchStart
+  if (isWhitespace(range[position])) {
+    position++
+  }
+  if (range[position] === '<' || range[position] === '>') {
+    position++
+  }
+  if (range[position] === '=') {
+    position++
+  }
+  return isWhitespace(range[position]) ? position : -1
+}
+
+/**
+ * Joins an operator to its version, turning > 1.2.3 into >1.2.3.
+ * Copies everything else according to the old regex's matching rules.
+ * Moves forward through prefixes and whole versions to avoid repeatedly
+ * searching the same characters on long inputs.
+ *
+ * @param {string} range The range text to process; the original string is unchanged.
+ * @returns {string} The range with matched operator whitespace removed.
+ * @example trimComparatorWhitespace('> 1.2.3 < 2') // '>1.2.3 <2'
+ * @example trimComparatorWhitespace('> invalid') // '> invalid'
+ */
+const trimComparatorWhitespace = range => {
+  let result = ''
+  let copyFrom = 0
+  let cursor = 0
+  const digitRuns = { start: -1, end: -1, previousStart: -1, previousEnd: -1 }
+
+  while (cursor < range.length) {
+    const matchStart = cursor
+    if (range[cursor] === '<' || range[cursor] === '>') {
+      cursor++
+    } else if (!isVersionPrefix(range[cursor]) && !isVersionStart(range[cursor])) {
+      cursor++
+      continue
+    }
+
+    // Consume a v/=/whitespace run once, even when no version follows it.
+    while (cursor < range.length && isVersionPrefix(range[cursor])) {
+      cursor++
+    }
+    if (!isVersionStart(range[cursor])) {
+      continue
+    }
+
+    const whitespacePosition = findRemovableWhitespaceIndex(range, matchStart)
+    if (whitespacePosition !== -1) {
+      result += range.slice(copyFrom, whitespacePosition)
+      copyFrom = whitespacePosition + 1
+    }
+
+    // Skip the entire match, so a prerelease's trailing v cannot be
+    // reconsidered as the prefix of another version.
+    cursor = findVersionEndIndex(range, cursor, digitRuns)
+  }
+
+  return result + range.slice(copyFrom)
+}
+
+module.exports = trimComparatorWhitespace
diff --git a/deps/npm/node_modules/semver/package.json b/deps/npm/node_modules/semver/package.json
index 0cb7c7bb465..80bf748cd04 100644
--- a/deps/npm/node_modules/semver/package.json
+++ b/deps/npm/node_modules/semver/package.json
@@ -1,6 +1,6 @@
 {
   "name": "semver",
-  "version": "7.8.5",
+  "version": "7.8.6",
   "description": "The semantic version parser used by npm.",
   "main": "index.js",
   "scripts": {
diff --git a/deps/npm/node_modules/undici/docs/docs/api/Client.md b/deps/npm/node_modules/undici/docs/docs/api/Client.md
index e0d41b47805..ca6e336f226 100644
--- a/deps/npm/node_modules/undici/docs/docs/api/Client.md
+++ b/deps/npm/node_modules/undici/docs/docs/api/Client.md
@@ -29,6 +29,8 @@ Returns: `Client`
 * **webSocket** `WebSocketOptions` (optional) - WebSocket-specific configuration options.
   * **maxFragments** `number` (optional) - Default: `131072` - Maximum number of fragments in a message. Set to 0 to disable the limit.
   * **maxPayloadSize** `number` (optional) - Default: `134217728` (128 MB) - Maximum allowed payload size in bytes for WebSocket messages. Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages. Set to 0 to disable the limit.
+* **eventSource** `EventSourceOptions` (optional) - EventSource-specific configuration options.
+  * **maxEventSize** `number` (optional) - The maximum total bytes of data and metadata field values retained for a pending EventSource event. Each unfinished line is separately limited to this value plus seven syntax bytes. The number of `data:` lines per event and input chunks buffered for an unfinished line are each limited to `min(131072, max(1024, floor(maxEventSize / 128)))` to bound object overhead. Set to `0` to disable these limits. Default: `buffer.kStringMaxLength`.
 * **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
 * **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
 * **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
diff --git a/deps/npm/node_modules/undici/docs/docs/api/DiagnosticsChannel.md b/deps/npm/node_modules/undici/docs/docs/api/DiagnosticsChannel.md
index 099c072f6c6..aefb1009c63 100644
--- a/deps/npm/node_modules/undici/docs/docs/api/DiagnosticsChannel.md
+++ b/deps/npm/node_modules/undici/docs/docs/api/DiagnosticsChannel.md
@@ -40,7 +40,8 @@ diagnosticsChannel.channel('undici:request:bodySent').subscribe(({ request }) =>

 ## `undici:request:headers`

-This message is published after the response headers have been received, i.e. the response has been completed.
+This message is published after the response headers have been received. This includes a successful CONNECT or
+protocol upgrade response.

 ```js
 import diagnosticsChannel from 'diagnostics_channel'
@@ -57,6 +58,7 @@ diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, respo
 ## `undici:request:trailers`

 This message is published after the response body and trailers have been received, i.e. the response has been completed.
+After an upgraded socket is passed to the request handler, this message is published with an empty `trailers` array.

 ```js
 import diagnosticsChannel from 'diagnostics_channel'
diff --git a/deps/npm/node_modules/undici/lib/core/request.js b/deps/npm/node_modules/undici/lib/core/request.js
index 8e7ecc73084..0b2b1a8d9d7 100644
--- a/deps/npm/node_modules/undici/lib/core/request.js
+++ b/deps/npm/node_modules/undici/lib/core/request.js
@@ -263,11 +263,77 @@ class Request {
     }
   }

-  onUpgrade (statusCode, headers, socket) {
+  /**
+   * @param {number|null} statusCode
+   * @param {Buffer[]|null} headers
+   * @param {import('node:stream').Duplex} socket
+   * @param {string} [statusText]
+   */
+  onUpgrade (statusCode, headers, socket, statusText = '') {
+    this.onFinally()
+
     assert(!this.aborted)
     assert(!this.completed)

-    return this[kHandler].onUpgrade(statusCode, headers, socket)
+    if (statusCode !== null) {
+      this.#publishUpgradeHeaders(statusCode, headers, statusText)
+    }
+
+    const result = this[kHandler].onUpgrade(statusCode, headers, socket)
+
+    if (!this.aborted) {
+      this.completed = true
+      if (statusCode !== null) {
+        this.#publishUpgradeTrailers()
+      }
+    }
+
+    return result
+  }
+
+  /**
+   * @param {number} statusCode
+   * @param {import('node:http2').IncomingHttpHeaders} headers
+   * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders
+   * @param {string} [statusText]
+   */
+  onUpgradeResponse (statusCode, headers, parseHeaders, statusText = '') {
+    assert(!this.aborted)
+    assert(this.completed)
+
+    if (channels.headers.hasSubscribers) {
+      this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText)
+    }
+    this.#publishUpgradeTrailers()
+  }
+
+  /**
+   * @param {Error} error
+   */
+  onUpgradeError (error) {
+    assert(!this.aborted)
+    assert(this.completed)
+
+    if (channels.error.hasSubscribers) {
+      channels.error.publish({ request: this, error })
+    }
+  }
+
+  /**
+   * @param {number} statusCode
+   * @param {Buffer[]} headers
+   * @param {string} statusText
+   */
+  #publishUpgradeHeaders (statusCode, headers, statusText) {
+    if (channels.headers.hasSubscribers) {
+      channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
+    }
+  }
+
+  #publishUpgradeTrailers () {
+    if (channels.trailers.hasSubscribers) {
+      channels.trailers.publish({ request: this, trailers: [] })
+    }
   }

   onComplete (trailers) {
diff --git a/deps/npm/node_modules/undici/lib/dispatcher/agent.js b/deps/npm/node_modules/undici/lib/dispatcher/agent.js
index 90b46fe3aeb..416ab3edda3 100644
--- a/deps/npm/node_modules/undici/lib/dispatcher/agent.js
+++ b/deps/npm/node_modules/undici/lib/dispatcher/agent.js
@@ -23,7 +23,7 @@ function defaultFactory (origin, opts) {
 }

 class Agent extends DispatcherBase {
-  constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
+  constructor ({ factory = defaultFactory, maxRedirections = 0, connect, tls, ...options } = {}) {
     if (typeof factory !== 'function') {
       throw new InvalidArgumentError('factory must be a function.')
     }
@@ -42,11 +42,15 @@ class Agent extends DispatcherBase {
       connect = { ...connect }
     }

+    if (tls && typeof tls !== 'function') {
+      tls = { ...tls }
+    }
+
     this[kInterceptors] = options.interceptors?.Agent && Array.isArray(options.interceptors.Agent)
       ? options.interceptors.Agent
       : [createRedirectInterceptor({ maxRedirections })]

-    this[kOptions] = { ...util.deepClone(options), connect }
+    this[kOptions] = { ...util.deepClone(options), connect, tls }
     this[kOptions].interceptors = options.interceptors
       ? { ...options.interceptors }
       : undefined
diff --git a/deps/npm/node_modules/undici/lib/dispatcher/client-h1.js b/deps/npm/node_modules/undici/lib/dispatcher/client-h1.js
index a801ecb3604..7d1fdbdf6e7 100644
--- a/deps/npm/node_modules/undici/lib/dispatcher/client-h1.js
+++ b/deps/npm/node_modules/undici/lib/dispatcher/client-h1.js
@@ -432,7 +432,7 @@ class Parser {
   }

   onUpgrade (head) {
-    const { upgrade, client, socket, headers, statusCode } = this
+    const { upgrade, client, socket, headers, statusCode, statusText } = this

     assert(upgrade)
     assert(client[kSocket] === socket)
@@ -467,9 +467,10 @@ class Parser {
     client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade'))

     try {
-      request.onUpgrade(statusCode, headers, socket)
-    } catch (err) {
-      util.destroy(socket, err)
+      request.onUpgrade(statusCode, headers, socket, statusText)
+    } catch (error) {
+      util.errorRequest(client, request, error)
+      util.destroy(socket, error)
     }

     client[kResume]()
@@ -726,8 +727,6 @@ async function connectH1 (client, socket) {
   socket[kParser] = new Parser(client, socket, llhttpInstance)

   addListener(socket, 'error', function (err) {
-    assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
-
     const parser = this[kParser]

     // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
@@ -876,7 +875,7 @@ async function connectH1 (client, socket) {

 function clearIdleSocketValidation (socket) {
   if (socket[kIdleSocketValidationTimeout]) {
-    clearTimeout(socket[kIdleSocketValidationTimeout])
+    clearImmediate(socket[kIdleSocketValidationTimeout])
     socket[kIdleSocketValidationTimeout] = null
   }

@@ -885,15 +884,23 @@ function clearIdleSocketValidation (socket) {

 function scheduleIdleSocketValidation (client, socket) {
   socket[kIdleSocketValidation] = 1
-  socket[kIdleSocketValidationTimeout] = setTimeout(() => {
+  // Yield to the check phase (after poll) so unsolicited bytes / FIN / RST
+  // already pending on this idle keep-alive socket are processed before the
+  // next request is written (GHSA-35p6-xmwp-9g52).
+  //
+  // setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse
+  // (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll
+  // block for ~500ms when the event loop is otherwise idle (#5600 / #5606).
+  // A ref'd Immediate both keeps the pending request alive and makes poll
+  // return immediately — the hybrid those issues asked for.
+  socket[kIdleSocketValidationTimeout] = setImmediate(() => {
     socket[kIdleSocketValidationTimeout] = null
     socket[kIdleSocketValidation] = 2

     if (client[kSocket] === socket && !socket.destroyed) {
       client[kResume]()
     }
-  }, 0)
-  socket[kIdleSocketValidationTimeout].unref?.()
+  })
 }

 /**
@@ -1042,12 +1049,22 @@ function writeH1 (client, request) {
   const socket = client[kSocket]
   clearIdleSocketValidation(socket)

-  const abort = (err) => {
-    if (request.aborted || request.completed) {
+  /**
+   * @param {Error} [error]
+   */
+  const abort = (error) => {
+    if (request.aborted) {
+      return
+    }
+
+    if (request.completed) {
+      if (request.upgrade || request.method === 'CONNECT') {
+        util.destroy(socket, new InformationalError('aborted'))
+      }
       return
     }

-    util.errorRequest(client, request, err || new RequestAbortedError())
+    util.errorRequest(client, request, error || new RequestAbortedError())

     util.destroy(body)
     util.destroy(socket, new InformationalError('aborted'))
diff --git a/deps/npm/node_modules/undici/lib/dispatcher/client-h2.js b/deps/npm/node_modules/undici/lib/dispatcher/client-h2.js
index 4a52effb1f3..f417aa3d186 100644
--- a/deps/npm/node_modules/undici/lib/dispatcher/client-h2.js
+++ b/deps/npm/node_modules/undici/lib/dispatcher/client-h2.js
@@ -1,6 +1,7 @@
 'use strict'

 const assert = require('node:assert')
+const { errorMonitor } = require('node:events')
 const { pipeline } = require('node:stream')
 const util = require('../core/util.js')
 const {
@@ -77,6 +78,15 @@ function parseH2Headers (headers) {
   return result
 }

+/**
+ * @param {import('node:http2').IncomingHttpHeaders} headers
+ * @returns {Buffer[]}
+ */
+function parseH2ResponseHeaders (headers) {
+  const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers
+  return parseH2Headers(realHeaders)
+}
+
 async function connectH2 (client, socket) {
   client[kSocket] = socket

@@ -126,8 +136,6 @@ async function connectH2 (client, socket) {
   socket[kHTTP2Session] = session

   util.addListener(socket, 'error', function (err) {
-    assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
-
     this[kError] = err

     this[kClient][kOnError](err)
@@ -201,8 +209,6 @@ function resumeH2 (client) {
 }

 function onHttp2SessionError (err) {
-  assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
-
   this[kSocket][kError] = err
   this[kClient][kOnError](err)
 }
@@ -297,22 +303,32 @@ function writeH2 (client, request) {
   headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`
   headers[HTTP2_HEADER_METHOD] = method

-  const abort = (err) => {
-    if (request.aborted || request.completed) {
+  /**
+   * @param {Error} [error]
+   */
+  const abort = (error) => {
+    if (request.aborted) {
       return
     }

-    err = err || new RequestAbortedError()
+    if (request.completed) {
+      if (method === 'CONNECT' && stream != null) {
+        util.destroy(stream, error || new RequestAbortedError())
+      }
+      return
+    }

-    util.errorRequest(client, request, err)
+    error = error || new RequestAbortedError()
+
+    util.errorRequest(client, request, error)

     if (stream != null) {
-      util.destroy(stream, err)
+      util.destroy(stream, error)
     }

     // We do not destroy the socket as we can continue using the session
     // the stream get's destroyed and the session remains to create new streams
-    util.destroy(body, err)
+    util.destroy(body, error)
     client[kQueue][client[kRunningIdx]++] = null
     client[kResume]()
   }
@@ -331,25 +347,57 @@ function writeH2 (client, request) {

   if (method === 'CONNECT') {
     session.ref()
-    // We are already connected, streams are pending, first request
-    // will create a new stream. We trigger a request to create the stream and wait until
-    // `ready` event is triggered
     // We disabled endStream to allow the user to write to the stream
     stream = session.request(headers, { endStream: false, signal })
+    let upgradeResponseFinished = false
+
+    /**
+     * @param {import('node:http2').IncomingHttpHeaders} headers
+     */
+    const onResponse = (headers) => {
+      upgradeResponseFinished = true
+      stream.off(errorMonitor, onUpgradeError)
+      request.onUpgradeResponse(Number(headers[HTTP2_HEADER_STATUS]), headers, parseH2ResponseHeaders)
+    }

-    if (stream.id && !stream.pending) {
-      request.onUpgrade(null, null, stream)
-      ++session[kOpenStreams]
-      client[kQueue][client[kRunningIdx]++] = null
-    } else {
-      stream.once('ready', () => {
+    /**
+     * @param {Error} error
+     */
+    const onUpgradeError = (error) => {
+      upgradeResponseFinished = true
+      stream.off('response', onResponse)
+      request.onUpgradeError(error)
+    }
+
+    const onReady = () => {
+      try {
         request.onUpgrade(null, null, stream)
-        ++session[kOpenStreams]
-        client[kQueue][client[kRunningIdx]++] = null
-      })
+      } catch (error) {
+        stream.off('response', onResponse)
+        abort(error)
+        return
+      }
+
+      if (request.aborted) {
+        return
+      }
+
+      stream.off('error', abort)
+      stream.once(errorMonitor, onUpgradeError)
+      client[kQueue][client[kRunningIdx]++] = null
     }

+    stream.once('response', onResponse)
+    stream.once('error', abort)
+    ++session[kOpenStreams]
+    onReady()
+
     stream.once('close', () => {
+      if (!upgradeResponseFinished && request.completed) {
+        stream.off('response', onResponse)
+        stream.off(errorMonitor, onUpgradeError)
+        request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`))
+      }
       session[kOpenStreams] -= 1
       if (session[kOpenStreams] === 0) session.unref()
     })
diff --git a/deps/npm/node_modules/undici/lib/dispatcher/client.js b/deps/npm/node_modules/undici/lib/dispatcher/client.js
index 18472fffd77..9efe80e3002 100644
--- a/deps/npm/node_modules/undici/lib/dispatcher/client.js
+++ b/deps/npm/node_modules/undici/lib/dispatcher/client.js
@@ -107,9 +107,10 @@ class Client extends DispatcherBase {
     // h2
     maxConcurrentStreams,
     allowH2,
-    webSocket
+    webSocket,
+    eventSource
   } = {}) {
-    super({ webSocket })
+    super({ webSocket, eventSource })

     if (keepAlive !== undefined) {
       throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead')
diff --git a/deps/npm/node_modules/undici/lib/dispatcher/dispatcher-base.js b/deps/npm/node_modules/undici/lib/dispatcher/dispatcher-base.js
index 371a3ea1f6f..e90e4b379ef 100644
--- a/deps/npm/node_modules/undici/lib/dispatcher/dispatcher-base.js
+++ b/deps/npm/node_modules/undici/lib/dispatcher/dispatcher-base.js
@@ -1,5 +1,6 @@
 'use strict'

+const buffer = require('node:buffer')
 const Dispatcher = require('./dispatcher')
 const {
   ClientDestroyedError,
@@ -12,6 +13,7 @@ const kOnDestroyed = Symbol('onDestroyed')
 const kOnClosed = Symbol('onClosed')
 const kInterceptedDispatch = Symbol('Intercepted Dispatch')
 const kWebSocketOptions = Symbol('webSocketOptions')
+const kEventSourceOptions = Symbol('eventSourceOptions')

 class DispatcherBase extends Dispatcher {
   constructor (opts) {
@@ -22,6 +24,7 @@ class DispatcherBase extends Dispatcher {
     this[kClosed] = false
     this[kOnClosed] = []
     this[kWebSocketOptions] = opts?.webSocket ?? {}
+    this[kEventSourceOptions] = opts?.eventSource ?? {}
   }

   get webSocketOptions () {
@@ -31,6 +34,12 @@ class DispatcherBase extends Dispatcher {
     }
   }

+  get eventSourceOptions () {
+    return {
+      maxEventSize: this[kEventSourceOptions].maxEventSize ?? buffer.kStringMaxLength
+    }
+  }
+
   get destroyed () {
     return this[kDestroyed]
   }
diff --git a/deps/npm/node_modules/undici/lib/handler/retry-handler.js b/deps/npm/node_modules/undici/lib/handler/retry-handler.js
index c62a2409f3a..7084c2b5652 100644
--- a/deps/npm/node_modules/undici/lib/handler/retry-handler.js
+++ b/deps/npm/node_modules/undici/lib/handler/retry-handler.js
@@ -90,6 +90,7 @@ class RetryHandler {
     this.end = null
     this.etag = null
     this.resume = null
+    this.headersSent = false

     // Handle possible onConnect duplication
     this.handler.onConnect(reason => {
@@ -102,6 +103,20 @@ class RetryHandler {
     })
   }

+  checkpointResponseEnd (headers, resume) {
+    if (this.end == null && this.opts.method !== 'HEAD') {
+      const contentLength = headers['content-length']
+      this.end = contentLength != null ? Number(contentLength) - 1 : null
+
+      assert(
+        this.end == null || Number.isFinite(this.end),
+        'invalid content-length'
+      )
+    }
+
+    this.resume = this.end != null ? resume : null
+  }
+
   onRequestSent () {
     if (this.handler.onRequestSent) {
       this.handler.onRequestSent()
@@ -190,7 +205,12 @@ class RetryHandler {
     this.retryCount += 1

     if (statusCode >= 300) {
-      if (this.retryOpts.statusCodes.includes(statusCode) === false) {
+      // Only expose a response if no earlier attempt has reached the caller.
+      // Otherwise abort this attempt so the error settles the existing body
+      // instead of replacing it with a new response.
+      if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) {
+        this.headersSent = true
+        this.checkpointResponseEnd(headers, resume)
         return this.handler.onHeaders(
           statusCode,
           rawHeaders,
@@ -259,8 +279,15 @@ class RetryHandler {

       const { start, size, end = size - 1 } = contentRange

-      assert(this.start === start, 'content-range mismatch')
-      assert(this.end == null || this.end === end, 'content-range mismatch')
+      if (this.start !== start || (this.end != null && this.end !== end)) {
+        this.abort(
+          new RequestRetryError('Content-Range mismatch', statusCode, {
+            headers,
+            data: { count: this.retryCount }
+          })
+        )
+        return false
+      }

       this.resume = resume
       return true
@@ -272,6 +299,7 @@ class RetryHandler {
         const range = parseRangeHeader(headers['content-range'])

         if (range == null) {
+          this.headersSent = true
           return this.handler.onHeaders(
             statusCode,
             rawHeaders,
@@ -310,6 +338,7 @@ class RetryHandler {
       )

       this.resume = resume
+      this.headersSent = true
       this.etag = headers.etag != null ? headers.etag : null

       // Weak etags are not useful for comparison nor cache
@@ -349,7 +378,7 @@ class RetryHandler {
   }

   onError (err) {
-    if (this.aborted || isDisturbed(this.opts.body)) {
+    if (this.aborted || isDisturbed(this.opts.body) || (this.headersSent && this.resume == null)) {
       return this.handler.onError(err)
     }

diff --git a/deps/npm/node_modules/undici/lib/web/eventsource/eventsource-stream.js b/deps/npm/node_modules/undici/lib/web/eventsource/eventsource-stream.js
index 754934568d0..9172602ad05 100644
--- a/deps/npm/node_modules/undici/lib/web/eventsource/eventsource-stream.js
+++ b/deps/npm/node_modules/undici/lib/web/eventsource/eventsource-stream.js
@@ -1,4 +1,5 @@
 'use strict'
+const buffer = require('node:buffer')
 const { Transform } = require('node:stream')
 const { isASCIINumber, isValidLastEventId } = require('./util')

@@ -23,6 +24,63 @@ const COLON = 0x3A
  */
 const SPACE = 0x20

+const defaultMaxEventSize = buffer.kStringMaxLength
+
+const DATA = Buffer.from('data')
+const EVENT = Buffer.from('event')
+const ID = Buffer.from('id')
+const RETRY = Buffer.from('retry')
+
+// Each data field creates a string node, and each unconsumed input chunk keeps
+// a Buffer wrapper. The absolute ceiling protects the large default byte limit.
+const minParserItems = 1024
+const maxParserItems = 131072
+const bytesPerParserItem = 128
+
+function isASCIINumberBytes (buffer, start) {
+  if (start >= buffer.length) {
+    return false
+  }
+
+  for (let i = start; i < buffer.length; i++) {
+    if (buffer[i] < 0x30 || buffer[i] > 0x39) {
+      return false
+    }
+  }
+
+  return true
+}
+
+function isValidLastEventIdBytes (buffer, start) {
+  for (let i = start; i < buffer.length; i++) {
+    if (buffer[i] === 0x00) {
+      return false
+    }
+  }
+
+  return true
+}
+
+function isFieldName (line, length, field) {
+  if (length !== field.length) {
+    return false
+  }
+
+  for (let i = 0; i < length; i++) {
+    if (line[i] !== field[i]) {
+      return false
+    }
+  }
+
+  return true
+}
+
+function createMaxEventSizeExceededError () {
+  const error = new Error('EventSource message size exceeded')
+  error.aborted = false
+  return error
+}
+
 /**
  * @typedef {object} EventSourceStreamEvent
  * @type {object}
@@ -63,11 +121,21 @@ class EventSourceStream extends Transform {
   eventEndCheck = false

   /**
-   * @type {Buffer}
+   * @type {Buffer[]}
    */
-  buffer = null
+  chunks = []

+  chunkIndex = 0
   pos = 0
+  lineChunkIndex = 0
+  linePos = 0
+  lineLength = 0
+  eventSize = 0
+  eventFieldSizes = { data: 0, event: 0, id: 0, retry: 0 }
+  dataLineCount = 0
+  maxEventSize
+  maxDataLines
+  maxBufferedChunks

   event = {
     data: undefined,
@@ -78,6 +146,7 @@ class EventSourceStream extends Transform {

   /**
    * @param {object} options
+   * @param {number} [options.maxEventSize]
    * @param {eventSourceSettings} options.eventSourceSettings
    * @param {Function} [options.push]
    */
@@ -89,6 +158,12 @@ class EventSourceStream extends Transform {
     super(options)

     this.state = options.eventSourceSettings || {}
+    this.maxEventSize = options.maxEventSize ?? defaultMaxEventSize
+    const parserItemLimit = this.maxEventSize > 0
+      ? Math.min(maxParserItems, Math.max(minParserItems, Math.floor(this.maxEventSize / bytesPerParserItem)))
+      : 0
+    this.maxDataLines = parserItemLimit
+    this.maxBufferedChunks = parserItemLimit
     if (options.push) {
       this.push = options.push
     }
@@ -106,92 +181,28 @@ class EventSourceStream extends Transform {
       return
     }

-    // Cache the chunk in the buffer, as the data might not be complete while
-    // processing it
-    // TODO: Investigate if there is a more performant way to handle
-    // incoming chunks
-    // see: https://github.com/nodejs/undici/issues/2630
-    if (this.buffer) {
-      this.buffer = Buffer.concat([this.buffer, chunk])
-    } else {
-      this.buffer = chunk
+    // A leading line ending can immediately release the currently buffered
+    // line, even when it uses the final allowed chunk slot.
+    if (this.maxEventSize > 0 &&
+        this.chunks.length >= this.maxBufferedChunks &&
+        chunk[0] !== LF && chunk[0] !== CR) {
+      callback(createMaxEventSizeExceededError())
+      return
     }
+    this.chunks.push(chunk)

     // Strip leading byte-order-mark if we opened the stream and started
     // the processing of the incoming data
     if (this.checkBOM) {
-      switch (this.buffer.length) {
-        case 1:
-          // Check if the first byte is the same as the first byte of the BOM
-          if (this.buffer[0] === BOM[0]) {
-            // If it is, we need to wait for more data
-            callback()
-            return
-          }
-          // Set the checkBOM flag to false as we don't need to check for the
-          // BOM anymore
-          this.checkBOM = false
-
-          // The buffer only contains one byte so we need to wait for more data
-          callback()
-          return
-        case 2:
-          // Check if the first two bytes are the same as the first two bytes
-          // of the BOM
-          if (
-            this.buffer[0] === BOM[0] &&
-            this.buffer[1] === BOM[1]
-          ) {
-            // If it is, we need to wait for more data, because the third byte
-            // is needed to determine if it is the BOM or not
-            callback()
-            return
-          }
-
-          // Set the checkBOM flag to false as we don't need to check for the
-          // BOM anymore
-          this.checkBOM = false
-          break
-        case 3:
-          // Check if the first three bytes are the same as the first three
-          // bytes of the BOM
-          if (
-            this.buffer[0] === BOM[0] &&
-            this.buffer[1] === BOM[1] &&
-            this.buffer[2] === BOM[2]
-          ) {
-            // If it is, we can drop the buffered data, as it is only the BOM
-            this.buffer = Buffer.alloc(0)
-            // Set the checkBOM flag to false as we don't need to check for the
-            // BOM anymore
-            this.checkBOM = false
-
-            // Await more data
-            callback()
-            return
-          }
-          // If it is not the BOM, we can start processing the data
-          this.checkBOM = false
-          break
-        default:
-          // The buffer is longer than 3 bytes, so we can drop the BOM if it is
-          // present
-          if (
-            this.buffer[0] === BOM[0] &&
-            this.buffer[1] === BOM[1] &&
-            this.buffer[2] === BOM[2]
-          ) {
-            // Remove the BOM from the buffer
-            this.buffer = this.buffer.subarray(3)
-          }
-
-          // Set the checkBOM flag to false as we don't need to check for the
-          this.checkBOM = false
-          break
+      if (this.handleBOM()) {
+        callback()
+        return
       }
     }

-    while (this.pos < this.buffer.length) {
+    while (this.hasCurrentByte()) {
+      const byte = this.currentByte()
+
       // If the previous line ended with an end-of-line, we need to check
       // if the next character is also an end-of-line.
       if (this.eventEndCheck) {
@@ -204,10 +215,9 @@ class EventSourceStream extends Transform {
         if (this.crlfCheck) {
           // If the current character is a line feed, we can remove it
           // from the buffer and reset the crlfCheck flag
-          if (this.buffer[this.pos] === LF) {
-            this.buffer = this.buffer.subarray(this.pos + 1)
-            this.pos = 0
+          if (byte === LF) {
             this.crlfCheck = false
+            this.consumeCurrentByte()

             // It is possible that the line feed is not the end of the
             // event. We need to check if the next character is an
@@ -223,19 +233,17 @@ class EventSourceStream extends Transform {
           this.crlfCheck = false
         }

-        if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
+        if (byte === LF || byte === CR) {
           // If the current character is a carriage return, we need to
           // set the crlfCheck flag to true, as we need to check if the
           // next character is a line feed so we can remove it from the
           // buffer
-          if (this.buffer[this.pos] === CR) {
+          if (byte === CR) {
             this.crlfCheck = true
           }

-          this.buffer = this.buffer.subarray(this.pos + 1)
-          this.pos = 0
-          if (
-            this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
+          this.consumeCurrentByte()
+          if (this.hasPendingEvent()) {
             this.processEvent(this.event)
           }
           this.clearEvent()
@@ -249,22 +257,23 @@ class EventSourceStream extends Transform {

       // If the current character is an end-of-line, we can process the
       // line
-      if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
+      if (byte === LF || byte === CR) {
         // If the current character is a carriage return, we need to
         // set the crlfCheck flag to true, as we need to check if the
         // next character is a line feed
-        if (this.buffer[this.pos] === CR) {
+        if (byte === CR) {
           this.crlfCheck = true
         }

         // In any case, we can process the line as we reached an
         // end-of-line character
-        this.parseLine(this.buffer.subarray(0, this.pos), this.event)
-
-        // Remove the processed line from the buffer
-        this.buffer = this.buffer.subarray(this.pos + 1)
-        // Reset the position as we removed the processed line from the buffer
-        this.pos = 0
+        try {
+          this.parseLine(this.readLine(), this.event)
+        } catch (error) {
+          callback(error)
+          return
+        }
+        this.consumeCurrentByte()
         // A line was processed and this could be the end of the event. We need
         // to check if the next line is empty to determine if the event is
         // finished.
@@ -272,15 +281,28 @@ class EventSourceStream extends Transform {
         continue
       }

-      this.pos++
+      // readLine() is only called after CR or LF. Reject an unfinished line
+      // before it can retain an unbounded number of decoded chunks. The seven
+      // extra bytes allow the longest field prefix ("event: " or "retry: ").
+      if (this.maxEventSize > 0 && ++this.lineLength > this.maxEventSize + 7) {
+        callback(createMaxEventSizeExceededError())
+        return
+      }
+      this.advanceCursor()
     }

     callback()
   }

+  _destroy (error, callback) {
+    this.chunks.length = 0
+    this.clearEvent()
+    super._destroy(error, callback)
+  }
+
   /**
    * @param {Buffer} line
-   * @param {EventStreamEvent} event
+   * @param {EventSourceStreamEvent} event
    */
   parseLine (line, event) {
     // If the line is empty (a blank line)
@@ -297,67 +319,74 @@ class EventSourceStream extends Transform {
       return
     }

-    let field = ''
-    let value = ''
+    let fieldLength = line.length
+    let valueStart = line.length

     // If the line contains a U+003A COLON character (:)
     if (colonPosition !== -1) {
-      // Collect the characters on the line before the first U+003A COLON
-      // character (:), and let field be that string.
-      // TODO: Investigate if there is a more performant way to extract the
-      // field
-      // see: https://github.com/nodejs/undici/issues/2630
-      field = line.subarray(0, colonPosition).toString('utf8')
+      fieldLength = colonPosition

       // Collect the characters on the line after the first U+003A COLON
       // character (:), and let value be that string.
       // If value starts with a U+0020 SPACE character, remove it from value.
-      let valueStart = colonPosition + 1
+      valueStart = colonPosition + 1
       if (line[valueStart] === SPACE) {
         ++valueStart
       }
-      // TODO: Investigate if there is a more performant way to extract the
-      // value
-      // see: https://github.com/nodejs/undici/issues/2630
-      value = line.subarray(valueStart).toString('utf8')
-
-      // Otherwise, the string is not empty but does not contain a U+003A COLON
-      // character (:)
-    } else {
-      // Process the field using the steps described below, using the whole
-      // line as the field name, and the empty string as the field value.
-      field = line.toString('utf8')
-      value = ''
     }

-    // Modify the event with the field name and value. The value is also
-    // decoded as UTF-8
-    switch (field) {
-      case 'data':
-        if (event[field] === undefined) {
-          event[field] = value
-        } else {
-          event[field] += `\n${value}`
-        }
-        break
-      case 'retry':
-        if (isASCIINumber(value)) {
-          event[field] = value
-        }
-        break
-      case 'id':
-        if (isValidLastEventId(value)) {
-          event[field] = value
-        }
-        break
-      case 'event':
-        if (value.length > 0) {
-          event[field] = value
-        }
-        break
+    if (isFieldName(line, fieldLength, DATA)) {
+      if (this.maxEventSize > 0 && this.dataLineCount >= this.maxDataLines) {
+        throw createMaxEventSizeExceededError()
+      }
+      const valueBytes = line.length - valueStart
+      const dataSize = this.eventFieldSizes.data + (event.data === undefined ? 0 : 1) + valueBytes
+      this.setEventFieldSize('data', dataSize)
+
+      const value = line.toString('utf8', valueStart)
+
+      if (event.data === undefined) {
+        event.data = value
+      } else {
+        event.data += `\n${value}`
+      }
+      this.dataLineCount++
+      return
+    }
+
+    if (isFieldName(line, fieldLength, RETRY)) {
+      if (isASCIINumberBytes(line, valueStart)) {
+        this.setEventFieldSize('retry', line.length - valueStart)
+        event.retry = line.toString('utf8', valueStart)
+      }
+      return
+    }
+
+    if (isFieldName(line, fieldLength, ID)) {
+      if (isValidLastEventIdBytes(line, valueStart)) {
+        this.setEventFieldSize('id', line.length - valueStart)
+        event.id = line.toString('utf8', valueStart)
+      }
+      return
+    }
+
+    if (isFieldName(line, fieldLength, EVENT)) {
+      if (valueStart < line.length) {
+        this.setEventFieldSize('event', line.length - valueStart)
+        event.event = line.toString('utf8', valueStart)
+      }
     }
   }

+  setEventFieldSize (field, size) {
+    const eventSize = this.eventSize - this.eventFieldSizes[field] + size
+    if (this.maxEventSize > 0 && eventSize > this.maxEventSize) {
+      throw createMaxEventSizeExceededError()
+    }
+    this.eventSize = eventSize
+    this.eventFieldSizes[field] = size
+  }
+
   /**
    * @param {EventSourceStreamEvent} event
    */
@@ -384,13 +413,160 @@ class EventSourceStream extends Transform {
   }

   clearEvent () {
-    this.event = {
-      data: undefined,
-      event: undefined,
-      id: undefined,
-      retry: undefined
+    this.event.data = undefined
+    this.event.event = undefined
+    this.event.id = undefined
+    this.event.retry = undefined
+    this.eventSize = 0
+    this.dataLineCount = 0
+    this.eventFieldSizes.data = 0
+    this.eventFieldSizes.event = 0
+    this.eventFieldSizes.id = 0
+    this.eventFieldSizes.retry = 0
+  }
+
+  hasPendingEvent () {
+    return this.event.data !== undefined ||
+      this.event.event !== undefined ||
+      this.event.id !== undefined ||
+      this.event.retry !== undefined
+  }
+
+  hasCurrentByte () {
+    return this.chunkIndex < this.chunks.length &&
+      this.pos < this.chunks[this.chunkIndex].length
+  }
+
+  currentByte () {
+    return this.chunks[this.chunkIndex][this.pos]
+  }
+
+  consumeCurrentByte () {
+    this.advanceCursor()
+    this.syncLineStartToCursor()
+  }
+
+  advanceCursor () {
+    this.pos++
+
+    while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) {
+      this.chunkIndex++
+      this.pos = 0
+    }
+  }
+
+  syncLineStartToCursor () {
+    this.lineChunkIndex = this.chunkIndex
+    this.linePos = this.pos
+    this.lineLength = 0
+    this.dropConsumedChunks()
+  }
+
+  dropConsumedChunks () {
+    if (this.lineChunkIndex > 0) {
+      const consumed = this.lineChunkIndex
+      this.chunks.splice(0, consumed)
+      this.lineChunkIndex = 0
+      this.chunkIndex -= consumed
+    }
+
+    if (this.chunkIndex === this.chunks.length) {
+      this.chunks.length = 0
+      this.chunkIndex = 0
+      this.pos = 0
+      this.lineChunkIndex = 0
+      this.linePos = 0
     }
   }
+
+  readLine () {
+    if (this.lineChunkIndex === this.chunkIndex) {
+      return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos)
+    }
+
+    const chunks = []
+    let length = 0
+
+    for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) {
+      const chunk = this.chunks[i]
+      const start = i === this.lineChunkIndex ? this.linePos : 0
+      const end = i === this.chunkIndex ? this.pos : chunk.length
+      const slice = chunk.subarray(start, end)
+      length += slice.length
+      chunks.push(slice)
+    }
+
+    return Buffer.concat(chunks, length)
+  }
+
+  peekBufferedByte (offset) {
+    let chunkIndex = this.lineChunkIndex
+    let pos = this.linePos
+
+    while (chunkIndex < this.chunks.length) {
+      const chunk = this.chunks[chunkIndex]
+      const remaining = chunk.length - pos
+
+      if (offset < remaining) {
+        return chunk[pos + offset]
+      }
+
+      offset -= remaining
+      chunkIndex++
+      pos = 0
+    }
+  }
+
+  discardLeadingBytes (count) {
+    while (count > 0 && this.lineChunkIndex < this.chunks.length) {
+      const chunk = this.chunks[this.lineChunkIndex]
+      const remaining = chunk.length - this.linePos
+
+      if (count < remaining) {
+        this.linePos += count
+        count = 0
+      } else {
+        count -= remaining
+        this.lineChunkIndex++
+        this.linePos = 0
+      }
+    }
+
+    this.chunkIndex = this.lineChunkIndex
+    this.pos = this.linePos
+    this.dropConsumedChunks()
+  }
+
+  handleBOM () {
+    const first = this.peekBufferedByte(0)
+    const second = this.peekBufferedByte(1)
+    const third = this.peekBufferedByte(2)
+
+    if (second === undefined) {
+      if (first === BOM[0]) {
+        return true
+      }
+
+      this.checkBOM = false
+      return true
+    }
+
+    if (third === undefined) {
+      if (first === BOM[0] && second === BOM[1]) {
+        return true
+      }
+
+      this.checkBOM = false
+      return false
+    }
+
+    if (first === BOM[0] && second === BOM[1] && third === BOM[2]) {
+      this.discardLeadingBytes(3)
+    }
+
+    this.checkBOM = false
+    return !this.hasCurrentByte()
+  }
 }

 module.exports = {
diff --git a/deps/npm/node_modules/undici/lib/web/eventsource/eventsource.js b/deps/npm/node_modules/undici/lib/web/eventsource/eventsource.js
index 5a488ffce27..6092645bf2c 100644
--- a/deps/npm/node_modules/undici/lib/web/eventsource/eventsource.js
+++ b/deps/npm/node_modules/undici/lib/web/eventsource/eventsource.js
@@ -11,6 +11,7 @@ const { isNetworkError } = require('../fetch/response')
 const { delay } = require('./util')
 const { kEnumerableProperty } = require('../../core/util')
 const { environmentSettingsObject } = require('../fetch/util')
+const { getGlobalDispatcher } = require('../../global')

 let experimentalWarned = false

@@ -292,6 +293,7 @@ class EventSource extends EventTarget {

       const eventSourceStream = new EventSourceStream({
         eventSourceSettings: this.#state,
+        maxEventSize: this.#dispatcher.eventSourceOptions?.maxEventSize,
         push: (event) => {
           this.dispatchEvent(createFastMessageEvent(
             event.type,
@@ -470,7 +472,8 @@ webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
   },
   {
     key: 'dispatcher', // undici only
-    converter: webidl.converters.any
+    converter: webidl.converters.any,
+    defaultValue: () => getGlobalDispatcher()
   }
 ])

diff --git a/deps/npm/node_modules/undici/lib/web/fetch/index.js b/deps/npm/node_modules/undici/lib/web/fetch/index.js
index 9a685d680a1..b3b21873dcd 100644
--- a/deps/npm/node_modules/undici/lib/web/fetch/index.js
+++ b/deps/npm/node_modules/undici/lib/web/fetch/index.js
@@ -1950,8 +1950,10 @@ async function httpNetworkFetch (
   // 19. Run these steps in parallel:

   //    1. Run these steps, but abort when fetchParams is canceled:
-  fetchParams.controller.onAborted = onAborted
-  fetchParams.controller.on('terminated', onAborted)
+  if (!fetchParams.controller.resume) {
+    fetchParams.controller.on('terminated', onAborted)
+  }
+
   fetchParams.controller.resume = async () => {
     // 1. While true
     while (true) {
@@ -2120,8 +2122,6 @@ async function httpNetworkFetch (
           }
           location = headersList.get('location', true)

-          this.body = new Readable({ read: resume })
-
           const decoders = []

           const willFollow = location && request.redirect === 'follow' &&
@@ -2139,7 +2139,7 @@ async function httpNetworkFetch (
             // CVE fix similar to urllib3 (GHSA-gm62-xv2j-4w53) and curl (CVE-2022-32206).
             const maxContentEncodings = 5
             if (codings.length > maxContentEncodings) {
-              reject(new Error(`too many content-encodings in response: ${codings.length}, maximum allowed is ${maxContentEncodings}`))
+              this.abort(new Error(`too many content-encodings in response: ${codings.length}, maximum allowed is ${maxContentEncodings}`))
               return true
             }

@@ -2172,6 +2172,8 @@ async function httpNetworkFetch (
             }
           }

+          this.body = new Readable({ read: resume })
+
           const onError = this.onError.bind(this)

           resolve({
@@ -2218,10 +2220,6 @@ async function httpNetworkFetch (
             fetchParams.controller.off('terminated', this.abort)
           }

-          if (fetchParams.controller.onAborted) {
-            fetchParams.controller.off('terminated', fetchParams.controller.onAborted)
-          }
-
           fetchParams.controller.ended = true

           this.body.push(null)
diff --git a/deps/npm/node_modules/undici/lib/web/websocket/connection.js b/deps/npm/node_modules/undici/lib/web/websocket/connection.js
index bb87d361e4b..1197b9b650c 100644
--- a/deps/npm/node_modules/undici/lib/web/websocket/connection.js
+++ b/deps/npm/node_modules/undici/lib/web/websocket/connection.js
@@ -192,7 +192,7 @@ function establishWebSocketConnection (url, protocols, client, ws, onEstablish,
         // is specified, the server needs to include the same field and one of
         // the selected subprotocol values in its response for the connection to
         // be established.
-        if (!requestProtocols.includes(secProtocol)) {
+        if (requestProtocols === null || !requestProtocols.includes(secProtocol)) {
           failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
           return
         }
diff --git a/deps/npm/node_modules/undici/lib/web/websocket/permessage-deflate.js b/deps/npm/node_modules/undici/lib/web/websocket/permessage-deflate.js
index 6a6e43899c5..0b3d493db82 100644
--- a/deps/npm/node_modules/undici/lib/web/websocket/permessage-deflate.js
+++ b/deps/npm/node_modules/undici/lib/web/websocket/permessage-deflate.js
@@ -63,7 +63,12 @@ class PerMessageDeflate {

         if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
           callback(new MessageSizeExceededError())
+          // The inflater may still hold buffered input that can emit a late
+          // zlib error. Remove the data listener, then deterministically stop
+          // the stream so a subsequent 'error' cannot fire without a listener
+          // (which would terminate the process as an unhandled error event).
           this.#inflate.removeAllListeners()
+          this.#inflate.destroy()
           this.#inflate = null
           return
         }
diff --git a/deps/npm/node_modules/undici/lib/web/websocket/receiver.js b/deps/npm/node_modules/undici/lib/web/websocket/receiver.js
index a7dea7fae1c..b36ef9f9378 100644
--- a/deps/npm/node_modules/undici/lib/web/websocket/receiver.js
+++ b/deps/npm/node_modules/undici/lib/web/websocket/receiver.js
@@ -249,6 +249,20 @@ class ByteParser extends Writable {
         if (isControlFrame(this.#info.opcode)) {
           this.#loop = this.parseControlFrame(body)
           this.#state = parserStates.INFO
+
+          // If the automatic PONG/CLOSE reply filled the socket's write buffer,
+          // stop parsing and resume on drain so a PING flood cannot grow the
+          // outbound queue without bound.
+          const socket = this.ws[kResponse].socket
+          if (this.#loop && socket.writableNeedDrain) {
+            this.#loop = false
+            socket.once('drain', () => {
+              if (this.destroyed) return
+              this.#loop = true
+              this.run(callback)
+            })
+            return
+          }
         } else {
           if (!this.#info.compressed) {
             if (!this.writeFragments(body)) {
diff --git a/deps/npm/node_modules/undici/package.json b/deps/npm/node_modules/undici/package.json
index cd46deca244..4bccc5455b8 100644
--- a/deps/npm/node_modules/undici/package.json
+++ b/deps/npm/node_modules/undici/package.json
@@ -1,6 +1,6 @@
 {
   "name": "undici",
-  "version": "6.28.0",
+  "version": "6.29.1",
   "description": "An HTTP/1.1 client, written from scratch for Node.js",
   "homepage": "https://undici.nodejs.org",
   "bugs": {
diff --git a/deps/npm/package.json b/deps/npm/package.json
index 2d30f3b6237..b1e37e484a1 100644
--- a/deps/npm/package.json
+++ b/deps/npm/package.json
@@ -1,5 +1,5 @@
 {
-  "version": "12.1.0",
+  "version": "12.2.2",
   "name": "npm",
   "description": "a package manager for JavaScript",
   "workspaces": [
@@ -48,20 +48,20 @@
   },
   "dependencies": {
     "@isaacs/string-locale-compare": "^1.1.0",
-    "@npmcli/arborist": "^10.0.3",
-    "@npmcli/config": "^11.1.0",
+    "@npmcli/arborist": "^10.0.4",
+    "@npmcli/config": "^11.2.0",
     "@npmcli/fs": "^6.0.0",
     "@npmcli/git": "^8.0.0",
     "@npmcli/map-workspaces": "^6.0.0",
     "@npmcli/metavuln-calculator": "^10.0.0",
     "@npmcli/package-json": "^8.0.0",
-    "@npmcli/promise-spawn": "^10.0.0",
+    "@npmcli/promise-spawn": "^10.0.1",
     "@npmcli/redact": "^5.0.0",
     "@npmcli/run-script": "^11.0.0",
     "@sigstore/tuf": "^5.0.0",
     "abbrev": "^5.0.0",
     "archy": "~1.0.0",
-    "bin-links": "^7.0.0",
+    "bin-links": "^7.0.1",
     "cacache": "^21.0.1",
     "chalk": "^5.6.2",
     "ci-info": "^4.4.0",
@@ -76,11 +76,11 @@
     "is-cidr": "^7.0.0",
     "json-parse-even-better-errors": "^6.0.0",
     "libnpmaccess": "^11.0.0",
-    "libnpmdiff": "^9.0.3",
-    "libnpmexec": "^11.0.3",
-    "libnpmfund": "^8.0.3",
+    "libnpmdiff": "^9.0.4",
+    "libnpmexec": "^11.0.5",
+    "libnpmfund": "^8.0.4",
     "libnpmorg": "^9.0.0",
-    "libnpmpack": "^10.0.3",
+    "libnpmpack": "^10.0.4",
     "libnpmpublish": "^12.0.1",
     "libnpmsearch": "^10.0.0",
     "libnpmteam": "^9.0.0",
@@ -100,12 +100,12 @@
     "npm-registry-fetch": "^20.0.1",
     "npm-user-validate": "^5.0.0",
     "p-map": "^7.0.4",
-    "pacote": "^22.0.0",
+    "pacote": "^22.0.1",
     "parse-conflict-json": "^6.0.0",
     "proc-log": "^7.0.0",
     "qrcode-terminal": "^0.12.0",
     "read": "^6.0.0",
-    "semver": "^7.8.5",
+    "semver": "^7.8.6",
     "spdx-expression-parse": "^4.0.0",
     "ssri": "^14.0.0",
     "supports-color": "^10.2.2",
@@ -262,6 +262,6 @@
   },
   "license": "Artistic-2.0",
   "engines": {
-    "node": "^22.22.2 || ^24.15.0 || >=26.0.0 || >=27.0.0-alpha"
+    "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
   }
 }
diff --git a/deps/npm/test/fixtures/mock-oidc.js b/deps/npm/test/fixtures/mock-oidc.js
index e2e11b27224..86735571b94 100644
--- a/deps/npm/test/fixtures/mock-oidc.js
+++ b/deps/npm/test/fixtures/mock-oidc.js
@@ -54,6 +54,7 @@ const mockOidc = async (t, {
   mockGithubOidcOptions = false,
   mockOidcTokenExchangeOptions = false,
   publishOptions = {},
+  publish = true,
   provenance = false,
   oidcVisibilityOptions = false,
 }) => {
@@ -139,7 +140,9 @@ const mockOidc = async (t, {
     registry.getVisibility({ spec: packageName, visibility: oidcVisibilityOptions })
   }

-  registry.publish(packageName, publishOptions)
+  if (publish) {
+    registry.publish(packageName, publishOptions)
+  }

   /**
    * this will nock / mock all the successful requirements for provenance and
diff --git a/deps/npm/test/lib/cli/entry.js b/deps/npm/test/lib/cli/entry.js
index 369927dace0..3c34172970a 100644
--- a/deps/npm/test/lib/cli/entry.js
+++ b/deps/npm/test/lib/cli/entry.js
@@ -150,6 +150,31 @@ t.test('unsupported node version', async t => {
   )
 })

+t.test('prerelease node versions', async t => {
+  for (const [version, supported] of [
+    ['v27.0.0-alpha.0.0.0', true],
+    ['v28.0.0-alpha.0.0.0', true],
+    ['v27.0.0-rc.0', true],
+    ['v26.0.0-alpha.0', false],
+    ['v23.0.0-alpha.0', false],
+  ]) {
+    await t.test(version, async t => {
+      const { cli, logs } = await cliMock(t, {
+        globals: {
+          'process.argv': ['node', 'npm', '--version'],
+          'process.version': version,
+        },
+      })
+      await cli(process)
+      if (supported) {
+        t.strictSame(logs.warn, [])
+      } else {
+        t.match(logs.warn[0], `does not support Node.js ${version}.`)
+      }
+    })
+  }
+})
+
 t.test('non-ascii dash', async t => {
   const { cli, logs } = await cliMock(t, {
     globals: {
diff --git a/deps/npm/test/lib/commands/approve-scripts.js b/deps/npm/test/lib/commands/approve-scripts.js
index 449382d19e9..38f9bc9b9df 100644
--- a/deps/npm/test/lib/commands/approve-scripts.js
+++ b/deps/npm/test/lib/commands/approve-scripts.js
@@ -859,3 +859,250 @@ t.test('approve-scripts --all with only bundled deps has nothing to review', asy
   const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
   t.notOk(pkg.allowScripts, 'no allowScripts written')
 })
+
+// Layout produced by install-strategy=linked: the real package lives in the store, node_modules holds a symlink to it, and the hidden lockfile records that isolated layout (npm/cli#9939).
+const setupLinkedProject = (t, { allowScripts, noResolved = false } = {}) => {
+  const storeDir = 'canvas@1.0.0-c2FsdHNhbHRzYWx0c2FsdA'
+  const storeLoc = `node_modules/.store/${storeDir}/node_modules/canvas`
+  const tarUrl = noResolved
+    ? undefined
+    : 'https://registry.npmjs.org/canvas/-/canvas-1.0.0.tgz'
+  const pkg = {
+    name: 'host',
+    version: '1.0.0',
+    dependencies: { canvas: '^1.0.0' },
+  }
+  if (allowScripts !== undefined) {
+    pkg.allowScripts = allowScripts
+  }
+  return {
+    'package.json': JSON.stringify(pkg, null, 2),
+    'package-lock.json': JSON.stringify({
+      name: pkg.name,
+      version: pkg.version,
+      lockfileVersion: 3,
+      requires: true,
+      packages: {
+        '': pkg,
+        'node_modules/canvas': {
+          version: '1.0.0',
+          resolved: tarUrl,
+          hasInstallScript: true,
+        },
+      },
+    }),
+    node_modules: {
+      '.package-lock.json': JSON.stringify({
+        lockfileVersion: 3,
+        requires: true,
+        packages: {
+          [`node_modules/.store/${storeDir}`]: {},
+          [storeLoc]: {
+            version: '1.0.0',
+            resolved: tarUrl,
+            hasInstallScript: true,
+          },
+          'node_modules/canvas': {
+            resolved: storeLoc,
+            link: true,
+          },
+        },
+      }),
+      '.store': {
+        [storeDir]: {
+          node_modules: {
+            canvas: {
+              'package.json': JSON.stringify({
+                name: 'canvas',
+                version: '1.0.0',
+                scripts: { install: 'echo install' },
+              }),
+            },
+          },
+        },
+      },
+      canvas: t.fixture('symlink', `.store/${storeDir}/node_modules/canvas`),
+    },
+  }
+}
+
+// loadActual only trusts the hidden lockfile when it is newer than every dir under node_modules (assertNoNewer allows 10ms), and fixture creation order makes that racy, so bump its mtime past the fixture writes.
+const trustHiddenLockfile = (prefix) => {
+  const future = new Date(Date.now() + 60_000)
+  fs.utimesSync(resolve(prefix, 'node_modules', '.package-lock.json'), future, future)
+}
+
+t.test('approve-scripts <pkg> under linked strategy writes a registry pin, not store paths', async t => {
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLinkedProject(t),
+  })
+  trustHiddenLockfile(prefix)
+  await npm.exec('approve-scripts', ['canvas'])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { 'canvas@1.0.0': true })
+})
+
+t.test('approve-scripts --all under linked strategy writes a registry pin, not store paths', async t => {
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLinkedProject(t),
+    config: { all: true },
+  })
+  trustHiddenLockfile(prefix)
+  await npm.exec('approve-scripts', [])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { 'canvas@1.0.0': true })
+})
+
+t.test('approve-scripts --pending is empty when the registry pin covers a linked store package', async t => {
+  const { npm, prefix, joinedOutput } = await mockNpm(t, {
+    prefixDir: setupLinkedProject(t, { allowScripts: { 'canvas@1.0.0': true } }),
+    config: { 'allow-scripts-pending': true },
+  })
+  trustHiddenLockfile(prefix)
+  await npm.exec('approve-scripts', [])
+  t.match(joinedOutput(), /No packages with unreviewed install scripts/)
+})
+
+t.test('deny-scripts under linked strategy writes a name-only deny', async t => {
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLinkedProject(t),
+  })
+  trustHiddenLockfile(prefix)
+  await npm.exec('deny-scripts', ['canvas'])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { canvas: false })
+})
+
+const setupLocalFileDepProject = (t) => {
+  const pkg = {
+    name: 'host',
+    version: '1.0.0',
+    dependencies: { foo: 'file:./local-foo' },
+  }
+  return {
+    'package.json': JSON.stringify(pkg, null, 2),
+    'package-lock.json': JSON.stringify({
+      name: 'host',
+      version: '1.0.0',
+      lockfileVersion: 3,
+      requires: true,
+      packages: {
+        '': pkg,
+        'local-foo': {
+          name: 'local-foo',
+          version: '1.0.0',
+          hasInstallScript: true,
+        },
+        'node_modules/foo': {
+          resolved: 'local-foo',
+          link: true,
+        },
+      },
+    }),
+    'local-foo': {
+      'package.json': JSON.stringify({
+        name: 'local-foo',
+        version: '1.0.0',
+        scripts: { install: 'echo install' },
+      }),
+    },
+    node_modules: {
+      foo: t.fixture('symlink', '../local-foo'),
+    },
+  }
+}
+
+t.test('approve-scripts <name> finds a local file: dep through its link', async t => {
+  // The Link is named `foo` while its target is named `local-foo`; positional matching must dereference the Link instead of skipping it (npm/cli#9939 review).
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLocalFileDepProject(t),
+  })
+  await npm.exec('approve-scripts', ['foo'])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { 'file:../local-foo': true })
+})
+
+t.test('deny-scripts <name> finds a local file: dep through its link', async t => {
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLocalFileDepProject(t),
+  })
+  await npm.exec('deny-scripts', ['foo'])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { 'file:../local-foo': false })
+})
+
+t.test('approve-scripts <pkg> under linked strategy without resolved URLs approves by name', async t => {
+  // omit-lockfile-registry-resolved: the store package has no resolved URL, so it cannot be pinned but must still be approved by name via the incoming Link's edge.
+  const { npm, prefix } = await mockNpm(t, {
+    prefixDir: setupLinkedProject(t, { noResolved: true }),
+  })
+  trustHiddenLockfile(prefix)
+  await npm.exec('approve-scripts', ['canvas'])
+
+  const pkg = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(pkg.allowScripts, { canvas: true })
+})
+
+for (const state of ['missing', 'stale']) {
+  t.test(`prune keeps denies with a ${state} hidden lockfile`, async t => {
+    // With no trusted version, the versioned deny still blocks at runtime, so prune must fail closed and keep it instead of flipping the effective policy to allowed (npm/cli#9941 review).
+    const Arborist = require('@npmcli/arborist')
+    const isScriptAllowed = require('@npmcli/arborist/lib/script-allowed.js')
+    const allowScripts = {
+      canvas: true,
+      'canvas@1.0.0': false,
+    }
+
+    const { npm, prefix } = await mockNpm(t, {
+      prefixDir: setupLinkedProject(t, { allowScripts }),
+      config: { 'install-strategy': 'linked' },
+    })
+
+    const hidden = resolve(prefix, 'node_modules', '.package-lock.json')
+    if (state === 'missing') {
+      fs.unlinkSync(hidden)
+    } else {
+      fs.utimesSync(hidden, new Date(0), new Date(0))
+    }
+
+    t.equal(npm.config.get('omit-lockfile-registry-resolved'), false)
+
+    const arb = new Arborist({ ...npm.flatOptions, path: prefix })
+    const tree = await arb.loadActual()
+    const target = [...tree.inventory.values()]
+      .find(node => !node.isLink && node.name === 'canvas')
+
+    t.ok(target, 'finds the installed target')
+    t.strictSame(
+      isScriptAllowed.getTrustedRegistryIdentity(target),
+      { name: 'canvas', version: null },
+      'recovers the registry name without inventing a trusted version'
+    )
+    t.equal(
+      isScriptAllowed(target, allowScripts),
+      false,
+      'the versioned deny blocks the package before pruning'
+    )
+
+    await npm.exec('install-scripts', ['prune'])
+
+    const pkg = JSON.parse(
+      fs.readFileSync(resolve(prefix, 'package.json'), 'utf8')
+    )
+    t.strictSame(
+      pkg.allowScripts,
+      allowScripts,
+      'pruning preserves both the allow and its active deny exception'
+    )
+    t.equal(
+      isScriptAllowed(target, pkg.allowScripts),
+      false,
+      'the package remains denied after pruning'
+    )
+  })
+}
diff --git a/deps/npm/test/lib/commands/dist-tag.js b/deps/npm/test/lib/commands/dist-tag.js
index 5de9acb1da8..531ade8aab7 100644
--- a/deps/npm/test/lib/commands/dist-tag.js
+++ b/deps/npm/test/lib/commands/dist-tag.js
@@ -1,6 +1,13 @@
 const t = require('tap')
 const realFetch = require('npm-registry-fetch')
+const npa = require('npm-package-arg')
 const mockNpm = require('../../fixtures/mock-npm')
+const {
+  circleciIdToken,
+  githubIdToken,
+  gitlabIdToken,
+  mockOidc,
+} = require('../../fixtures/mock-oidc')

 const fixtures = {
   workspace: {
@@ -61,6 +68,30 @@ const tags = {
   },
 }

+const mockTagRequests = ({
+  registry,
+  packageName,
+  token,
+  tags: tagData,
+  mutation,
+}) => {
+  const spec = npa(packageName)
+  const path = `/-/package/${spec.escapedName}/dist-tags`
+  const authorization = `Bearer ${token}`
+
+  registry.nock.get(registry.fullPath(path))
+    .matchHeader('authorization', authorization)
+    .reply(200, tagData)
+
+  if (mutation) {
+    registry.nock[mutation.method.toLowerCase()](
+      registry.fullPath(`${path}/${encodeURIComponent(mutation.tag)}`)
+    )
+      .matchHeader('authorization', authorization)
+      .reply(200, {})
+  }
+}
+
 const mockDist = async (t, { ...npmOpts } = {}) => {
   const getTag = async (url) => ({ ...tags })[url]

@@ -362,6 +393,351 @@ t.test('remove missing pkg name', async t => {
   )
 })

+t.test('oidc token exchange', async t => {
+  const packageName = '@npmcli/test-package'
+  const fallbackToken = 'existing-fallback-token'
+  const exchangeToken = 'exchange-token'
+  const privateGithubToken = githubIdToken({ visibility: 'private' })
+
+  const setup = (t, options = {}) => mockOidc(t, {
+    packageName,
+    publish: false,
+    ...options,
+  })
+
+  t.test('list uses the exchanged token', async t => {
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: { token: exchangeToken },
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0' },
+    })
+
+    await npm.exec('dist-tag', ['list', packageName])
+  })
+
+  t.test('add uses the exchanged token for GET and PUT', async t => {
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: { token: exchangeToken },
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0' },
+      mutation: { method: 'PUT', tag: 'next' },
+    })
+
+    await npm.exec('dist-tag', ['add', `${packageName}@2.0.0`, 'next'])
+  })
+
+  t.test('remove uses the exchanged token for GET and DELETE', async t => {
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: { token: exchangeToken },
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0', old: '0.9.0' },
+      mutation: { method: 'DELETE', tag: 'old' },
+    })
+
+    await npm.exec('dist-tag', ['remove', packageName, 'old'])
+  })
+
+  for (const [provider, oidcOptions, idToken] of [
+    ['gitlab', { gitlab: true, NPM_ID_TOKEN: gitlabIdToken({ visibility: 'private' }) }, gitlabIdToken({ visibility: 'private' })],
+    ['circleci', { circleci: true, NPM_ID_TOKEN: circleciIdToken() }, circleciIdToken()],
+  ]) {
+    t.test(`${provider} uses NPM_ID_TOKEN for exchange`, async t => {
+      const providerIdToken = oidcOptions.NPM_ID_TOKEN || idToken
+      const { npm, registry } = await setup(t, {
+        oidcOptions,
+        mockOidcTokenExchangeOptions: {
+          idToken: providerIdToken,
+          body: { token: exchangeToken },
+        },
+      })
+      mockTagRequests({
+        registry,
+        packageName,
+        token: exchangeToken,
+        tags: { latest: '1.0.0' },
+      })
+
+      await npm.exec('dist-tag', ['list', packageName])
+    })
+  }
+
+  t.test('custom scoped registry uses its audience and auth key', async t => {
+    const registryUrl = 'https://registry.zzz.org'
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      config: {
+        '@npmcli:registry': registryUrl,
+      },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.zzz.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: { token: exchangeToken },
+      },
+      load: {
+        registry: registryUrl,
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0' },
+    })
+
+    await npm.exec('dist-tag', ['list', packageName])
+  })
+
+  for (const testCase of [
+    {
+      name: 'no CI',
+      oidcOptions: {},
+    },
+    {
+      name: 'missing GitHub OIDC permissions',
+      oidcOptions: { github: true, ACTIONS_ID_TOKEN_REQUEST_URL: '' },
+    },
+    {
+      name: 'GitHub identity token request failure',
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        statusCode: 500,
+      },
+    },
+    {
+      name: 'token exchange failure',
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        statusCode: 500,
+        body: { message: 'exchange failed' },
+      },
+    },
+    {
+      name: 'token exchange response missing token',
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: {},
+      },
+    },
+  ]) {
+    t.test(`${testCase.name} preserves fallback credentials`, async t => {
+      const { npm, registry } = await setup(t, {
+        config: {
+          '//registry.npmjs.org/:_authToken': fallbackToken,
+        },
+        ...testCase,
+      })
+      mockTagRequests({
+        registry,
+        packageName,
+        token: fallbackToken,
+        tags: { latest: '1.0.0' },
+      })
+
+      await npm.exec('dist-tag', ['list', packageName])
+    })
+  }
+
+  t.test('current package list exchanges after resolving its name', async t => {
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: privateGithubToken,
+        body: { token: exchangeToken },
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0' },
+    })
+
+    await npm.exec('dist-tag', ['list'])
+  })
+
+  t.test('workspace list exchanges separately for each package', async t => {
+    const workspaceToken = githubIdToken({ visibility: 'private' })
+    const prefixDir = {
+      'package.json': JSON.stringify({
+        name: 'workspace-root',
+        version: '1.0.0',
+        workspaces: ['workspace-a', 'workspace-b'],
+      }),
+      'workspace-a': {
+        'package.json': JSON.stringify({
+          name: 'workspace-a',
+          version: '1.0.0',
+        }),
+      },
+      'workspace-b': {
+        'package.json': JSON.stringify({
+          name: 'workspace-b',
+          version: '1.0.0',
+        }),
+      },
+    }
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      config: { workspaces: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: workspaceToken,
+        times: 2,
+      },
+      load: { prefixDir },
+    })
+
+    for (const [name, token] of [
+      ['workspace-a', 'workspace-a-exchange-token'],
+      ['workspace-b', 'workspace-b-exchange-token'],
+    ]) {
+      registry.mockOidcTokenExchange({
+        packageName: name,
+        idToken: workspaceToken,
+        body: { token },
+      })
+      mockTagRequests({
+        registry,
+        packageName: name,
+        token,
+        tags: { latest: '1.0.0' },
+      })
+    }
+
+    await npm.exec('dist-tag', [])
+  })
+
+  t.test('workspace list restores fallback credentials after a failed exchange', async t => {
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      config: { workspaces: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: privateGithubToken,
+        times: 3,
+      },
+      load: {
+        prefixDir: fixtures.workspace,
+        homeDir: {
+          '.npmrc': `//registry.npmjs.org/:_authToken=${fallbackToken}`,
+        },
+      },
+    })
+    for (const [name, token] of [
+      ['workspace-a', exchangeToken],
+      ['workspace-b', fallbackToken],
+      ['workspace-c', 'workspace-c-exchange-token'],
+    ]) {
+      const failed = name === 'workspace-b'
+      registry.mockOidcTokenExchange({
+        packageName: name,
+        idToken: privateGithubToken,
+        statusCode: failed ? 404 : 200,
+        body: failed ? { message: 'No trusted publisher configured' } : { token },
+      })
+      mockTagRequests({
+        registry,
+        packageName: name,
+        token,
+        tags: { latest: '1.0.0' },
+      })
+    }
+
+    await npm.exec('dist-tag', [])
+  })
+
+  t.test('does not run publish provenance checks', async t => {
+    const publicGithubToken = githubIdToken({ visibility: 'public' })
+    let visibilityCalls = 0
+    const { npm, registry } = await setup(t, {
+      oidcOptions: { github: true },
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: publicGithubToken,
+      },
+      mockOidcTokenExchangeOptions: {
+        idToken: publicGithubToken,
+        body: { token: exchangeToken },
+      },
+      load: {
+        mocks: {
+          libnpmaccess: {
+            getVisibility: () => {
+              visibilityCalls++
+              return { public: true }
+            },
+          },
+        },
+      },
+    })
+    mockTagRequests({
+      registry,
+      packageName,
+      token: exchangeToken,
+      tags: { latest: '1.0.0' },
+    })
+
+    await npm.exec('dist-tag', ['list', packageName])
+    t.equal(visibilityCalls, 0, 'must not check package visibility')
+  })
+
+  t.end()
+})
+
 t.test('completion', async t => {
   const { distTag } = await mockDist(t)

diff --git a/deps/npm/test/lib/commands/install-scripts.js b/deps/npm/test/lib/commands/install-scripts.js
index cf7063b5957..fd7051c7e44 100644
--- a/deps/npm/test/lib/commands/install-scripts.js
+++ b/deps/npm/test/lib/commands/install-scripts.js
@@ -334,3 +334,64 @@ t.test('install-scripts prune fails for global installs', async t => {
     { code: 'EGLOBAL' }
   )
 })
+
+t.test('install-scripts prune under linked strategy keeps the registry pin, drops store paths', async t => {
+  // Regression for npm/cli#9939: the buggy writer produced file:.store keys; prune must drop those and keep the valid registry pin covering the store package.
+  const storeDir = 'canvas@1.0.0-c2FsdHNhbHRzYWx0c2FsdA'
+  const storeLoc = `node_modules/.store/${storeDir}/node_modules/canvas`
+  const tarUrl = 'https://registry.npmjs.org/canvas/-/canvas-1.0.0.tgz'
+  const pkg = {
+    name: 'host',
+    version: '1.0.0',
+    dependencies: { canvas: '^1.0.0' },
+    allowScripts: {
+      'canvas@1.0.0': true,
+      [`file:.store/${storeDir}/node_modules/canvas`]: true,
+    },
+  }
+  const { npm, prefix, joinedOutput } = await mockNpm(t, {
+    prefixDir: {
+      'package.json': JSON.stringify(pkg, null, 2),
+      node_modules: {
+        '.package-lock.json': JSON.stringify({
+          lockfileVersion: 3,
+          requires: true,
+          packages: {
+            [`node_modules/.store/${storeDir}`]: {},
+            [storeLoc]: {
+              version: '1.0.0',
+              resolved: tarUrl,
+              hasInstallScript: true,
+            },
+            'node_modules/canvas': {
+              resolved: storeLoc,
+              link: true,
+            },
+          },
+        }),
+        '.store': {
+          [storeDir]: {
+            node_modules: {
+              canvas: {
+                'package.json': JSON.stringify({
+                  name: 'canvas',
+                  version: '1.0.0',
+                  scripts: { install: 'echo install' },
+                }),
+              },
+            },
+          },
+        },
+        canvas: t.fixture('symlink', `.store/${storeDir}/node_modules/canvas`),
+      },
+    },
+  })
+  // loadActual only trusts the hidden lockfile when it is newer than every dir under node_modules (assertNoNewer allows 10ms), and fixture creation order makes that racy, so bump its mtime past the fixture writes.
+  const future = new Date(Date.now() + 60_000)
+  fs.utimesSync(resolve(prefix, 'node_modules', '.package-lock.json'), future, future)
+  await npm.exec('install-scripts', ['prune'])
+
+  const updated = JSON.parse(fs.readFileSync(resolve(prefix, 'package.json'), 'utf8'))
+  t.strictSame(updated.allowScripts, { 'canvas@1.0.0': true })
+  t.match(joinedOutput(), /file:\.store.*\(package not installed\)/)
+})
diff --git a/deps/npm/test/lib/commands/patch.js b/deps/npm/test/lib/commands/patch.js
index ac409bf2d17..ffcb306f83f 100644
--- a/deps/npm/test/lib/commands/patch.js
+++ b/deps/npm/test/lib/commands/patch.js
@@ -1,4 +1,5 @@
 const fs = require('node:fs')
+const fsPromises = require('node:fs/promises')
 const path = require('node:path')
 const t = require('tap')
 const Arborist = require('@npmcli/arborist')
@@ -909,6 +910,64 @@ t.test('update: a patch that no longer applies to its baseline rejects with EPAT
   await t.rejects(npm.exec('patch', ['update', name]), { code: 'EPATCHBASE' })
 })

+// fs/promises whose rm always fails for the rebase workdir, mimicking a concurrent git process leaving it non-empty.
+const failingWorkdirRm = {
+  'node:fs/promises': {
+    ...fsPromises,
+    rm: async (p, opts) => {
+      if (path.basename(p).startsWith('npm-patch-rebase-')) {
+        throw Object.assign(new Error(`ENOTEMPTY: directory not empty, rmdir '${p}'`), { code: 'ENOTEMPTY' })
+      }
+      return fsPromises.rm(p, opts)
+    },
+  },
+}
+
+t.test('update: a failed workdir cleanup does not mask the real error', async t => {
+  const name = 'upd-drift-rm'
+  const { npm, registry } = await loadMockNpm(t, {
+    config: { 'ignore-scripts': true, audit: false },
+    strictRegistryNock: false,
+    prefixDir: rootWith({ [name]: '^1.0.0' }),
+    mocks: failingWorkdirRm,
+  })
+  await setupVersions(npm, registry, name, { '1.0.0': 'real\n', '2.0.0': 'real2\n' })
+  await npm.exec('install', [])
+  fs.mkdirSync(path.join(npm.prefix, 'patches'), { recursive: true })
+  fs.writeFileSync(path.join(npm.prefix, 'patches', `${name}@1.0.0.patch`),
+    '--- a/index.js\t\n+++ b/index.js\t\n@@ -1,1 +1,1 @@\n-NOT-THE-REAL-LINE\n+changed\n')
+  const pkg = readJson(path.join(npm.prefix, 'package.json'))
+  pkg.patchedDependencies = { [`${name}@1.0.0`]: `patches/${name}@1.0.0.patch` }
+  fs.writeFileSync(path.join(npm.prefix, 'package.json'), JSON.stringify(pkg))
+  npm.config.set('to', '2.0.0')
+  await t.rejects(npm.exec('patch', ['update', name]), { code: 'EPATCHBASE' })
+})
+
+t.test('update: a failed workdir cleanup does not fail a successful update', async t => {
+  const name = 'upd-exact-rm'
+  const { npm, joinedOutput, outputs, registry } = await loadMockNpm(t, {
+    config: { 'ignore-scripts': true, audit: false },
+    strictRegistryNock: false,
+    prefixDir: rootWith({ [name]: '^1.0.0' }),
+    mocks: failingWorkdirRm,
+  })
+  await setupVersions(npm, registry, name, { '1.0.0': 'a\nb\nc\n', '2.0.0': 'a\nb\nCC\n' })
+  await npm.exec('install', [])
+
+  outputs.length = 0
+  await npm.exec('patch', ['add', name])
+  const editDir = joinedOutput().match(/directory: (.+)/)[1].trim()
+  fs.writeFileSync(path.join(editDir, 'index.js'), 'AA\nb\nc\n')
+  await npm.exec('patch', ['commit', editDir])
+
+  npm.config.set('to', '2.0.0')
+  await npm.exec('patch', ['update', name])
+
+  const pkg = readJson(path.join(npm.prefix, 'package.json'))
+  t.same(pkg.patchedDependencies, { [`${name}@2.0.0`]: `patches/${name}@2.0.0.patch` },
+    'selector renamed to the new version')
+})
+
 t.test('update: when the new version already contains the patch, reports EPATCHEMPTY', async t => {
   const name = 'upd-empty'
   const { npm, joinedOutput, outputs, registry } = await loadMockNpm(t, {
diff --git a/deps/npm/test/lib/commands/publish.js b/deps/npm/test/lib/commands/publish.js
index 0a9fd2cd36f..9ddca285488 100644
--- a/deps/npm/test/lib/commands/publish.js
+++ b/deps/npm/test/lib/commands/publish.js
@@ -1420,6 +1420,123 @@ t.test('oidc token exchange - no provenance', t => {
     },
   }))

+  for (const fallback of [true, false]) {
+    t.test(`workspace exchange failure ${fallback ? 'restores fallback' : 'requires auth'}`, async t => {
+      const fallbackToken = 'existing-fallback-token'
+      const { npm, registry } = await mockOidc(t, {
+        oidcOptions: { github: true },
+        publish: false,
+        config: { workspaces: true },
+        mockGithubOidcOptions: {
+          audience: 'npm:registry.npmjs.org',
+          idToken: githubPrivateIdToken,
+          times: 2,
+        },
+        load: {
+          homeDir: fallback ? {
+            '.npmrc': `//registry.npmjs.org/:_authToken=${fallbackToken}`,
+          } : {},
+          prefixDir: {
+            'package.json': JSON.stringify({
+              name: 'workspace-root',
+              version: '1.0.0',
+              workspaces: ['workspace-a', 'workspace-b'],
+            }),
+            'workspace-a': {
+              'package.json': JSON.stringify({ name: 'workspace-a', version: '1.0.0' }),
+            },
+            'workspace-b': {
+              'package.json': JSON.stringify({ name: 'workspace-b', version: '1.0.0' }),
+            },
+          },
+        },
+      })
+      registry.mockOidcTokenExchange({
+        packageName: 'workspace-a',
+        idToken: githubPrivateIdToken,
+        body: { token: 'workspace-a-exchange-token' },
+      })
+      registry.publish('workspace-a', { token: 'workspace-a-exchange-token' })
+      registry.mockOidcTokenExchange({
+        packageName: 'workspace-b',
+        idToken: githubPrivateIdToken,
+        statusCode: 404,
+        body: { message: 'No trusted publisher configured' },
+      })
+      if (fallback) {
+        registry.publish('workspace-b', { token: fallbackToken })
+        await npm.exec('publish', [])
+      } else {
+        await t.rejects(npm.exec('publish', []), { code: 'ENEEDAUTH' })
+      }
+      t.equal(
+        npm.config.getCredentialsByURI('https://registry.npmjs.org/').token,
+        fallback ? fallbackToken : undefined
+      )
+    })
+  }
+
+  t.test('sequential operations clear OIDC tokens after exchange failure', async t => {
+    // These calls share one npm instance, unlike separate CLI invocations.
+    // The workspace tests above cover one real --workspaces command; this also checks recovery.
+    const packages = ['workflow-one', 'workflow-two', 'workflow-three']
+    const registryUrl = 'https://registry.npmjs.org/'
+    const authTokenKey = '//registry.npmjs.org/:_authToken'
+    const { npm, registry, joinedOutput } = await mockOidc(t, {
+      oidcOptions: { github: true },
+      publish: false,
+      mockGithubOidcOptions: {
+        audience: 'npm:registry.npmjs.org',
+        idToken: githubPrivateIdToken,
+        times: 3,
+      },
+      load: {
+        prefixDir: {
+          'package.json': JSON.stringify({ name: 'workflow-root', version: '1.0.0' }),
+          ...Object.fromEntries(packages.map(name => [name, {
+            'package.json': JSON.stringify({ name, version: '1.0.0' }),
+          }])),
+        },
+      },
+    })
+    t.equal(npm.config.getCredentialsByURI(registryUrl).token, undefined, 'no fallback token')
+
+    registry.mockOidcTokenExchange({
+      packageName: packages[0],
+      idToken: githubPrivateIdToken,
+      body: { token: 'first-exchange-token' },
+    })
+    registry.publish(packages[0], { token: 'first-exchange-token' })
+    await npm.exec('publish', [`./${packages[0]}`])
+    t.equal(npm.flatOptions[authTokenKey], 'first-exchange-token')
+    t.match(joinedOutput(), '+ workflow-one@1.0.0')
+
+    registry.mockOidcTokenExchange({
+      packageName: packages[1],
+      idToken: githubPrivateIdToken,
+      statusCode: 404,
+      body: { message: 'No trusted publisher configured' },
+    })
+    await t.rejects(
+      npm.exec('publish', [`./${packages[1]}`]),
+      { code: 'ENEEDAUTH' },
+      'failed exchange cannot reuse the previous operation token'
+    )
+    t.equal(npm.config.getCredentialsByURI(registryUrl).token, undefined, 'token is cleared')
+    t.notOk(Object.hasOwn(npm.flatOptions, authTokenKey), 'flat options contain no stale token')
+    t.notMatch(joinedOutput(), '+ workflow-two@1.0.0')
+
+    registry.mockOidcTokenExchange({
+      packageName: packages[2],
+      idToken: githubPrivateIdToken,
+      body: { token: 'third-exchange-token' },
+    })
+    registry.publish(packages[2], { token: 'third-exchange-token' })
+    await npm.exec('publish', [`./${packages[2]}`])
+    t.equal(npm.flatOptions[authTokenKey], 'third-exchange-token')
+    t.match(joinedOutput(), '+ workflow-three@1.0.0')
+  })
+
   t.test('dry-run can be used to check oidc config but not publish', oidcPublishTest({
     oidcOptions: { github: true },
     config: {
diff --git a/deps/npm/test/lib/commands/stage/index.js b/deps/npm/test/lib/commands/stage/index.js
index bd81c7aab5e..127c0ea8252 100644
--- a/deps/npm/test/lib/commands/stage/index.js
+++ b/deps/npm/test/lib/commands/stage/index.js
@@ -3,6 +3,7 @@ const { load: loadMockNpm } = require('../../../fixtures/mock-npm')
 const MockRegistry = require('@npmcli/mock-registry')
 const path = require('node:path')
 const fs = require('node:fs')
+const { githubIdToken, mockOidc } = require('../../../fixtures/mock-oidc')

 const pkg = '@npmcli/test-package'
 const token = 'test-auth-token'
@@ -31,6 +32,32 @@ t.test('stages a package from cwd', async t => {
   t.match(joinedOutput(), /\+ @npmcli\/test-package@1\.0\.0 \(staged\)/)
 })

+t.test('stages a package with the OIDC exchange token', async t => {
+  const idToken = githubIdToken({ visibility: 'private' })
+  const exchangeToken = 'exchange-token'
+  const { npm, registry } = await mockOidc(t, {
+    packageName: pkg,
+    oidcOptions: { github: true },
+    mockGithubOidcOptions: {
+      audience: 'npm:registry.npmjs.org',
+      idToken,
+    },
+    mockOidcTokenExchangeOptions: {
+      idToken,
+      body: { token: exchangeToken },
+    },
+    publishOptions: {
+      noPut: true,
+    },
+  })
+
+  registry.nock.post('/-/stage/package/@npmcli%2ftest-package')
+    .matchHeader('authorization', `Bearer ${exchangeToken}`)
+    .reply(201, {})
+
+  await npm.exec('stage', ['publish'])
+})
+
 t.test('stages with --dry-run', async t => {
   const { npm, joinedOutput, logs } = await loadMockNpm(t, {
     config: { ...authConfig, 'dry-run': true },
diff --git a/deps/npm/test/lib/utils/oidc.js b/deps/npm/test/lib/utils/oidc.js
new file mode 100644
index 00000000000..72f77261266
--- /dev/null
+++ b/deps/npm/test/lib/utils/oidc.js
@@ -0,0 +1,239 @@
+const t = require('tap')
+const { readFile } = require('node:fs/promises')
+const { join } = require('node:path')
+const mockGlobals = require('@npmcli/mock-globals')
+const mockNpm = require('../../fixtures/mock-npm')
+const tmock = require('../../fixtures/tmock')
+
+const registry = 'https://registry.npmjs.org/'
+const authTokenKey = '//registry.npmjs.org/:_authToken'
+const fallbackToken = 'fallback-token'
+const exchangeToken = 'exchange-token'
+
+const setup = async t => {
+  const { npm } = await mockNpm(t, {
+    config: ({ globalPrefix, home, prefix }) => ({
+      globalconfig: join(globalPrefix, 'etc', 'npmrc'),
+      prefix,
+      userconfig: join(home, '.npmrc'),
+    }),
+    globals: ({ globalPrefix, home, prefix }) => ({
+      'process.env.NPM_CONFIG_GLOBALCONFIG': join(globalPrefix, 'etc', 'npmrc'),
+      'process.env.NPM_CONFIG_PREFIX': prefix,
+      'process.env.NPM_CONFIG_USERCONFIG': join(home, '.npmrc'),
+    }),
+    npm: ({ other }) => ({
+      npmRoot: join(other, 'node'),
+    }),
+    otherDirs: {
+      node: { npmrc: '' },
+    },
+  })
+  mockGlobals(t, {
+    'process.env.NPM_ID_TOKEN': 'identity-token',
+    'process.env.ACTIONS_ID_TOKEN_REQUEST_URL': 'https://github.com/actions/id-token',
+    'process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN': 'request-token',
+  })
+  const ci = { GITLAB: true }
+  const responses = [{ token: exchangeToken }]
+  const { oidc } = tmock(t, '{LIB}/utils/oidc.js', {
+    'ci-info': ci,
+    'npm-registry-fetch': {
+      json: async (_url, opts) => {
+        const response = responses.shift()
+        if (response instanceof Error) {
+          throw response
+        }
+        if (typeof response === 'function') {
+          return response(opts)
+        }
+        return response
+      },
+    },
+    'make-fetch-happen': async () => ({
+      ok: false,
+      status: 500,
+      json: async () => ({}),
+    }),
+  })
+  const run = async (opts = { ...npm.flatOptions }, registryUrl = registry) => {
+    await oidc({ packageName: 'test-package', registry: registryUrl, opts, config: npm.config })
+    return opts
+  }
+  return { npm, ci, responses, run, oidc }
+}
+
+for (const failure of [
+  'exchange failure',
+  'missing exchange token',
+  'missing identity token',
+  'unsupported CI',
+  'missing GitHub permissions',
+  'GitHub identity request failure',
+]) {
+  t.test(`restores credentials before ${failure}`, async t => {
+    const { npm, ci, responses, run } = await setup(t)
+    npm.config.set(authTokenKey, fallbackToken, 'user')
+    const firstOpts = await run()
+    t.equal(firstOpts[authTokenKey], exchangeToken)
+    t.equal(npm.config.get(authTokenKey), exchangeToken)
+    t.equal(npm.config.get(authTokenKey, 'cli'), exchangeToken)
+    t.equal(npm.config.get(authTokenKey, 'user'), fallbackToken, 'user config is never overwritten')
+
+    if (failure === 'exchange failure') {
+      responses.push(new Error('exchange failed'))
+    } else if (failure === 'missing exchange token') {
+      responses.push({})
+    } else if (failure === 'unsupported CI') {
+      ci.GITLAB = false
+    } else {
+      delete process.env.NPM_ID_TOKEN
+      if (failure !== 'missing identity token') {
+        ci.GITLAB = false
+        ci.GITHUB_ACTIONS = true
+        if (failure === 'missing GitHub permissions') {
+          delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL
+        }
+      }
+    }
+
+    const nextOpts = await run()
+    t.equal(nextOpts[authTokenKey], fallbackToken, 'next request uses fallback credentials')
+    t.equal(firstOpts[authTokenKey], fallbackToken, 'previous options no longer contain the token')
+    t.equal(npm.config.get(authTokenKey, 'cli'), undefined, 'clears the runtime override')
+    t.equal(npm.config.get(authTokenKey, 'user'), fallbackToken, 'preserves user config')
+    t.equal(npm.flatOptions[authTokenKey], fallbackToken, 'restores flattened config')
+  })
+}
+
+for (const source of ['user', 'global', 'project', 'env', 'cli', 'none']) {
+  t.test(`preserves ${source} credentials when reusing flat options`, async t => {
+    const { npm, responses, run } = await setup(t)
+    if (source !== 'none') {
+      npm.config.set(authTokenKey, fallbackToken, source)
+    }
+    const opts = npm.flatOptions
+    await run(opts)
+    t.equal(npm.config.getCredentialsByURI(registry).token, exchangeToken)
+    // Populate the flat-options cache with the temporary runtime token.
+    const nextOpts = npm.flatOptions
+    responses.push({})
+    await run(opts)
+
+    const expected = source === 'none' ? undefined : fallbackToken
+    t.equal(opts[authTokenKey], expected)
+    t.equal(npm.config.get(authTokenKey), expected)
+    t.equal(npm.flatOptions[authTokenKey], expected)
+    t.equal(npm.config.get(authTokenKey, 'user'), source === 'user' ? fallbackToken : undefined)
+    t.not(npm.flatOptions, nextOpts, 'invalidates the cached temporary credentials')
+    if (source === 'none') {
+      t.notOk(Object.hasOwn(opts, authTokenKey), 'removes the temporary option entirely')
+    }
+  })
+}
+
+t.test('does not restore an earlier exchange token after multiple successes', async t => {
+  const { npm, responses, run } = await setup(t)
+  npm.config.set(authTokenKey, fallbackToken, 'user')
+  await run()
+  responses.push({ token: 'second-exchange-token' })
+  const secondOpts = await run()
+  t.equal(secondOpts[authTokenKey], 'second-exchange-token')
+  responses.push({})
+  const thirdOpts = await run()
+  t.equal(thirdOpts[authTokenKey], fallbackToken)
+  t.equal(npm.config.get(authTokenKey), fallbackToken)
+})
+
+t.test('clears the previous token before starting another exchange', async t => {
+  const { npm, responses, run } = await setup(t)
+  npm.config.set(authTokenKey, fallbackToken, 'user')
+  const firstOpts = await run()
+  responses.push(opts => {
+    t.equal(npm.config.get(authTokenKey), fallbackToken, 'old token is already cleared')
+    t.equal(firstOpts[authTokenKey], fallbackToken, 'old request options are already cleared')
+    t.equal(opts[authTokenKey], 'identity-token', 'exchange uses the identity token')
+    return { token: 'new-exchange-token' }
+  })
+  const nextOpts = await run()
+  t.equal(nextOpts[authTokenKey], 'new-exchange-token')
+  t.equal(npm.config.get(authTokenKey), 'new-exchange-token')
+})
+
+t.test('clears the previous registry token when switching registries', async t => {
+  const { npm, responses, run } = await setup(t)
+  const otherRegistry = 'https://other.registry.npmjs.org/'
+  const otherKey = '//other.registry.npmjs.org/:_authToken'
+  npm.config.set(authTokenKey, fallbackToken, 'user')
+  npm.config.set(otherKey, 'other-fallback', 'user')
+  await run()
+  responses.push({ token: 'other-exchange-token' })
+  const otherOpts = await run(undefined, otherRegistry)
+  t.equal(otherOpts[authTokenKey], fallbackToken)
+  t.equal(otherOpts[otherKey], 'other-exchange-token')
+  responses.push({})
+  const nextOpts = await run()
+  t.equal(nextOpts[authTokenKey], fallbackToken)
+  t.equal(nextOpts[otherKey], 'other-fallback')
+  t.equal(npm.config.get(otherKey), 'other-fallback')
+})
+
+t.test('preserves credentials explicitly replaced after an exchange', async t => {
+  const { npm, responses, run } = await setup(t)
+  const opts = await run()
+  npm.config.set(authTokenKey, 'updated-user-token', 'user')
+  opts[authTokenKey] = 'updated-request-token'
+  responses.push({})
+  await run(opts)
+  t.equal(npm.config.get(authTokenKey), 'updated-user-token')
+  t.equal(opts[authTokenKey], 'updated-request-token')
+})
+
+t.test('preserves a runtime credential replaced independently of OIDC', async t => {
+  const { npm, responses, run } = await setup(t)
+  await run()
+  npm.config.set(authTokenKey, 'updated-runtime-token', 'cli')
+  responses.push({})
+  const opts = await run()
+  t.equal(npm.config.get(authTokenKey, 'cli'), 'updated-runtime-token')
+  t.equal(opts[authTokenKey], 'updated-runtime-token')
+})
+
+t.test('saving config during an exchange never persists the OIDC token', async t => {
+  const { npm, run } = await setup(t)
+  const sources = ['user', 'project', 'global']
+  for (const source of sources) {
+    npm.config.set(authTokenKey, `${source}-fallback`, source)
+  }
+  await run()
+  t.equal(npm.config.get(authTokenKey, 'cli'), exchangeToken)
+  await t.rejects(npm.config.save('cli'), { message: 'invalid config location param: cli' })
+  for (const source of sources) {
+    t.equal(npm.config.get(authTokenKey, source), `${source}-fallback`)
+    await npm.config.save(source)
+    const content = await readFile(npm.config.data.get(source).source, 'utf8')
+    t.match(content, `${authTokenKey}=${source}-fallback`)
+    t.notMatch(content, exchangeToken)
+  }
+})
+
+t.test('the next invocation clears the token even with a different config', async t => {
+  const { npm, ci, run, oidc } = await setup(t)
+  npm.config.set(authTokenKey, fallbackToken, 'user')
+  const opts = await run()
+  ci.GITLAB = false
+  await oidc({ packageName: 'other-package', registry, opts: {}, config: {} })
+  t.equal(npm.config.get(authTokenKey, 'cli'), undefined)
+  t.equal(npm.config.get(authTokenKey), fallbackToken)
+  t.equal(opts[authTokenKey], fallbackToken)
+})
+
+t.test('does not copy package-specific fallback options into the next package', async t => {
+  const { npm, responses, run } = await setup(t)
+  npm.config.set(authTokenKey, fallbackToken, 'user')
+  const firstOpts = await run({ ...npm.flatOptions, [authTokenKey]: 'package-specific-token' })
+  responses.push({})
+  const nextOpts = await run()
+  t.equal(firstOpts[authTokenKey], 'package-specific-token')
+  t.equal(nextOpts[authTokenKey], fallbackToken)
+})