Compare commits

...
353 Commits
Author SHA1 Message Date
CaliBrain 2c6d6a02cd ci: debounce dev image builds instead of building nightly (#1376)
Replace the nightly cron and its check-changes job with a debounce.
Every push to main starts dev-image-debounce.yml, which waits out the
60-minute wait timer on the dev-image-debounce environment, then
dispatches the Docker workflow only if main still points at its commit.
A burst of merges now publishes one dev image, an hour after the last
merge.

The Docker workflow keeps only its tag and workflow_dispatch triggers,
so its history holds real builds only. The debounce workflow deletes its
own finished runs, so no-op runs don't pile up either.

Requires the dev-image-debounce environment with a 60-minute wait
timer (Settings → Environments).
2026-09-21 02:38:06 -04:00
dependabot[bot] 4a0675e0d3 build(deps): bump the python-deps group with 4 updates (#1375)
Bumps the python-deps group with 4 updates:
[gevent](https://github.com/gevent/gevent),
[emoji](https://github.com/carpedm20/emoji),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[ruff](https://github.com/astral-sh/ruff).

Updates `gevent` from 26.8.0 to 26.9.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/gevent/gevent/commit/003c77a6f3da41c014dd415022fb61f9d91fc95d"><code>003c77a</code></a>
Preparing release 26.9.0</li>
<li><a
href="https://github.com/gevent/gevent/commit/725ecc3e53dd74f3828f1cf189e1cbeaebbdfae9"><code>725ecc3</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2209">#2209</a>
from bojanz/issue2207-resolve-result-on-setup-failure</li>
<li><a
href="https://github.com/gevent/gevent/commit/a5b68e812e8ddf65d13dfa117d8656fcb713d69b"><code>a5b68e8</code></a>
Adjust the ThreadPool after an unexpected worker exit</li>
<li><a
href="https://github.com/gevent/gevent/commit/67a725659bd622ac476bd39019209e11a1f18f2b"><code>67a7256</code></a>
Resolve the ThreadResult when worker task setup fails</li>
<li><a
href="https://github.com/gevent/gevent/commit/a3b307bb82cd9b875933a964e883015bf0ce18b2"><code>a3b307b</code></a>
Add change note for <a
href="https://redirect.github.com/gevent/gevent/issues/2211">#2211</a> /
<a
href="https://redirect.github.com/gevent/gevent/issues/2039">#2039</a>
[skip ci]</li>
<li><a
href="https://github.com/gevent/gevent/commit/b0ec8d3b4cb7cde5799dc57d35f74267e3b8259a"><code>b0ec8d3</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2211">#2211</a>
from afonsojanu/fix/subprocess-stdin-mode-missing-bi...</li>
<li><a
href="https://github.com/gevent/gevent/commit/29b00308c74a703e26178229f6edacf98a31a1cb"><code>29b0030</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2210">#2210</a>
from Shivakarthikeya23/issue-1946</li>
<li><a
href="https://github.com/gevent/gevent/commit/47ea41c7e2bc8ca50785a60e929e7335c75fc308"><code>47ea41c</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2208">#2208</a>
from bojanz/issue2206-skip-missing-hooks</li>
<li><a
href="https://github.com/gevent/gevent/commit/0ee0c838cf50255c40647109de5391f84630af6a"><code>0ee0c83</code></a>
Report the full binary mode string from FileObjectPosix</li>
<li><a
href="https://github.com/gevent/gevent/commit/3f3dc574d2b1e5381ea70bfea0da565fd4fcd6c8"><code>3f3dc57</code></a>
Fix AsyncResult accumulating traceback frames on repeated get()</li>
<li>Additional commits viewable in <a
href="https://github.com/gevent/gevent/compare/26.8.0...26.9.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `emoji` from 2.15.0 to 2.16.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/carpedm20/emoji/releases">emoji's
releases</a>.</em></p>
<blockquote>
<h2>v2.16.0</h2>
<ul>
<li>Update to Unicode 18.0</li>
<li>Update translations to CLDR release-49-alpha2</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/carpedm20/emoji/blob/master/CHANGES.md">emoji's
changelog</a>.</em></p>
<blockquote>
<h2>v2.16.0 (2026-09-16)</h2>
<ul>
<li>Update to Unicode 18.0</li>
<li>Update translations to CLDR release-49-alpha2</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/carpedm20/emoji/commit/d5d59d591f8590ada989f0bdf31603b3fe84e103"><code>d5d59d5</code></a>
Merge pull request <a
href="https://redirect.github.com/carpedm20/emoji/issues/335">#335</a>
from carpedm20/update-unicode-18.0</li>
<li><a
href="https://github.com/carpedm20/emoji/commit/7acc7f0740b0ded33c7450d788c6641b74e84e16"><code>7acc7f0</code></a>
update to Unicode 18.0.0</li>
<li>See full diff in <a
href="https://github.com/carpedm20/emoji/compare/v2.15.0...v2.16.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.54.5 to 4.54.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.54.9 - MCP Server: Patch 17</h2>
<h2>MCP Server: Patch 17</h2>
<ul>
<li><a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4508/changes/e323a9d851b58a99b8b55b041218f415652a9fd6">Update
the MCP server</a></li>
<li><a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4508/commits/bc88accb2909629f7b0af68be73bebf014c17373">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 17 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4508">seleniumbase/SeleniumBase#4508</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.8...v4.54.9">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.8...v4.54.9</a></p>
<h2>4.54.8 - Fix command injection and more</h2>
<h2>Fix command injection and more</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7c8744798ed97616fe246effe982b93b0cc1d15e">Fix
command injection in console scripts</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7c9871c812bf410164b3a6ed14aec9b9cfe2abd3">Fix
issue with clearing a field that has autocomplete</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/969a36c19fb3a05eec50821ad6be63805a68e21a">Fix
typos in behave_sb.py</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/47034f13729e9f24564c18ba1952b1307798f080">Refactor
console scripts</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f7da99c23471a0f0a1101b0afd9a0a82d38a99ba">Update
the MCP server</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4bc64fb41dcd6ea6030887456fe97de72a3443a7">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c1b492a650c8077ae6ef43915b3a455fab8f4e8d">Update
examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Fix command injection and more by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4507">seleniumbase/SeleniumBase#4507</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.7...v4.54.8">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.7...v4.54.8</a></p>
<h2>4.54.7 - MCP Server: Patch 16</h2>
<h2>MCP Server: Patch 16</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/534c0c124002bfb48e10a7198194c91c61f4d4db">Update
the MCP server</a>
--&gt; annotations and docstrings</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4a5453ee14dff60599b058669eaff025488b75d2">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 16 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4505">seleniumbase/SeleniumBase#4505</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.6...v4.54.7">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.6...v4.54.7</a></p>
<h2>4.54.6 - MCP Server: Patch 15</h2>
<h2>MCP Server: Patch 15</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fbc665f3cb19ea6e5eb4ed6ffcf4eec32e4d9580">Add
tool annotations to the MCP Server</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4503">seleniumbase/SeleniumBase#4503</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a406b7f277de3a56dc3d83d4b5466dbca34a35e4">Update
the Dockerfile</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8c9805f870bd1a2a0bb9b8ef79e710848a9e81f2">Update
CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7f488faed38e8afce01d18b30291906e75dfe72d">Update
uv</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b4910211a8e801eebab9f0b1a6679bf1077ac53f">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 15 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4504">seleniumbase/SeleniumBase#4504</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ddd0f047e522c584221176bccf078784cac03b00"><code>ddd0f04</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4508">#4508</a>
from seleniumbase/mcp-server-patch-17</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/918078082a49b2a57f3a33fc9a4149973f780e64"><code>9180780</code></a>
Version 4.54.9</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bc88accb2909629f7b0af68be73bebf014c17373"><code>bc88acc</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d10f01b50168d62aea34bdc756ae249f75fdf642"><code>d10f01b</code></a>
Update MCP versioning</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e323a9d851b58a99b8b55b041218f415652a9fd6"><code>e323a9d</code></a>
Update the MCP server</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/52ceddcfbc466c937f88b322cfa69f11600b1e0a"><code>52ceddc</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4507">#4507</a>
from seleniumbase/fix-command-injection-and-more</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1b18c10456cc064ce38e7024913b285b3053197a"><code>1b18c10</code></a>
Version 4.54.8</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c1b492a650c8077ae6ef43915b3a455fab8f4e8d"><code>c1b492a</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a64c668254f20c3384c9f0ec1635de7e9eba45ce"><code>a64c668</code></a>
Update MCP versioning</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4bc64fb41dcd6ea6030887456fe97de72a3443a7"><code>4bc64fb</code></a>
Refresh Python dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.5...v4.54.9">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.7 to 0.16.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.8</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-16.</p>
<h3>Bug fixes</h3>
<ul>
<li>Visit functional <code>TypedDict</code> keyword arguments correctly
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li>
<li>[<code>flake8-simplify</code>] Detect nested <code>async with</code>
under sync parent (<code>SIM117</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li>
<li>[<code>flake8-simplify</code>] Preserve operand order in
<code>SIM109</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li>
<li>[<code>pyupgrade</code>] Preserve required parentheses in multiline
<code>UP040</code> fixes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28164">#28164</a>)</li>
<li>[<code>pyupgrade</code>] Skip <code>TypeVarTuple</code> and
<code>ParamSpec</code> conversions with bounds or constraints
(<code>UP040</code>, <code>UP046</code>, <code>UP047</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28505">#28505</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Add support for <code>__lazy_modules__</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28459">#28459</a>)</li>
<li>Recognize PEP-728 <code>TypedDict</code> class keywords (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28533">#28533</a>)</li>
<li>Recognize quoted types in <code>typing.TypeForm</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28507">#28507</a>)</li>
<li>Support conditional assignment to <code>__lazy_modules__</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28491">#28491</a>)</li>
<li>[<code>flake8-type-checking</code>] Prefer lazy imports over
<code>TYPE_CHECKING</code> on Python 3.15 and later (<code>TC001</code>,
<code>TC002</code>, <code>TC003</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28541">#28541</a>)</li>
<li>[<code>pyupgrade</code>] Make the fix for <code>UP040</code> always
unsafe (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28526">#28526</a>)</li>
<li>[<code>pyupgrade</code>] Stop recommending deprecated
<code>ByteString</code> aliases (<code>UP035</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28498">#28498</a>)</li>
<li>[<code>ruff</code>, <code>flake8-use-pathlib</code>] Recognize the
<code>parent_mode</code> argument (<code>RUF064</code>,
<code>PTH103</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28528">#28528</a>)</li>
<li>[<code>ruff</code>] Detect <code>\Z</code> in
<code>pytest.raises()</code> match patterns (<code>RUF043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28598">#28598</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Use rule name and code in formatter incompatibility warnings (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28571">#28571</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>[<code>flake8-tidy-imports</code>] Add
<code>extend-banned-api</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28644">#28644</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/VedantMadane"><code>@​VedantMadane</code></a></li>
<li><a href="https://github.com/alzeph"><code>@​alzeph</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/fredrikblau"><code>@​fredrikblau</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/Aniket-a14"><code>@​Aniket-a14</code></a></li>
<li><a href="https://github.com/r-b-1"><code>@​r-b-1</code></a></li>
</ul>
<h2>Install ruff 0.16.8</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.8/ruff-installer.sh
| sh
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.8</h2>
<p>Released on 2026-09-16.</p>
<h3>Bug fixes</h3>
<ul>
<li>Visit functional <code>TypedDict</code> keyword arguments correctly
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li>
<li>[<code>flake8-simplify</code>] Detect nested <code>async with</code>
under sync parent (<code>SIM117</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li>
<li>[<code>flake8-simplify</code>] Preserve operand order in
<code>SIM109</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li>
<li>[<code>pyupgrade</code>] Preserve required parentheses in multiline
<code>UP040</code> fixes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28164">#28164</a>)</li>
<li>[<code>pyupgrade</code>] Skip <code>TypeVarTuple</code> and
<code>ParamSpec</code> conversions with bounds or constraints
(<code>UP040</code>, <code>UP046</code>, <code>UP047</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28505">#28505</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Add support for <code>__lazy_modules__</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28459">#28459</a>)</li>
<li>Recognize PEP-728 <code>TypedDict</code> class keywords (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28533">#28533</a>)</li>
<li>Recognize quoted types in <code>typing.TypeForm</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28507">#28507</a>)</li>
<li>Support conditional assignment to <code>__lazy_modules__</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28491">#28491</a>)</li>
<li>[<code>flake8-type-checking</code>] Prefer lazy imports over
<code>TYPE_CHECKING</code> on Python 3.15 and later (<code>TC001</code>,
<code>TC002</code>, <code>TC003</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28541">#28541</a>)</li>
<li>[<code>pyupgrade</code>] Make the fix for <code>UP040</code> always
unsafe (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28526">#28526</a>)</li>
<li>[<code>pyupgrade</code>] Stop recommending deprecated
<code>ByteString</code> aliases (<code>UP035</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28498">#28498</a>)</li>
<li>[<code>ruff</code>, <code>flake8-use-pathlib</code>] Recognize the
<code>parent_mode</code> argument (<code>RUF064</code>,
<code>PTH103</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28528">#28528</a>)</li>
<li>[<code>ruff</code>] Detect <code>\Z</code> in
<code>pytest.raises()</code> match patterns (<code>RUF043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28598">#28598</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Use rule name and code in formatter incompatibility warnings (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28571">#28571</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>[<code>flake8-tidy-imports</code>] Add
<code>extend-banned-api</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28644">#28644</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/VedantMadane"><code>@​VedantMadane</code></a></li>
<li><a href="https://github.com/alzeph"><code>@​alzeph</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/fredrikblau"><code>@​fredrikblau</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/Aniket-a14"><code>@​Aniket-a14</code></a></li>
<li><a href="https://github.com/r-b-1"><code>@​r-b-1</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/62914c4b9b79a9e5004374a9c482ad2ed69290e1"><code>62914c4</code></a>
Bump version to 0.16.8 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28648">#28648</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c47e0cdc665f56536ce7f7a8ac40fa0ff3f79482"><code>c47e0cd</code></a>
[ty] Bound aliased intersection expansion during inference (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28546">#28546</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ff4747b509ab4fffbe5689fcae39caa7503d1dcf"><code>ff4747b</code></a>
renovate: update uv hashes correctly with setup-uv (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28621">#28621</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/94efeaa28630d80b2a74adf3c3963de99ed4ee29"><code>94efeaa</code></a>
[ty] Compact reachable binding and declaration histories (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28349">#28349</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/50020fb1e8aa83b0826fa6f5f33a1e93c10cc60e"><code>50020fb</code></a>
[ty] Avoid storing constraint nodes twice (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28375">#28375</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/446bb68da50014bb75f5ce1504a80c5883e3b0b2"><code>446bb68</code></a>
[ty] Compare bound-method receivers before signatures (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28384">#28384</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/304ab86be5de6507e276ab09f5b43f44aeb92469"><code>304ab86</code></a>
[<code>flake8-type-checking</code>] Prefer lazy imports over
<code>TYPE_CHECKING</code> on 3.15+ (`...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d940b244f7512427b0d87c7953e88c60e69f9bdf"><code>d940b24</code></a>
[ty] Watch script dependencies in CLI watch mode (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28125">#28125</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/fe9f065a504127b11da72c2ff6d7813ddf3ce8ac"><code>fe9f065</code></a>
[flake8-tidy-imports] Add <code>extend-banned-api</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28644">#28644</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/31131db44f057cce68fa6b95552b7db54167b0b3"><code>31131db</code></a>
[ty] Support <code>type[A &amp; B]</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27124">#27124</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.7...0.16.8">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-21 00:44:08 -04:00
CaliBrain e1c3f057ab fix: bypass recordings, welib wrong-md5 links, footer build sha (#1364) (#1373)
Debug screen recordings never started. Every bypass logged "Capturearea
1540x1050 at position 0.0 outside the screen size 1440x1880".We ask
ffmpeg for the fingerprint screen size plus margin, the size wealso pass
SeleniumBase as xvfb_metrics. SeleniumBase builds thatdisplay with
use_xauth=True, the image ships no xauth binary, so itfalls back to a
fixed 1440x1880 Xvfb and the requested size neverexists. Drop
-video_size so x11grab records the whole screen, whateversize it turned
out to be.

welib could hand back a link for a different book. Welib
answers/md5/<md5> with a search for that md5; when it does not have the
file,the resolver took the first "Download" on the results page
(md5a2c1dc0c... resolved to auto_download/9c8cf85d...). On an
/md5/<md5>page a GET/Download link is now only taken when its href names
thatmd5; otherwise the source is reported as not having the file.
Alsoremoves _get_download_urls_from_welib and _is_source_enabled:
themd5-template branch in _get_urls_for_source always handles welib
first,so that resolver could never run.

The footer showed the build date instead of the commit. CI
stampsBUILD_VERSION as <yyyy-mm-dd>-<sha> (pr-<sha> for PR images) and
thefooter kept its first seven characters, so dev images read
"Shelfmarkmain (2026-09)". Take the trailing commit sha instead: "main
(1a5b37d)".The full BUILD_VERSION stays in the hover title
2026-09-21 00:15:41 -04:00
CaliBrain d978896142 fix(auth): rename the API_KEY env var to SHELFMARK_API_KEY (#1374) 2026-09-21 00:10:10 -04:00
Gavin McFallandClaude Fable 5.1 3b280009ae feat(auth): static API_KEY (env) accepted as Bearer or X-Api-Key, cookie or key (#1366)
Supersedes #1353, per the discussion in #1352: one `API_KEY` environment
variable; when set, a request carrying it is authenticated as the first
admin, and cookie sessions keep working exactly as before (cookie **or**
key). Nothing else changes. No table, no UI, no settings-tab switch, no
per-user keys.

## What

- `API_KEY` (env). Unset → the feature is off and none of the new code
runs.
- `Authorization: Bearer <key>` or `X-Api-Key: <key>` on any existing
`/api/*` route authenticates that request as the first admin in
`users.db` (`ORDER BY id`), or as a bare admin identity
(`user_id="api"`, `is_admin=True`, no local user row) if the install has
no admin yet. Per request only; nothing is persisted; the admin's role
is read live, so deleting or demoting that user takes effect on the next
request.
- Both headers are checked and either may match. That is what makes the
key usable behind a reverse proxy that injects its own `Authorization`
header (oauth2-proxy, Authelia, forwardAuth): send the key in
`X-Api-Key`.
- A credential that is **not** the key is ignored and the request
continues on the normal session path, so proxy-forwarded tokens are
unaffected. Without a valid session such a request gets the usual `401
{"error": "Unauthorized"}`, identical to a request with no credential,
so there is nothing to probe.

## How

- `shelfmark/config/env.py`: `API_KEY = os.getenv("API_KEY",
"").strip()`.
- `shelfmark/core/api_key.py`: `extract_api_key_candidates()` (Bearer
token if the scheme is Bearer, then `X-Api-Key`) and `matches_api_key()`
using `hmac.compare_digest` on bytes.
- `shelfmark/core/user_db.py`: `UserDB.get_first_admin()`.
- `shelfmark/main.py`: `api_key_auth_middleware` (`before_request`,
registered before `proxy_auth_middleware`, which early-returns for keyed
requests). Only `/api/` paths; `/api/health` and `/api/auth/*` exempt;
no-op when `API_KEY` is unset or the auth mode is `none`. On a match it
mirrors the proxy-auth pattern: `session.clear()` then populate
`user_id` / `is_admin` / `db_user_id` for this request, `permanent =
False`, `modified = False`, `g.api_key_auth = True`. An `after_request`
hook guarantees no `Set-Cookie` is written for a keyed request even if a
handler dirties the session.
- `docs/api-access.md` (new), the `API_KEY` entry in
`docs/environment-variables.md`, and a README link.

## Security

- Constant-time compare; the key is never logged or echoed.
- Keyed requests never mint or refresh a session cookie and ignore any
cookie sent with them (a non-admin cookie plus the key yields admin for
that request; the browser's own session is left untouched and usable).
- The mismatch path touches neither the session nor `g`, so a stray
bearer on a browser request can neither log the user out nor change how
their cookie is refreshed.
- Store errors during the admin lookup fail closed (`500 {"error":
"Authentication error"}`), never to anonymous.
- Verified against Flask's `save_session` / `should_set_cookie`
ordering, and under auth modes `none`, `builtin`, `proxy`.

## Tests

`tests/core/test_api_key_env.py` (36): extraction and matching;
first-admin lookup; middleware behaviour on a guarded route and an admin
route, with and without a user_db, `X-Api-Key`, both-headers
combinations, no `Set-Cookie` when a handler dirties the session,
incoming non-admin cookie ignored, browser cookie still usable after a
keyed request, security headers, store error → 500, mismatch → guard's
401 / cookie path / permanent cookie untouched, unset → off, exempt
paths and path probes, `none` and `proxy` modes, deleted and demoted
first admin, a keyed write passing the guard. Existing auth suites
unchanged. All CI gates green on the fork:
https://github.com/gavinmcfall/shelfmark/pull/2 (CI-only draft).

Also exercised against a running instance: 47 scripted checks including
150 concurrent requests, proxy-mode switching through the key, an
unset-key restart, and a log scan for the key.

## Naming

`API_KEY` as discussed. If you'd rather namespace it
(`SHELFMARK_API_KEY`) to avoid clashing with other tools' env vars in
shared compose files, it is a one-line change; say the word.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 00:00:42 -04:00
splitsec2 1a5b37d9d3 fix(deluge): send seeding ratio limit under Deluge's own keys (#1367)
Deluge's per-torrent options are `stop_at_ratio` (bool) and `stop_ratio`
(float), and `torrentmanager` checks `options['stop_at_ratio'] and
get_ratio() >= options['stop_ratio']`. We were putting the indexer's
float into `stop_at_ratio`, which only switched stopping on and left the
daemon's global ratio (default 2.0) as the one actually enforced. A
`ratio_limit` of 0 turned stopping off entirely. `stop_at_ratio_enabled`
is not a Deluge option at all.

Deluge has no per-torrent seeding time limit, `seed_time_limit` is a
global core preference, so the value is logged as unapplied instead of
sent as a key the daemon drops.

qBittorrent and Transmission already honour both indexer limits, so this
removes a silent difference between clients.

## Verification

- `tests/prowlarr/test_deluge_client.py`: the ratio arrives as
`stop_ratio` with `stop_at_ratio` set, and no key Deluge does not define
is sent. Both fail on current main and pass here.
- Full suite (3165), ruff, ruff format, basedpyright, vulture green.
2026-09-20 23:06:14 -04:00
splitsec2 7c8e89c567 fix(googlebooks): page by the capped size, not the raw limit (#1370)
The Google Books search builds `maxResults` as `min(limit, 40)` because
the API caps a page at 40 volumes, but advances `startIndex` by the full
`limit`. The pages then stop tiling. With `limit=50`, page 1 covers
items 0 to 39 and page 2 starts at 50, so items 40 to 49 are never
returned and every later page drops another 10.

This computes the page size once and uses it for both `maxResults` and
`startIndex`. The shipped frontend asks for 40 and is unaffected.
`/api/metadata/search` clamps `limit` to 100, so an API caller passing
41 to 100 was hitting it.

One thing I left alone. The provider uses the base `search_paginated`
heuristic, `has_more = len(books) >= options.limit`, which still reports
`has_more: false` for a limit above 40 since Google can never return
that many. That was already the behaviour before this change, and fixing
it means either touching the shared heuristic or adding a provider
override, so I kept this patch to the stride. Happy to follow up if you
want it.

## Verification

- `tests/metadata/test_googlebooks_parse.py`: pages 1 and 2 at
`limit=50` must tile exactly, plus a guard that `limit=25` still strides
by 25. The first fails on current main and passes here.
- Full suite (3165), ruff, ruff format, basedpyright, vulture green.
2026-09-20 23:05:48 -04:00
splitsec2 bc03ad062e fix(http): keep the host of a protocol-relative download link (#1368)
`get_absolute_url()` replaced both `netloc` and `scheme` whenever either
one was missing. A protocol-relative href such as
`//cdn.example.org/f.epub`, scraped from a page on
`https://annas-archive.org/...`, parses with a netloc and an empty
scheme, so it came back pointing at the page's own host. The download
then 404s and the source is skipped.

Each field now falls back to the base URL only when the parsed URL does
not supply it. Plain relative paths resolve exactly as before, which the
control test covers.

This affects the Z-Library, welib and generic download link handling in
`release_sources/direct_download/annas_archive.py`.

## Verification

- New `tests/download/test_http_absolute_url.py`: a protocol-relative
link keeps its own host, and a plain `/path` still resolves against the
base. The first fails on current main and passes here.
- Full suite (3165), ruff, ruff format, basedpyright, vulture green.
2026-09-20 23:04:22 -04:00
splitsec2 ab3aa9a8b0 fix(requests): reject non-object items in the batch endpoint (#1369)
`POST /api/requests/batch` checks that `requests` is a non-empty list
and then hands each element to the shared preparation helper, which
calls `.get()` on it. A bare string, number or null in the list raises
`AttributeError` and the caller gets a 500, while `POST /api/requests`
answers 400 with a message for the same mistake.

This validates the element type beside the existing list check. One bad
item rejects the whole batch rather than being reported per item, which
matches the endpoint's current contract: every other failure path
already aborts the batch with a single error body, as
`test_batch_create_requests_is_atomic` asserts. Responses for valid
payloads are unchanged.

## Verification

- `tests/core/test_request_routes_api.py`: a case per bad shape (int,
str, null, list), plus a mixed valid and invalid batch that asserts
nothing was created. All fail on current main with a 500 and pass here.
- Full suite (3168), ruff, ruff format, basedpyright, vulture green.
2026-09-20 23:03:31 -04:00
Paul Rimmer d4619be69a Feature: Show the AA search result stats (#1362)
When doing a direct search for a book, show the stats of the AA results.
For example if we search for "The Great Gatsby", AA reports it has 240
hits and shows the first page of 50. Provide this stats info in the
shelfmark webUI via ResultsSection.tsx and ReleaseModal.tsx. This table
shows what should be displayed based on the total number of hits found:

|Total	|Display|
|-------|-------|
|1	|"Result 1 (1 Total)"|
|6	|"Results 1-6 (6 Total)"|
|144	|"Results 1-50 (144 Total)"|
|500+	|"Results 1-50 (500+ Total)"|

Currently, shelfmark also only shows us the first 50 search hits even if
there were more available from AA. This could be added later if
considered desirable.

As usual, a picture is worth a 1000 words:

<img width="1012" height="610" alt="direct-results-stat"
src="https://github.com/user-attachments/assets/8c0c688f-444e-482a-a9a3-2dee5a5563b8"
/>

<img width="1013" height="741" alt="universal-results-info"
src="https://github.com/user-attachments/assets/399bbb79-87f2-4432-a3d0-64937795f5f1"
/>

Coded with llama.cpp, opencode and 🤖
2026-09-20 13:03:32 -04:00
splitsec2 c1315a2b23 fix(download): check task ownership before serving queued files (#1357)
`/api/localdownload` resolves the file through the live queue and
returns it before checking who owns the task; the owner check only runs
on the download-history fallback, once the task has aged out of the
queue. Task ids are source ids, so two users who searched the same book
can end up with the same id.

This applies the same rule on the queue path, reusing the
`_task_owned_by_actor` helper the cancel/retry/priority routes already
use, so both paths answer a non-owner with the same 404. Admin behaviour
is unchanged.

The 404 matches what this endpoint's history path already returns for a
non-owner rather than the 403 `download_not_owned` the
cancel/retry/priority routes use, happy to switch it if you prefer
consistency with the siblings instead.

## Verification

- `tests/core/test_activity_routes_api.py`: the owner still receives
their queued file; a different user receives 404. The new case fails on
current main and passes here; the existing history-fallback test is
unchanged.
- Full suite (3148), ruff, ruff format, basedpyright, vulture green.
2026-09-20 12:56:23 -04:00
splitsec2 7934924678 fix(queue): don't stamp CANCELLED over a finished download (#1361)
`cancel_download` reads the task status under the queue lock, releases
it, and only then writes CANCELLED through `update_status`. A download
that finishes in that window has its COMPLETE overwritten. The queue and
the UI show the task as cancelled while the file is already on disk, and
the terminal hook fires for both statuses.

The check and the write now happen in a single lock hold. Because the
lock is non-reentrant and the terminal hook has to run after it is
released (the stall canceller depends on that), the lock-held part of
`update_status` moved into a small private helper that both paths share;
`update_status` is a thin wrapper over it. A cancel arriving once the
task is already terminal still returns `False`.

## Verification

-
`tests/core/test_queue.py::test_cancel_does_not_overwrite_a_download_that_finished_first`:
a worker thread completes the download while the cancel is in flight,
with the handover driven by events rather than sleeps. The task stays
complete. Fails on main, passes here.
- Full suite (3147), plus `tests/download/` and
`tests/core/test_download_api_guardrails.py`, ruff, ruff format,
basedpyright, vulture green.
2026-09-20 12:54:05 -04:00
splitsec2 a6204a318e fix(oidc): reject backslash paths in the return_to sanitizer (#1359)
The OIDC `return_to` sanitizer rejects values starting with `//` and
then relies on `urlsplit` to catch anything carrying a netloc. A value
such as `/\host` has no netloc, so it is stored in the session and used
as the post-login redirect target and browsers resolve the backslash as
a path separator, which lands the user outside the app after a
successful login.

`_normalize_return_to` now also rejects values whose path contains a
backslash. That matches the frontend sanitizer in `authRedirect.ts`,
which parses with `URL` and already discards those forms, so the two
ends agree again. The check covers the path only, so query and fragment
backslashes still round-trip, and it also catches the script-root case
where `/app/\host` strips to `/\host`.

## Verification

- New cases in `tests/core/test_oidc_routes.py` cover the rejected
forms, including under a script root, and confirm `/`, `/settings` and
`/search?q=x#frag` are unaffected. They fail on current main and pass
here.
- Full suite (3155), ruff, ruff format, basedpyright, vulture green.
2026-09-20 12:51:21 -04:00
splitsec2 545480c557 fix(download): default is_admin to False in the request policy guard (#1358)
`_resolve_policy_mode_for_current_user` reads `session.get("is_admin",
True)`, so a session carrying `user_id` but no `is_admin` key skips the
request policy entirely, while every other admin check in the codebase
defaults the key to `False`.

This uses the same default here. Every authenticated login path
(builtin, CWA, proxy, OIDC) writes `is_admin` into the session, and
`AUTH_METHOD=none` is already short-circuited one line earlier, so
sessions from those flows behave exactly as before.

## Verification

- `tests/core/test_request_routes_api.py::TestDownloadPolicyGuards`: a
session without `is_admin` now gets `policy_requires_request` and
nothing is queued. Fails on current main, passes here.
- Full suite (3147), ruff, ruff format, basedpyright, vulture green.
2026-09-20 12:50:53 -04:00
splitsec2 127dd82615 fix(users): apply user updates only after the payload validates (#1360)
`PUT /api/users/me` and `PUT /api/admin/users/<id>` write the new
password hash, and then the profile fields, before the rest of the
payload is checked. When the request is rejected further down as an
invalid role, an admin-only setting, an invalid settings value, the
route answers 400 with those writes already committed, so the caller
sees an error while the password has in fact changed.

Both routes now validate the whole payload before touching the database,
and the password hash is folded into the same `update_user` call as the
other fields so the field write is a single transaction. Error messages,
status codes and the order they are reported in are unchanged.

## Verification

- New tests in `tests/core/test_self_user_routes.py` and
`tests/core/test_admin_users_api.py` assert that a rejected update
leaves the password, profile fields and role as they were, plus a
positive case that a valid payload still applies all three. They fail on
current main and pass here.
- Full suite (3150), ruff, ruff format, basedpyright, vulture green.
2026-09-20 12:50:14 -04:00
splitsec2 acd59f7cbb feat(auth): provision proxy users as non-admin once an admin exists (#1356)
With `AUTH_METHOD=proxy` and no admin group configured, every user the
proxy authenticates for the first time is provisioned as an admin
(`is_admin = True` unless the user already exists in `users.db`). The
intent to never lock an instance out makes sense, but the effect is that
anyone the SSO gate lets through becomes an administrator. On an
instance shared with family or a small community that is a footgun; I
hit it when the first invited reader landed as an admin.

This keeps the guarantee and removes the footgun: the first account is
still provisioned as an admin while the instance has no admin at all,
and later first-time users follow a new `PROXY_AUTH_DEFAULT_ROLE`
setting (Security tab / env), default `user`. Known users keep their
stored role; the `PROXY_AUTH_ADMIN_GROUP_NAME` path is unchanged and
still takes precedence. I couldn't find a way with Cloudflare access to
pass this along.

Changes: `UserDB.has_admin()`, `_proxy_default_is_admin()` in the proxy
middleware, the new `SelectField` beside the other proxy settings, the
regenerated `docs/environment-variables.md` entry and a row in
`docs/reverse-proxy.md`.

Compatibility: the default moves from "everyone admin" to "first admin,
then users". Accounts already in `users.db` are unaffected; new SSO
users on an existing instance become regular users unless
`PROXY_AUTH_DEFAULT_ROLE=admin` is set. If you would rather ship this
purely opt-in I can flip the default to `admin`.

## Verification

- `tests/core/test_auth_api.py::TestProxyProvisioningRole`: first user
admin / second user not; `PROXY_AUTH_DEFAULT_ROLE=admin` restores the
old behaviour; an admin from another auth source counts as "an admin
exists"; a known user keeps their role whatever the default.
- Full suite (3094), ruff, ruff format, basedpyright, vulture green.
- Running on my own instance since 2026-09-19.
2026-09-19 23:27:13 -04:00
dependabot[bot] c42edac363 build(deps): bump the gh-actions group with 6 updates (#1350)
Bumps the gh-actions group with 6 updates:

| Package | From | To |
| --- | --- | --- |
|
[docker/setup-buildx-action](https://github.com/docker/setup-buildx-action)
| `4.3.0` | `4.4.0` |
|
[docker/build-push-action](https://github.com/docker/build-push-action)
| `7.3.0` | `7.4.0` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `10.0.1`
| `10.1.0` |
| [github/codeql-action/init](https://github.com/github/codeql-action) |
`4.37.9` | `4.38.0` |
|
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
| `4.37.9` | `4.38.0` |
|
[github/codeql-action/analyze](https://github.com/github/codeql-action)
| `4.37.9` | `4.38.0` |

Updates `docker/setup-buildx-action` from 4.3.0 to 4.4.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/setup-buildx-action/releases">docker/setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.4.0</h2>
<ul>
<li>Use official Buildx releases for cloud driver by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/606">docker/setup-buildx-action#606</a></li>
<li>Pull BuildKit image before builder creation by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/609">docker/setup-buildx-action#609</a></li>
<li>Use shared error helpers for Buildx and Docker commands by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/620">docker/setup-buildx-action#620</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.95.0 to 0.100.0 in
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/610">docker/setup-buildx-action#610</a>
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/618">docker/setup-buildx-action#618</a>
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/619">docker/setup-buildx-action#619</a></li>
<li>Bump <code>@​humanfs/node</code> from 0.16.7 to 0.16.8 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/614">docker/setup-buildx-action#614</a></li>
<li>Bump js-yaml from 5.3.0 to 5.4.2 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/608">docker/setup-buildx-action#608</a>
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/617">docker/setup-buildx-action#617</a></li>
<li>Bump postcss-selector-parser from 7.1.1 to 7.1.5 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/611">docker/setup-buildx-action#611</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/setup-buildx-action/compare/v4.3.0...v4.4.0">https://github.com/docker/setup-buildx-action/compare/v4.3.0...v4.4.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/594f3bf4285d9ea8dc53c9a0c9c4092420091003"><code>594f3bf</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/609">#609</a>
from crazy-max/pull-buildkit-image-before-create</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/bd6e702fc33b636671900d5b5edfab64698c9c25"><code>bd6e702</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/6268c9da9abbd1309c8a16a75f92a878715c3032"><code>6268c9d</code></a>
pull BuildKit image before builder creation</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/e8235251b82e23c90e6fad50016f0a78b7f28f11"><code>e823525</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/621">#621</a>
from docker/dependabot/github_actions/codeql-actions-...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/533ed8ed095b0b133ef16fb495aad119524e220d"><code>533ed8e</code></a>
build(deps): bump the codeql-actions group with 2 updates</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/bedaf135699075c88620cd30772b9b6eadc9ba99"><code>bedaf13</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/620">#620</a>
from crazy-max/shared-error-helpers</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/d5079fba84d5edd23d25ba7f3045122175ca6ee2"><code>d5079fb</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/226a61612ab71c26bbd805f955834049a4a9772f"><code>226a616</code></a>
use shared error helpers for Buildx and Docker commands</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/77ce7f4bab9bc462d825001cde7f82d409ee474c"><code>77ce7f4</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/619">#619</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/0dc1dc94f0f7c064e93fda72884ca71e054c0354"><code>0dc1dc9</code></a>
[dependabot skip] chore: update generated content</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/setup-buildx-action/compare/37fe631027851001ddb9b187196cc803df7f5f0e...594f3bf4285d9ea8dc53c9a0c9c4092420091003">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/build-push-action` from 7.3.0 to 7.4.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.4.0</h2>
<ul>
<li>Use the shared error helper for Buildx commands by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/build-push-action/pull/1620">docker/build-push-action#1620</a></li>
<li>Prevent workflow command injection in metadata logs by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/build-push-action/pull/1617">docker/build-push-action#1617</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.92.0 to 0.100.0 in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1614">docker/build-push-action#1614</a>
<a
href="https://redirect.github.com/docker/build-push-action/pull/1618">docker/build-push-action#1618</a>
<a
href="https://redirect.github.com/docker/build-push-action/pull/1621">docker/build-push-action#1621</a></li>
<li>Bump <code>@​humanfs/node</code> from 0.16.7 to 0.16.8 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1609">docker/build-push-action#1609</a></li>
<li>Bump brace-expansion from 1.1.13 to 1.1.18 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1592">docker/build-push-action#1592</a></li>
<li>Bump csv-parse from 7.0.0 to 7.0.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1613">docker/build-push-action#1613</a></li>
<li>Bump js-yaml from 4.3.0 to 4.3.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1605">docker/build-push-action#1605</a>
<a
href="https://redirect.github.com/docker/build-push-action/pull/1615">docker/build-push-action#1615</a></li>
<li>Bump nanoid from 3.3.16 to 3.3.18 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1611">docker/build-push-action#1611</a></li>
<li>Bump postcss from 8.5.10 to 8.5.25 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1590">docker/build-push-action#1590</a></li>
<li>Bump postcss-selector-parser from 7.1.1 to 7.1.5 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1606">docker/build-push-action#1606</a></li>
<li>Bump sigstore from 4.1.0 to 4.1.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1577">docker/build-push-action#1577</a></li>
<li>Bump undici from 6.27.0 to 6.28.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1594">docker/build-push-action#1594</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.3.0...v7.4.0">https://github.com/docker/build-push-action/compare/v7.3.0...v7.4.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/build-push-action/commit/c3c9e263c25d99ce0380d002d59b67737d91b0dc"><code>c3c9e26</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1621">#1621</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/459b6741834dcd35f946352017e7675bd2089d42"><code>459b674</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/4dedcb23c91d79c1629bf53ec2c3bcfffef5b34e"><code>4dedcb2</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.99.0 to
0.100.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/379bf63a979bd70751945601fa04c50674509952"><code>379bf63</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1620">#1620</a>
from crazy-max/buildx-error-message</li>
<li><a
href="https://github.com/docker/build-push-action/commit/9877975c9e0b0b661592ff61049069507f9bc2f6"><code>9877975</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/7ed0556ffafb8eb312463411ef0a84a1dfe24d94"><code>7ed0556</code></a>
use the shared Buildx error summary helper</li>
<li><a
href="https://github.com/docker/build-push-action/commit/91670ba5a4df99a24efff8637a78c83fd1b0f6b1"><code>91670ba</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1618">#1618</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/80dbc8614a5c0ce4356740f69179cf829ecdc79a"><code>80dbc86</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/50cac3a3b6f55e6015d6483d1dd72a3ecb90d20d"><code>50cac3a</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.98.0 to
0.99.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/03b4d6cac0163b44733e1fa60adfd6da560ee4d1"><code>03b4d6c</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1617">#1617</a>
from crazy-max/fix-metadata-workflow-commands</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/build-push-action/compare/53b7df96c91f9c12dcc8a07bcb9ccacbed38856a...c3c9e263c25d99ce0380d002d59b67737d91b0dc">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 10.0.1 to 10.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v10.1.0 🌈 New output <code>python-runtime-id</code>and respect
NO_PROXY</h2>
<h2>Changes</h2>
<p>This release adds more bheind the scene security improvements and
also 2 small improvements.</p>
<h3>NO_PROXY</h3>
<p>This action now respects <code>no_proxy/NO_PROXY</code> environment
variables which were previously ignored.</p>
<h3>New output <code>python-runtime-id</code></h3>
<p>The new output <code>python-runtime-id</code> can be used to know
which python version exactly was installed if you use
<code>activate-environment</code>. See <a
href="https://redirect.github.com/pyca/cryptography/pull/15572#discussion_r3913508686">pyca/cryptography#15572</a>
for details on why this can be useful.</p>
<h2>🐛 Bug fixes</h2>
<ul>
<li>fix: respect no proxy directive <a
href="https://github.com/mj0nez"><code>@​mj0nez</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1037">#1037</a>)</li>
<li>Use JSON + a typed wrapper instead of TS codegen <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1025">#1025</a>)</li>
</ul>
<h2>🚀 Enhancements</h2>
<ul>
<li>Expose a Python &quot;identity&quot; output <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1036">#1036</a>)</li>
<li>Verify downloads with astral-sh/versions checksums <a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1033">#1033</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>chore: update known checksums for 0.12.12 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1041">#1041</a>)</li>
<li>chore: update known checksums for 0.12.10/0.12.11 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1038">#1038</a>)</li>
<li>chore: update known checksums for 0.12.9 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1035">#1035</a>)</li>
<li>chore: update known checksums for 0.12.7/0.12.8 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1031">#1031</a>)</li>
<li>chore: update known checksums for 0.12.6 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1030">#1030</a>)</li>
<li>chore: update known checksums for 0.12.5 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1020">#1020</a>)</li>
<li>Use self-repo syntax for all in-repo actions/reusable workflows <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1024">#1024</a>)</li>
<li>Pin one-shot tools <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1022">#1022</a>)</li>
<li>ci: remove obsolete direct push attempts <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1019">#1019</a>)</li>
</ul>
<h2>📚 Documentation</h2>
<ul>
<li>docs: update version references to v10.0.1 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1018">#1018</a>)</li>
</ul>
<h2>⬆️ Dependency updates</h2>
<ul>
<li>chore(deps-dev): roll up Dependabot updates <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1043">#1043</a>)</li>
<li>Harden npm install defaults <a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1026">#1026</a>)</li>
<li>Add dependency cooldowns <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1021">#1021</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/bec219d24cd3e171d82865faccec33120bb574f4"><code>bec219d</code></a>
chore(deps-dev): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1043">#1043</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/b90ec40d15bfa44c33c6700196eb6efcdddb4373"><code>b90ec40</code></a>
fix: respect no proxy directive (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1037">#1037</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/421feb646df5262e7dd93bc54161edfa30372417"><code>421feb6</code></a>
chore: update known checksums for 0.12.12 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1041">#1041</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f634bf473ad85bf3e23a613f52c5fa9f363874fc"><code>f634bf4</code></a>
Expose a Python &quot;identity&quot; output (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1036">#1036</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/a6772c8f0a09dc9e3582c70a994b0c55af921803"><code>a6772c8</code></a>
chore: update known checksums for 0.12.10/0.12.11 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1038">#1038</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e105c8fb1d7b13074b851babdaef4185243c6a07"><code>e105c8f</code></a>
chore: update known checksums for 0.12.9 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1035">#1035</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cd13f9217092d43a771cf9ba7b09bdd3da8d7c4d"><code>cd13f92</code></a>
Verify downloads with astral-sh/versions checksums (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1033">#1033</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/3aef7b92c52cec135792ea1e95f4c77683d39e61"><code>3aef7b9</code></a>
chore: update known checksums for 0.12.7/0.12.8 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1031">#1031</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/d08d816a1ea176d61a318eff45abd3dffef415b1"><code>d08d816</code></a>
chore: update known checksums for 0.12.6 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1030">#1030</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/19b4d1e990bec64818914c40230bde93a0de300b"><code>19b4d1e</code></a>
Harden npm install defaults (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1026">#1026</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/20cfd1bf945f4377ade1205e4dbc17946fc9a30d...bec219d24cd3e171d82865faccec33120bb574f4">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/init` from 4.37.9 to 4.38.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.38.0</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/b96794f015dfd88f77b49b1c93e0fa7110f94c63"><code>b96794f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4131">#4131</a>
from github/update-v4.38.0-7e08580a9</li>
<li><a
href="https://github.com/github/codeql-action/commit/02d5093871674ea20274117103ce3038c73c77ef"><code>02d5093</code></a>
Update changelog for v4.38.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/7e08580a93dc4e4b9dda167e364577035cf504c6"><code>7e08580</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4130">#4130</a>
from github/henrymercer/workflow-runner-sizing</li>
<li><a
href="https://github.com/github/codeql-action/commit/bfcc52b4f5d98468a5993daa0bf0e4fb3f3ed698"><code>bfcc52b</code></a>
Run slow macOS checks on larger runners</li>
<li><a
href="https://github.com/github/codeql-action/commit/8c251e757c0260283fc50214a06ac768b61d3af4"><code>8c251e7</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4129">#4129</a>
from github/update-bundle/codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/0b7ca400df35985869d4b9146a067865d4115da1"><code>0b7ca40</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/40484b339517c6bcf00f81eebc95ca041ddca505"><code>40484b3</code></a>
Update default bundle to codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/977e6ceaea7361825998245d787fa3b4d6b9e5df"><code>977e6ce</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4124">#4124</a>
from github/henrymercer/toolcache-bundle-cleanup</li>
<li><a
href="https://github.com/github/codeql-action/commit/40a6b3824794ae1156e1a5320d32e364bf1dcebc"><code>40a6b38</code></a>
Address toolcache cleanup review feedback</li>
<li><a
href="https://github.com/github/codeql-action/commit/deece8f852f048bc3f52fd42c9cc7a99b1ebb252"><code>deece8f</code></a>
Apply suggestion from <a
href="https://github.com/henrymercer"><code>@​henrymercer</code></a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.9 to 4.38.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.38.0</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/b96794f015dfd88f77b49b1c93e0fa7110f94c63"><code>b96794f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4131">#4131</a>
from github/update-v4.38.0-7e08580a9</li>
<li><a
href="https://github.com/github/codeql-action/commit/02d5093871674ea20274117103ce3038c73c77ef"><code>02d5093</code></a>
Update changelog for v4.38.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/7e08580a93dc4e4b9dda167e364577035cf504c6"><code>7e08580</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4130">#4130</a>
from github/henrymercer/workflow-runner-sizing</li>
<li><a
href="https://github.com/github/codeql-action/commit/bfcc52b4f5d98468a5993daa0bf0e4fb3f3ed698"><code>bfcc52b</code></a>
Run slow macOS checks on larger runners</li>
<li><a
href="https://github.com/github/codeql-action/commit/8c251e757c0260283fc50214a06ac768b61d3af4"><code>8c251e7</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4129">#4129</a>
from github/update-bundle/codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/0b7ca400df35985869d4b9146a067865d4115da1"><code>0b7ca40</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/40484b339517c6bcf00f81eebc95ca041ddca505"><code>40484b3</code></a>
Update default bundle to codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/977e6ceaea7361825998245d787fa3b4d6b9e5df"><code>977e6ce</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4124">#4124</a>
from github/henrymercer/toolcache-bundle-cleanup</li>
<li><a
href="https://github.com/github/codeql-action/commit/40a6b3824794ae1156e1a5320d32e364bf1dcebc"><code>40a6b38</code></a>
Address toolcache cleanup review feedback</li>
<li><a
href="https://github.com/github/codeql-action/commit/deece8f852f048bc3f52fd42c9cc7a99b1ebb252"><code>deece8f</code></a>
Apply suggestion from <a
href="https://github.com/henrymercer"><code>@​henrymercer</code></a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.9 to 4.38.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.38.0</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.38.0 - 09 Sept 2026</h2>
<ul>
<li>On GitHub-hosted runners, the CodeQL Action now deletes unused
CodeQL bundles from the toolcache before downloading a different bundle,
which frees up disk space for the analysis. We expect to roll this
change out to everyone in September. <a
href="https://redirect.github.com/github/codeql-action/pull/4124">#4124</a></li>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and downloads the native <code>linux-arm64</code>
CodeQL bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0">2.27.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4129">#4129</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/b96794f015dfd88f77b49b1c93e0fa7110f94c63"><code>b96794f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4131">#4131</a>
from github/update-v4.38.0-7e08580a9</li>
<li><a
href="https://github.com/github/codeql-action/commit/02d5093871674ea20274117103ce3038c73c77ef"><code>02d5093</code></a>
Update changelog for v4.38.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/7e08580a93dc4e4b9dda167e364577035cf504c6"><code>7e08580</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4130">#4130</a>
from github/henrymercer/workflow-runner-sizing</li>
<li><a
href="https://github.com/github/codeql-action/commit/bfcc52b4f5d98468a5993daa0bf0e4fb3f3ed698"><code>bfcc52b</code></a>
Run slow macOS checks on larger runners</li>
<li><a
href="https://github.com/github/codeql-action/commit/8c251e757c0260283fc50214a06ac768b61d3af4"><code>8c251e7</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4129">#4129</a>
from github/update-bundle/codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/0b7ca400df35985869d4b9146a067865d4115da1"><code>0b7ca40</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/40484b339517c6bcf00f81eebc95ca041ddca505"><code>40484b3</code></a>
Update default bundle to codeql-bundle-v2.27.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/977e6ceaea7361825998245d787fa3b4d6b9e5df"><code>977e6ce</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4124">#4124</a>
from github/henrymercer/toolcache-bundle-cleanup</li>
<li><a
href="https://github.com/github/codeql-action/commit/40a6b3824794ae1156e1a5320d32e364bf1dcebc"><code>40a6b38</code></a>
Address toolcache cleanup review feedback</li>
<li><a
href="https://github.com/github/codeql-action/commit/deece8f852f048bc3f52fd42c9cc7a99b1ebb252"><code>deece8f</code></a>
Apply suggestion from <a
href="https://github.com/henrymercer"><code>@​henrymercer</code></a></li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-19 23:19:16 -04:00
dependabot[bot] d09ec9de25 build(deps): bump the npm-deps group in /src/frontend with 9 updates (#1349)
Bumps the npm-deps group in /src/frontend with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [react](https://github.com/react/react/tree/HEAD/packages/react) |
`19.2.8` | `19.3.0` |
|
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)
| `19.2.18` | `19.3.0` |
|
[react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom)
| `19.2.8` | `19.3.0` |
|
[@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom)
| `19.2.7` | `19.3.0` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `26.5.0` | `26.5.1` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.34.0` | `6.35.1` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.67.0` | `0.68.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.82.0` | `1.83.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.2.2` | `8.3.0` |

Updates `react` from 19.2.8 to 19.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/releases">react's
releases</a>.</em></p>
<blockquote>
<h2>19.3.0 (September 9, 2026)</h2>
<p>Below is a list of all new features, APIs, and bug fixes.</p>
<p>Read the <a href="https://react.dev/blog/2026/09/09/react-19-3">React
19.3 release post</a> for more information.</p>
<h2>New React Features</h2>
<ul>
<li><code>&lt;ViewTransition /&gt;</code>: Adds <code>&lt;ViewTransition
/&gt;</code> and <code>addTransitionType</code> APIs to power View
Transition animations in React (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/gaearon"><code>@​gaearon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/31975">#31975</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31987">#31987</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31996">#31996</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31999">#31999</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32001">#32001</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32002">#32002</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32028">#32028</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32029">#32029</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32031">#32031</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32034">#32034</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32038">#32038</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32041">#32041</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32050">#32050</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32090">#32090</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32105">#32105</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32254">#32254</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32379">#32379</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32422">#32422</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32462">#32462</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32540">#32540</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32545">#32545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32585">#32585</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32599">#32599</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32611">#32611</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32612">#32612</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32617">#32617</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32651">#32651</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32653">#32653</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32656">#32656</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32664">#32664</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32699">#32699</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32723">#32723</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32734">#32734</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32751">#32751</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32752">#32752</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32760">#32760</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32761">#32761</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32764">#32764</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32772">#32772</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32790">#32790</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32819">#32819</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32820">#32820</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32822">#32822</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32833">#32833</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32849">#32849</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33094">#33094</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33191">#33191</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33200">#33200</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33206">#33206</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33293">#33293</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33330">#33330</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33331">#33331</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33332">#33332</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33357">#33357</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33362">#33362</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33433">#33433</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33576">#33576</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34374">#34374</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34450">#34450</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34481">#34481</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34500">#34500</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34502">#34502</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34510">#34510</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34511">#34511</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34539">#34539</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35567">#35567</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35564">#35564</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35485">#35485</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35380">#35380</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35063">#35063</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35060">#35060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34676">#34676</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36917">#36917</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35337">#35337</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35520">#35520</a>)</li>
<li>Fragment Refs: Add Refs to <code>&lt;Fragment /&gt;</code> to
support composable platform behavior (<a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>, <a
href="https://github.com/Dhakshin2007"><code>@​Dhakshin2007</code></a>,
<a href="https://github.com/chirokas"><code>@​chirokas</code></a>, <a
href="https://github.com/teamleaderleo"><code>@​teamleaderleo</code></a>,
<a
href="https://github.com/fallintoplace"><code>@​fallintoplace</code></a>:
<a
href="https://redirect.github.com/facebook/react/pull/32465">#32465</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32613">#32613</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32619">#32619</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32654">#32654</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32660">#32660</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32682">#32682</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32722">#32722</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32813">#32813</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32814">#32814</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33056">#33056</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33058">#33058</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33093">#33093</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34069">#34069</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34103">#34103</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34544">#34544</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34545">#34545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37062">#37062</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37061">#37061</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37060">#37060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36047">#36047</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36010">#36010</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35642">#35642</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35641">#35641</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35637">#35637</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35630">#35630</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34935">#34935</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37457">#37457</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37408">#37408</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37326">#37326</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37251">#37251</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37171">#37171</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37169">#37169</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37168">#37168</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37167">#37167</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37166">#37166</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37165">#37165</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37164">#37164</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37163">#37163</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37162">#37162</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37161">#37161</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37160">#37160</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37125">#37125</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37063">#37063</a>)</li>
</ul>
<h2>New React DOM Features</h2>
<ul>
<li><code>browser()</code>: a new <code>react-dom</code> API that
returns a usable which errors during server rendering and resolves in
the browser. <code>use(browser())</code> inside a
<code>&lt;Suspense&gt;</code> boundary marks a subtree as browser-only
without reporting a recoverable error (<a
href="https://github.com/gnoff"><code>@​gnoff</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37143">#37143</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37241">#37241</a>)
<ul>
<li>Added an <code>onBrowserBailout</code> option to the
<code>react-dom/server</code> APIs to observe when a subtree defers to
the browser (<a href="https://github.com/gnoff"><code>@​gnoff</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/37193">#37193</a>)</li>
</ul>
</li>
</ul>
<h2>Notable changes</h2>
<ul>
<li>Enable Trusted Types API integration (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35816">#35816</a>)</li>
<li>Transitions now render independently instead of being entangled into
a single render, so a slow transition no longer holds up unrelated ones
(<a href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
<li>Added a DEV-only warning when a component appears to have been
unblocked by calling <code>use()</code> conditionally (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
</ul>
<h2>All Changes</h2>
<h3>React</h3>
<ul>
<li>Fast Refresh Fixes
<ul>
<li>Fix Fast Refresh to find and remount edits to components wrapped
behind <code>lazy()</code> (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36965">#36965</a>)</li>
<li>Fix Fast Refresh so edits to a <code>memo()</code> comparison
function take effect (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36964">#36964</a>)</li>
<li>Fix Fast Refresh crash when an edit changes the kind of a
component's type (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36963">#36963</a>)</li>
<li>Unify hot reload type resolution for Fast Refresh (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36962">#36962</a>)</li>
<li>Fix Fast Refresh to remount correctly when an edit changes the
component kind (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36950">#36950</a>)</li>
<li>Double invoke effects in StrictMode after Fast Refresh (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35962">#35962</a>)</li>
</ul>
</li>
<li>Performance Track Fixes
<ul>
<li>Prevent crash when accessing <code>$$typeof</code> in Performance
Tracks (<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35679">#35679</a>)</li>
<li>Handle non-string function names in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35659">#35659</a>)</li>
<li>Use minus (<code>-</code>) instead of en dash for removed props in
Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35649">#35649</a>)</li>
<li>Handle arrays with bigints in deep objects in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35648">#35648</a>)</li>
<li>Don't enumerate typed array props in Performance Tracks in DEV (<a
href="https://github.com/UditDewan"><code>@​UditDewan</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36913">#36913</a>)</li>
<li>Bail out of diffing wide objects and arrays in Performance Tracks
(<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34742">#34742</a>)</li>
<li>Clear potentially large performance measures in DEV (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34803">#34803</a>)</li>
<li>Fix missing else branch for renders with no props change in
Performance Tracks (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34837">#34837</a>)</li>
</ul>
</li>
<li>Activity Fixes
<ul>
<li>Fix <code>useSyncExternalStore</code> missing store mutations that
happened while an Activity tree was hidden (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36947">#36947</a>)</li>
<li>Hide portal contents when an Activity is hidden (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35091">#35091</a>)</li>
<li>Prevent metadata hoisting in hidden <code>&lt;Activity&gt;</code>
trees (<a
href="https://github.com/ronnakamoto"><code>@​ronnakamoto</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34983">#34983</a>)</li>
<li>Prevent errors thrown inside a hidden Activity from escaping to the
visible UI (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35074">#35074</a>)</li>
<li>Don't unhide a node if a direct parent Offscreen is still hidden (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34821">#34821</a>)</li>
<li>Don't show internal <code>&lt;Offscreen&gt;</code> component in
error messages (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35763">#35763</a>)</li>
</ul>
</li>
<li>Warn in DEV when a component appears to have been unblocked by a
conditional <code>use()</code> (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
<li>Render transitions independently instead of entangling them into a
single render (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/blob/main/CHANGELOG.md">react's
changelog</a>.</em></p>
<blockquote>
<h2>19.3.0 (September 9, 2026)</h2>
<h3>New React Features</h3>
<ul>
<li><code>&lt;ViewTransition /&gt;</code>: Adds <code>&lt;ViewTransition
/&gt;</code> and <code>addTransitionType</code> APIs to power View
Transition animations in React (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/gaearon"><code>@​gaearon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/31975">#31975</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31987">#31987</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31996">#31996</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31999">#31999</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32001">#32001</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32002">#32002</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32028">#32028</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32029">#32029</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32031">#32031</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32034">#32034</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32038">#32038</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32041">#32041</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32050">#32050</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32090">#32090</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32105">#32105</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32254">#32254</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32379">#32379</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32422">#32422</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32462">#32462</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32540">#32540</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32545">#32545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32585">#32585</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32599">#32599</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32611">#32611</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32612">#32612</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32617">#32617</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32651">#32651</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32653">#32653</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32656">#32656</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32664">#32664</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32699">#32699</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32723">#32723</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32734">#32734</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32751">#32751</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32752">#32752</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32760">#32760</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32761">#32761</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32764">#32764</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32772">#32772</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32790">#32790</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32819">#32819</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32820">#32820</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32822">#32822</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32833">#32833</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32849">#32849</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33094">#33094</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33191">#33191</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33200">#33200</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33206">#33206</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33293">#33293</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33330">#33330</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33331">#33331</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33332">#33332</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33357">#33357</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33362">#33362</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33433">#33433</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33576">#33576</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34374">#34374</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34450">#34450</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34481">#34481</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34500">#34500</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34502">#34502</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34510">#34510</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34511">#34511</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34539">#34539</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35567">#35567</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35564">#35564</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35485">#35485</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35380">#35380</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35063">#35063</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35060">#35060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34676">#34676</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36917">#36917</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35337">#35337</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35520">#35520</a>)</li>
<li>Fragment Refs: Add Refs to <code>&lt;Fragment /&gt;</code> to
support composable platform behavior (<a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>, <a
href="https://github.com/Dhakshin2007"><code>@​Dhakshin2007</code></a>,
<a href="https://github.com/chirokas"><code>@​chirokas</code></a>, <a
href="https://github.com/teamleaderleo"><code>@​teamleaderleo</code></a>,
<a
href="https://github.com/fallintoplace"><code>@​fallintoplace</code></a>:
<a
href="https://redirect.github.com/facebook/react/pull/32465">#32465</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32613">#32613</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32619">#32619</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32654">#32654</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32660">#32660</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32682">#32682</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32722">#32722</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32813">#32813</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32814">#32814</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33056">#33056</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33058">#33058</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33093">#33093</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34069">#34069</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34103">#34103</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34544">#34544</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34545">#34545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37062">#37062</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37061">#37061</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37060">#37060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36047">#36047</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36010">#36010</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35642">#35642</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35641">#35641</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35637">#35637</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35630">#35630</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34935">#34935</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37457">#37457</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37408">#37408</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37326">#37326</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37251">#37251</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37171">#37171</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37169">#37169</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37168">#37168</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37167">#37167</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37166">#37166</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37165">#37165</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37164">#37164</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37163">#37163</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37162">#37162</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37161">#37161</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37160">#37160</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37125">#37125</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37063">#37063</a>)</li>
</ul>
<h3>New React DOM Features</h3>
<ul>
<li><code>browser()</code>: a new <code>react-dom</code> API that
returns a usable which errors during server rendering and resolves in
the browser. <code>use(browser())</code> inside a
<code>&lt;Suspense&gt;</code> boundary marks a subtree as browser-only
without reporting a recoverable error (<a
href="https://github.com/gnoff"><code>@​gnoff</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37143">#37143</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37241">#37241</a>)
<ul>
<li>Added an <code>onBrowserBailout</code> option to the
<code>react-dom/server</code> APIs to observe when a subtree defers to
the browser (<a href="https://github.com/gnoff"><code>@​gnoff</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/37193">#37193</a>)</li>
</ul>
</li>
</ul>
<h3>Notable changes</h3>
<ul>
<li>Enable Trusted Types API integration (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35816">#35816</a>)</li>
<li>Transitions now render independently instead of being entangled into
a single render, so a slow transition no longer holds up unrelated ones
(<a href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
<li>Added a DEV-only warning when a component appears to have been
unblocked by calling <code>use()</code> conditionally (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
</ul>
<h3>All Changes</h3>
<h4>React</h4>
<ul>
<li>Fast Refresh Fixes
<ul>
<li>Fix Fast Refresh to find and remount edits to components wrapped
behind <code>lazy()</code> (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36965">#36965</a>)</li>
<li>Fix Fast Refresh so edits to a <code>memo()</code> comparison
function take effect (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36964">#36964</a>)</li>
<li>Fix Fast Refresh crash when an edit changes the kind of a
component's type (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36963">#36963</a>)</li>
<li>Unify hot reload type resolution for Fast Refresh (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36962">#36962</a>)</li>
<li>Fix Fast Refresh to remount correctly when an edit changes the
component kind (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36950">#36950</a>)</li>
<li>Double invoke effects in StrictMode after Fast Refresh (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35962">#35962</a>)</li>
</ul>
</li>
<li>Performance Track Fixes
<ul>
<li>Prevent crash when accessing <code>$$typeof</code> in Performance
Tracks (<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35679">#35679</a>)</li>
<li>Handle non-string function names in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35659">#35659</a>)</li>
<li>Use minus (<code>-</code>) instead of en dash for removed props in
Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35649">#35649</a>)</li>
<li>Handle arrays with bigints in deep objects in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35648">#35648</a>)</li>
<li>Don't enumerate typed array props in Performance Tracks in DEV (<a
href="https://github.com/UditDewan"><code>@​UditDewan</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36913">#36913</a>)</li>
<li>Bail out of diffing wide objects and arrays in Performance Tracks
(<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34742">#34742</a>)</li>
<li>Clear potentially large performance measures in DEV (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34803">#34803</a>)</li>
<li>Fix missing else branch for renders with no props change in
Performance Tracks (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34837">#34837</a>)</li>
</ul>
</li>
<li>Activity Fixes
<ul>
<li>Fix <code>useSyncExternalStore</code> missing store mutations that
happened while an Activity tree was hidden (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36947">#36947</a>)</li>
<li>Hide portal contents when an Activity is hidden (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35091">#35091</a>)</li>
<li>Prevent metadata hoisting in hidden <code>&lt;Activity&gt;</code>
trees (<a
href="https://github.com/ronnakamoto"><code>@​ronnakamoto</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34983">#34983</a>)</li>
<li>Prevent errors thrown inside a hidden Activity from escaping to the
visible UI (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35074">#35074</a>)</li>
<li>Don't unhide a node if a direct parent Offscreen is still hidden (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34821">#34821</a>)</li>
<li>Don't show internal <code>&lt;Offscreen&gt;</code> component in
error messages (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35763">#35763</a>)</li>
</ul>
</li>
<li>Warn in DEV when a component appears to have been unblocked by a
conditional <code>use()</code> (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
<li>Render transitions independently instead of entangling them into a
single render (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
<li>Fix hang when updating a dehydrated boundary inside a hidden tree
(<a href="https://github.com/gaearon"><code>@​gaearon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37135">#37135</a>)</li>
<li>Don't reacquire Host Singletons during dev effect validation (<a
href="https://github.com/gnoff"><code>@​gnoff</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37113">#37113</a>)</li>
<li>Only remove properties from Host Singletons on release (<a
href="https://github.com/gnoff"><code>@​gnoff</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37112">#37112</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/react/react/commit/2dc7da790d6388b95b83198ca9b588b2ad5f5c0b"><code>2dc7da7</code></a>
[test] Bump Jest to 30.4 (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/37382">#37382</a>)</li>
<li><a
href="https://github.com/react/react/commit/4f9389423b7319e1f7acc3d158c84a8365462748"><code>4f93894</code></a>
docs: remove stale parentType param from validateChildKeys JSDoc (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36928">#36928</a>)</li>
<li><a
href="https://github.com/react/react/commit/dbc37501ffeaf8fec45af5898caf1c3d64ad10bf"><code>dbc3750</code></a>
Update required references to GitHub repo (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36752">#36752</a>)</li>
<li><a
href="https://github.com/react/react/commit/900ae094d85b11c67d53dd14af50a2bda5db4495"><code>900ae09</code></a>
[flow] Bump flow to v0.317.0 (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36701">#36701</a>)</li>
<li><a
href="https://github.com/react/react/commit/fbb137059e4aacfaab1d36516e9b55050b4a0454"><code>fbb1370</code></a>
[flow] Bump flow to v0.307.1 (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36199">#36199</a>)</li>
<li><a
href="https://github.com/react/react/commit/56922cf751fab6c7ab4c12ddbbd15839959fa255"><code>56922cf</code></a>
[react-native-renderer] Delete Paper (legacy) renderer (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36285">#36285</a>)</li>
<li><a
href="https://github.com/react/react/commit/74568e8627aa43469b74f2972f427a209639d0b6"><code>74568e8</code></a>
[Flight] Transport <code>AggregateErrors.errors</code> (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36156">#36156</a>)</li>
<li><a
href="https://github.com/react/react/commit/e66ef6480ecd19c6885f2c06dec34fec1fdc0a98"><code>e66ef64</code></a>
[tests] remove withoutStack from assertConsole helpers (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/35498">#35498</a>)</li>
<li><a
href="https://github.com/react/react/commit/db71391c5c70dc113560d1c23d0b6548604d827f"><code>db71391</code></a>
[Fiber] Instrument the lazy initializer thenable in all cases (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/35521">#35521</a>)</li>
<li><a
href="https://github.com/react/react/commit/3e1abcc8d7083a13adf4774feb0d67ecbe4a2bc4"><code>3e1abcc</code></a>
[tests] Require exact error messages in assertConsole helpers (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/35497">#35497</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/react/react/commits/v19.3.0/packages/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react` from 19.2.18 to 19.3.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-dom` from 19.2.8 to 19.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/releases">react-dom's
releases</a>.</em></p>
<blockquote>
<h2>19.3.0 (September 9, 2026)</h2>
<p>Below is a list of all new features, APIs, and bug fixes.</p>
<p>Read the <a href="https://react.dev/blog/2026/09/09/react-19-3">React
19.3 release post</a> for more information.</p>
<h2>New React Features</h2>
<ul>
<li><code>&lt;ViewTransition /&gt;</code>: Adds <code>&lt;ViewTransition
/&gt;</code> and <code>addTransitionType</code> APIs to power View
Transition animations in React (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/gaearon"><code>@​gaearon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/31975">#31975</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31987">#31987</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31996">#31996</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31999">#31999</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32001">#32001</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32002">#32002</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32028">#32028</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32029">#32029</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32031">#32031</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32034">#32034</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32038">#32038</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32041">#32041</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32050">#32050</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32090">#32090</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32105">#32105</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32254">#32254</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32379">#32379</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32422">#32422</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32462">#32462</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32540">#32540</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32545">#32545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32585">#32585</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32599">#32599</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32611">#32611</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32612">#32612</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32617">#32617</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32651">#32651</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32653">#32653</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32656">#32656</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32664">#32664</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32699">#32699</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32723">#32723</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32734">#32734</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32751">#32751</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32752">#32752</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32760">#32760</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32761">#32761</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32764">#32764</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32772">#32772</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32790">#32790</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32819">#32819</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32820">#32820</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32822">#32822</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32833">#32833</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32849">#32849</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33094">#33094</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33191">#33191</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33200">#33200</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33206">#33206</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33293">#33293</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33330">#33330</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33331">#33331</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33332">#33332</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33357">#33357</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33362">#33362</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33433">#33433</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33576">#33576</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34374">#34374</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34450">#34450</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34481">#34481</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34500">#34500</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34502">#34502</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34510">#34510</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34511">#34511</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34539">#34539</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35567">#35567</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35564">#35564</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35485">#35485</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35380">#35380</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35063">#35063</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35060">#35060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34676">#34676</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36917">#36917</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35337">#35337</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35520">#35520</a>)</li>
<li>Fragment Refs: Add Refs to <code>&lt;Fragment /&gt;</code> to
support composable platform behavior (<a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>, <a
href="https://github.com/Dhakshin2007"><code>@​Dhakshin2007</code></a>,
<a href="https://github.com/chirokas"><code>@​chirokas</code></a>, <a
href="https://github.com/teamleaderleo"><code>@​teamleaderleo</code></a>,
<a
href="https://github.com/fallintoplace"><code>@​fallintoplace</code></a>:
<a
href="https://redirect.github.com/facebook/react/pull/32465">#32465</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32613">#32613</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32619">#32619</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32654">#32654</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32660">#32660</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32682">#32682</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32722">#32722</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32813">#32813</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32814">#32814</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33056">#33056</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33058">#33058</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33093">#33093</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34069">#34069</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34103">#34103</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34544">#34544</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34545">#34545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37062">#37062</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37061">#37061</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37060">#37060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36047">#36047</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36010">#36010</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35642">#35642</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35641">#35641</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35637">#35637</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35630">#35630</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34935">#34935</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37457">#37457</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37408">#37408</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37326">#37326</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37251">#37251</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37171">#37171</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37169">#37169</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37168">#37168</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37167">#37167</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37166">#37166</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37165">#37165</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37164">#37164</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37163">#37163</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37162">#37162</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37161">#37161</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37160">#37160</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37125">#37125</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37063">#37063</a>)</li>
</ul>
<h2>New React DOM Features</h2>
<ul>
<li><code>browser()</code>: a new <code>react-dom</code> API that
returns a usable which errors during server rendering and resolves in
the browser. <code>use(browser())</code> inside a
<code>&lt;Suspense&gt;</code> boundary marks a subtree as browser-only
without reporting a recoverable error (<a
href="https://github.com/gnoff"><code>@​gnoff</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37143">#37143</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37241">#37241</a>)
<ul>
<li>Added an <code>onBrowserBailout</code> option to the
<code>react-dom/server</code> APIs to observe when a subtree defers to
the browser (<a href="https://github.com/gnoff"><code>@​gnoff</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/37193">#37193</a>)</li>
</ul>
</li>
</ul>
<h2>Notable changes</h2>
<ul>
<li>Enable Trusted Types API integration (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35816">#35816</a>)</li>
<li>Transitions now render independently instead of being entangled into
a single render, so a slow transition no longer holds up unrelated ones
(<a href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
<li>Added a DEV-only warning when a component appears to have been
unblocked by calling <code>use()</code> conditionally (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
</ul>
<h2>All Changes</h2>
<h3>React</h3>
<ul>
<li>Fast Refresh Fixes
<ul>
<li>Fix Fast Refresh to find and remount edits to components wrapped
behind <code>lazy()</code> (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36965">#36965</a>)</li>
<li>Fix Fast Refresh so edits to a <code>memo()</code> comparison
function take effect (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36964">#36964</a>)</li>
<li>Fix Fast Refresh crash when an edit changes the kind of a
component's type (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36963">#36963</a>)</li>
<li>Unify hot reload type resolution for Fast Refresh (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36962">#36962</a>)</li>
<li>Fix Fast Refresh to remount correctly when an edit changes the
component kind (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36950">#36950</a>)</li>
<li>Double invoke effects in StrictMode after Fast Refresh (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35962">#35962</a>)</li>
</ul>
</li>
<li>Performance Track Fixes
<ul>
<li>Prevent crash when accessing <code>$$typeof</code> in Performance
Tracks (<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35679">#35679</a>)</li>
<li>Handle non-string function names in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35659">#35659</a>)</li>
<li>Use minus (<code>-</code>) instead of en dash for removed props in
Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35649">#35649</a>)</li>
<li>Handle arrays with bigints in deep objects in Performance Tracks (<a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35648">#35648</a>)</li>
<li>Don't enumerate typed array props in Performance Tracks in DEV (<a
href="https://github.com/UditDewan"><code>@​UditDewan</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36913">#36913</a>)</li>
<li>Bail out of diffing wide objects and arrays in Performance Tracks
(<a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34742">#34742</a>)</li>
<li>Clear potentially large performance measures in DEV (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34803">#34803</a>)</li>
<li>Fix missing else branch for renders with no props change in
Performance Tracks (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34837">#34837</a>)</li>
</ul>
</li>
<li>Activity Fixes
<ul>
<li>Fix <code>useSyncExternalStore</code> missing store mutations that
happened while an Activity tree was hidden (<a
href="https://github.com/sophiebits"><code>@​sophiebits</code></a> <a
href="https://redirect.github.com/facebook/react/pull/36947">#36947</a>)</li>
<li>Hide portal contents when an Activity is hidden (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35091">#35091</a>)</li>
<li>Prevent metadata hoisting in hidden <code>&lt;Activity&gt;</code>
trees (<a
href="https://github.com/ronnakamoto"><code>@​ronnakamoto</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34983">#34983</a>)</li>
<li>Prevent errors thrown inside a hidden Activity from escaping to the
visible UI (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/35074">#35074</a>)</li>
<li>Don't unhide a node if a direct parent Offscreen is still hidden (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a> <a
href="https://redirect.github.com/facebook/react/pull/34821">#34821</a>)</li>
<li>Don't show internal <code>&lt;Offscreen&gt;</code> component in
error messages (<a
href="https://github.com/rickhanlonii"><code>@​rickhanlonii</code></a>
<a
href="https://redirect.github.com/facebook/react/pull/35763">#35763</a>)</li>
</ul>
</li>
<li>Warn in DEV when a component appears to have been unblocked by a
conditional <code>use()</code> (<a
href="https://github.com/hoxyq"><code>@​hoxyq</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/37104">#37104</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37203">#37203</a>,
<a
href="https://redirect.github.com/facebook/react/pull/37491">#37491</a>)</li>
<li>Render transitions independently instead of entangling them into a
single render (<a
href="https://github.com/acdlite"><code>@​acdlite</code></a> <a
href="https://redirect.github.com/facebook/react/pull/37290">#37290</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/blob/main/CHANGELOG.md">react-dom's
changelog</a>.</em></p>
<blockquote>
<h2>19.3.0 (September 9, 2026)</h2>
<h3>New React Features</h3>
<ul>
<li><code>&lt;ViewTransition /&gt;</code>: Adds <code>&lt;ViewTransition
/&gt;</code> and <code>addTransitionType</code> APIs to power View
Transition animations in React (<a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/gaearon"><code>@​gaearon</code></a>: <a
href="https://redirect.github.com/facebook/react/pull/31975">#31975</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31987">#31987</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31996">#31996</a>,
<a
href="https://redirect.github.com/facebook/react/pull/31999">#31999</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32001">#32001</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32002">#32002</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32028">#32028</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32029">#32029</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32031">#32031</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32034">#32034</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32038">#32038</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32041">#32041</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32050">#32050</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32090">#32090</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32105">#32105</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32254">#32254</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32379">#32379</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32422">#32422</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32462">#32462</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32540">#32540</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32545">#32545</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32585">#32585</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32599">#32599</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32611">#32611</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32612">#32612</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32617">#32617</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32651">#32651</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32653">#32653</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32656">#32656</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32664">#32664</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32699">#32699</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32723">#32723</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32734">#32734</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32751">#32751</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32752">#32752</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32760">#32760</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32761">#32761</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32764">#32764</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32772">#32772</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32790">#32790</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32819">#32819</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32820">#32820</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32822">#32822</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32833">#32833</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32849">#32849</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33094">#33094</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33191">#33191</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33200">#33200</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33206">#33206</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33293">#33293</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33330">#33330</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33331">#33331</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33332">#33332</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33357">#33357</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33362">#33362</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33433">#33433</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33576">#33576</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34374">#34374</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34450">#34450</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34481">#34481</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34500">#34500</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34502">#34502</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34510">#34510</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34511">#34511</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34539">#34539</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35567">#35567</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35564">#35564</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35485">#35485</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35380">#35380</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35063">#35063</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35060">#35060</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34676">#34676</a>,
<a
href="https://redirect.github.com/facebook/react/pull/36917">#36917</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35337">#35337</a>,
<a
href="https://redirect.github.com/facebook/react/pull/35520">#35520</a>)</li>
<li>Fragment Refs: Add Refs to <code>&lt;Fragment /&gt;</code> to
support composable platform behavior (<a
href="https://github.com/jackpope"><code>@​jackpope</code></a>, <a
href="https://github.com/sebmarkbage"><code>@​sebmarkbage</code></a>, <a
href="https://github.com/eps1lon"><code>@​eps1lon</code></a>, <a
href="https://github.com/Dhakshin2007"><code>@​Dhakshin2007</code></a>,
<a href="https://github.com/chirokas"><code>@​chirokas</code></a>, <a
href="https://github.com/teamleaderleo"><code>@​teamleaderleo</code></a>,
<a
href="https://github.com/fallintoplace"><code>@​fallintoplace</code></a>:
<a
href="https://redirect.github.com/facebook/react/pull/32465">#32465</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32613">#32613</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32619">#32619</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32654">#32654</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32660">#32660</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32682">#32682</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32722">#32722</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32813">#32813</a>,
<a
href="https://redirect.github.com/facebook/react/pull/32814">#32814</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33056">#33056</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33058">#33058</a>,
<a
href="https://redirect.github.com/facebook/react/pull/33093">#33093</a>,
<a
href="https://redirect.github.com/facebook/react/pull/34069">#34069</a>,
<a href="https://redirect...

_Description has been truncated_

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-19 23:19:07 -04:00
dependabot[bot] 83f86242b4 build(deps): bump the docker-base-image-digests group with 2 updates (#1348)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps the docker-base-image-digests group with 2 updates: node and
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `node` from `50c8e8c` to `ebfe2f9`

Updates `astral-sh/uv` from 0.12.13 to 0.12.16
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.12.16</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-17.</p>
<h3>Python</h3>
<ul>
<li>Add Pyodide 314.0.7, 0.29.5, and 0.27.8 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21741">#21741</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Verify downloaded wheels and source distributions against hashes
supplied by package indexes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21562">#21562</a>)</li>
<li>Allow <code>build-constraint-dependencies</code> entries to include
hashes for verifying downloaded build dependencies (<a
href="https://redirect.github.com/astral-sh/uv/pull/21467">#21467</a>)</li>
<li>Honor Darwin <code>platform_release</code> markers in
<code>required-environments</code> using macOS wheel deployment targets
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21766">#21766</a>)</li>
<li>Reject unsupported Git URL schemes while parsing lockfiles instead
of panicking during frozen exports (<a
href="https://redirect.github.com/astral-sh/uv/pull/21779">#21779</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Support <code>lock-without-metadata</code> across all dependency
types while retaining <code>package.metadata</code> for remote URL
dependencies to enable offline validation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21163">#21163</a>)</li>
<li>Honor configured and command-line index settings, including
credentials, in <code>uv upgrade</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21776">#21776</a>)</li>
<li>Allow <code>uv check</code> to run in projects that are not managed
by uv and outside workspaces (<a
href="https://redirect.github.com/astral-sh/uv/pull/21777">#21777</a>)</li>
<li>Respect <code>--python</code> and <code>UV_PYTHON</code> when
selecting the Python version for <code>uv check</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21744">#21744</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Redact Azure shared access signatures from displayed and logged URLs
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21755">#21755</a>)</li>
<li>Check archive sizes from <code>pylock.toml</code> before reusing
cached distributions (<a
href="https://redirect.github.com/astral-sh/uv/pull/21609">#21609</a>)</li>
<li>Keep user-authored local dependency paths relative in lockfiles when
backend metadata reports absolute paths (<a
href="https://redirect.github.com/astral-sh/uv/pull/20631">#20631</a>)</li>
<li>Use the bundled <code>uv_build</code> backend only when its version
matches active version pins (<a
href="https://redirect.github.com/astral-sh/uv/pull/21742">#21742</a>)</li>
<li>Handle malformed index URLs without panicking when credentials are
configured (<a
href="https://redirect.github.com/astral-sh/uv/pull/21784">#21784</a>)</li>
<li>Report a configuration error instead of panicking for proxy URLs
without a host (<a
href="https://redirect.github.com/astral-sh/uv/pull/21781">#21781</a>)</li>
<li>Return a credential-redacted error instead of panicking when a URL
cannot be converted to a path (<a
href="https://redirect.github.com/astral-sh/uv/pull/21783">#21783</a>)</li>
</ul>
<h2>Install uv 0.12.16</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.12.16/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/uv/releases/download/0.12.16/uv-installer.ps1
| iex&quot;
</code></pre>
<h2>Download uv 0.12.16</h2>
<p>|  File  | Platform | Checksum |</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.16</h2>
<p>Released on 2026-09-17.</p>
<h3>Python</h3>
<ul>
<li>Add Pyodide 314.0.7, 0.29.5, and 0.27.8 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21741">#21741</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Verify downloaded wheels and source distributions against hashes
supplied by package indexes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21562">#21562</a>)</li>
<li>Allow <code>build-constraint-dependencies</code> entries to include
hashes for verifying downloaded build dependencies (<a
href="https://redirect.github.com/astral-sh/uv/pull/21467">#21467</a>)</li>
<li>Honor Darwin <code>platform_release</code> markers in
<code>required-environments</code> using macOS wheel deployment targets
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21766">#21766</a>)</li>
<li>Reject unsupported Git URL schemes while parsing lockfiles instead
of panicking during frozen exports (<a
href="https://redirect.github.com/astral-sh/uv/pull/21779">#21779</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Support <code>lock-without-metadata</code> across all dependency
types while retaining <code>package.metadata</code> for remote URL
dependencies to enable offline validation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21163">#21163</a>)</li>
<li>Honor configured and command-line index settings, including
credentials, in <code>uv upgrade</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21776">#21776</a>)</li>
<li>Allow <code>uv check</code> to run in projects that are not managed
by uv and outside workspaces (<a
href="https://redirect.github.com/astral-sh/uv/pull/21777">#21777</a>)</li>
<li>Respect <code>--python</code> and <code>UV_PYTHON</code> when
selecting the Python version for <code>uv check</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21744">#21744</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Redact Azure shared access signatures from displayed and logged URLs
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21755">#21755</a>)</li>
<li>Check archive sizes from <code>pylock.toml</code> before reusing
cached distributions (<a
href="https://redirect.github.com/astral-sh/uv/pull/21609">#21609</a>)</li>
<li>Keep user-authored local dependency paths relative in lockfiles when
backend metadata reports absolute paths (<a
href="https://redirect.github.com/astral-sh/uv/pull/20631">#20631</a>)</li>
<li>Use the bundled <code>uv_build</code> backend only when its version
matches active version pins (<a
href="https://redirect.github.com/astral-sh/uv/pull/21742">#21742</a>)</li>
<li>Handle malformed index URLs without panicking when credentials are
configured (<a
href="https://redirect.github.com/astral-sh/uv/pull/21784">#21784</a>)</li>
<li>Report a configuration error instead of panicking for proxy URLs
without a host (<a
href="https://redirect.github.com/astral-sh/uv/pull/21781">#21781</a>)</li>
<li>Return a credential-redacted error instead of panicking when a URL
cannot be converted to a path (<a
href="https://redirect.github.com/astral-sh/uv/pull/21783">#21783</a>)</li>
</ul>
<h2>0.12.15</h2>
<p>Released on 2026-09-15.</p>
<h3>Performance</h3>
<ul>
<li>Speed up cold-cache resolution and HTTP cache revalidation by
batching cache writes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21675">#21675</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix regressions in <code>0.12.14</code> when installing to symlinked
destinations or using <code>uv pip install --target .</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21699">#21699</a>)</li>
</ul>
<h2>0.12.14</h2>
<p>Released on 2026-09-15.</p>
<h3>Enhancements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/761ff1379b3b79f61fc8d421dfe4fe064834e084"><code>761ff13</code></a>
Bump version to 0.12.16 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21809">#21809</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/a2f820ad0cebb7118f7686be3619d48df5121f6e"><code>a2f820a</code></a>
Assign release pull requests to the workflow initiator (<a
href="https://redirect.github.com/astral-sh/uv/issues/21808">#21808</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6dffe7e03898409c04e2f46436bffa60abbae465"><code>6dffe7e</code></a>
Ignore <code>UV_NATIVE_TLS</code> when <code>UV_SYSTEM_CERTS</code> is
set (<a
href="https://redirect.github.com/astral-sh/uv/issues/21805">#21805</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/7bc36767ae3ea0d45e3cc6f219765fdec2992a33"><code>7bc3676</code></a>
Avoid warning when both <code>native-tls</code> and
<code>system-certs</code> are configured (<a
href="https://redirect.github.com/astral-sh/uv/issues/21806">#21806</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/07b838a33179967b87d513825b02504a75b21b3a"><code>07b838a</code></a>
Avoid warning when both <code>UV_NATIVE_TLS</code> and
<code>UV_SYSTEM_CERTS</code> are set (<a
href="https://redirect.github.com/astral-sh/uv/issues/21788">#21788</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/5d64ede21e9e835e59ecd85329ebefd43faa8211"><code>5d64ede</code></a>
Remove Hash API (<a
href="https://redirect.github.com/astral-sh/uv/issues/21786">#21786</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/9ddc4308551335e9c2ab6571ea0cf529eccf3e76"><code>9ddc430</code></a>
Move shared thread initialization into uv-threads (<a
href="https://redirect.github.com/astral-sh/uv/issues/21746">#21746</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/ef1e0689b4612796d7781ebeae7866028c6c9e82"><code>ef1e068</code></a>
Make Git stamping opt-in for development builds (<a
href="https://redirect.github.com/astral-sh/uv/issues/21750">#21750</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6ce09770cec30b30cdc66c3595517dce2b112562"><code>6ce0977</code></a>
Avoid panics for non-base index URLs (<a
href="https://redirect.github.com/astral-sh/uv/issues/21784">#21784</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/47f19ec154f325ade7d6045c4e785531c24635f7"><code>47f19ec</code></a>
Return an error for failed VerbatimUrl path conversions (<a
href="https://redirect.github.com/astral-sh/uv/issues/21783">#21783</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.12.13...0.12.16">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-19 23:18:59 -04:00
splitsec2andInfiniteAvenger 44f4e13cce refactor: extract the per-source release search out of /api/releases (#1355)
The `/api/releases` route carries an inner `_search_source_releases`
helper that builds the search plan for one source, logs the planned
query type, runs the search and turns
`SourceUnavailableError`/operational errors into an error message
instead of raising. Anything outside the route that wants to search one
source with exactly those semantics has to go through Flask today.

This moves that helper into `shelfmark/core/release_search.py` as
`search_source_releases()` and has the route delegate to it. Behaviour
is unchanged: same plan construction (including the caller's `user_id`,
so per-user default languages still apply), same logging, same
error-to-message handling.

It is the refactor half of #1047 by @InfiniteAvenger, split out on its
own as you asked for other PRs (#1318). Their authorship is preserved on
the commit; I rebased it onto current `main` and added tests.

## Verification

- `tests/core/test_release_search.py`: unknown source → `"Unknown
source: …"`, `SourceUnavailableError` and operational errors →
`"<source>: <error>"`, success path forwards `expand_search` /
`content_type` and returns the source instance, the plan receives
languages / manual query / indexers / `user_id`. (These tests are
type-annotated; happy to strip the annotations if you prefer the suite's
bare style.)
- Full suite, ruff, ruff format, basedpyright, vulture green; the
existing `/api/releases` route tests are unchanged and pass.

Co-authored-by: InfiniteAvenger <calebewest02@gmail.com>
2026-09-19 23:16:53 -04:00
Marcelo Rodrigo b7002a6eca feat: Add TorBox client support and settings integration (#1342)
Add **TorBox** as a torrent download client for Prowlarr releases.

Users can select `TorBox` in the download client settings, configure it
with the new `TORBOX_API_KEY` environment variable, and verify their
credentials with the connection test button.

The integration supports both magnet links and `.torrent` files. It
tracks the torrent lifecycle through TorBox, downloads supported book
and audiobook files from the TorBox CDN, preserves safe nested file
paths, and cleans up remote and local download state.

Important: Shared HTTP download logs omit full download URLs and
URL-bearing exception text to avoid exposing credentials, following best
practices. This applies to all clients that use the shared
`download_url()` path; URLs remain available to the HTTP operations
themselves.

---
There is already related work in progress in #1173, which includes both
torrent and direct-download support for TorBox.

This PR is not intended to replace or compete with that contribution. It
offers the tested torrent client functionality as a smaller, focused
change that can make TorBox available to the community sooner. The
direct-download integration proposed in #1173 remains valuable and could
be reviewed or introduced separately.

Automated tests cover configuration, connection validation, magnet and
torrent-file submission, API errors, status and progress handling, file
retrieval, path traversal protection, cancellation, cleanup, and
sensitive URL redaction.

I also validated the complete flow locally with several magnet links and
`.torrent` downloads. TorBox processed the torrents and Shelfmark
downloaded the resulting files as expected.

AI was used to help with the implementation, with human validation. This
PR and long description? Took me some good minutes at night after work,
but gives me joy to open this PR to share with the community this
improvement.
2026-09-19 23:15:57 -04:00
Paul Rimmer aafce2be1d Added the ability to sort direct search results by Most downloads (#1351)
Now that we know about the AA Downloads stats for search results
(#1336), this PR allows sorting them locally by "Most downloads" without
doing another AA search. Not needing to do an AA search for this is
faster than the other sorts which do new AA searches asking for their
results to be sorted a certain way. Also added the "Settings->Search
Mode->Default Sort Order->Most downloads" option. Universal downloads do
not allow for results sorting so I did not include this feature there.

NOTE: While adding this feature I noticed that shelfmark only looks at
the first page of AA search results. So switching between different sort
orders may result in different sets of results with the same search
term.

Here's a couple of pics showing the new sort option:

<img width="1186" height="759"
alt="search-mode-sort-order-most-downloads"
src="https://github.com/user-attachments/assets/c43fe2e7-84ba-48cd-a850-383f1af0d28f"
/>

<img width="1172" height="828"
alt="direct-search-results-most-downloads"
src="https://github.com/user-attachments/assets/4e240180-6a9d-4ce1-ab86-006b286570dd"
/>

Coded with llama.cpp, opencode and 🤖
2026-09-19 23:12:36 -04:00
dependabot[bot] cdd001bdd9 build(deps): bump python-socketio from 5.16.4 to 5.17.0 in the python-deps group (#1347)
Bumps the python-deps group with 1 update:
[python-socketio](https://github.com/sponsors/miguelgrinberg).

Updates `python-socketio` from 5.16.4 to 5.17.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/sponsors/miguelgrinberg/commits">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python-socketio&package-manager=uv&previous-version=5.16.4&new-version=5.17.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-18 00:14:55 -04:00
CaliBrain e5dd34ae0e fix: unbreak main and follow up on the Blackhole handoff review (#1346)
DownloadHistoryService.record_download and updated the single production
caller, but not the eleven in the test suite, leaving main red with 32
failures. Pass None, which is what the pre-#1336 behaviour recorded.

For the Blackhole handoff (#1345): add_download publishes the torrent
before the cancel check runs, and BlackholeClient.remove() is a no-op,
so
the watcher picks the file up regardless. Reporting a bare "Cancelled"
hid
that from the user. Name the completed handoff in the cancellation
message
instead, drop the _handle_cancelled_download call whose usenet branch
cannot apply to a handoff-only client, and record why the orchestrator
no
longer verifies HandoffResult.path.

Finally, make tests/direct_download a package: test_libgen_extract.py
imports tests.libgen.sample_html across test directories, so without an
__init__.py pytest named its modules by bare basename and a same-named
module elsewhere would collide.
2026-09-17 16:27:53 -04:00
dependabot[bot] 38a429acc8 build(deps): bump the python-deps group across 1 directory with 5 updates (#1344)
Bumps the python-deps group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [tqdm](https://github.com/tqdm/tqdm) | `4.70.0` | `4.70.1` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.53.7` | `4.54.5` |
| [basedpyright](https://github.com/detachhead/basedpyright) | `1.40.0`
| `1.40.1` |
| [prek](https://github.com/j178/prek) | `0.5.2` | `0.5.3` |
| [ruff](https://github.com/astral-sh/ruff) | `0.16.6` | `0.16.7` |


Updates `tqdm` from 4.70.0 to 4.70.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.70.1 stable</h2>
<ul>
<li><code>contrib.concurrent</code>: fix no-len iterables (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1830">#1830</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1828">#1828</a>)</li>
<li>tests: major overhaul (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1819">#1819</a>)</li>
<li>update AI policy in PR template</li>
<li>misc lint &amp; tidy</li>
<li>CI: bump workflow actions &amp; pre-commit hooks</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/9cf5a12b1f955468a17f0ba3c59092b23e4258ac"><code>9cf5a12</code></a>
Merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1830">#1830</a> from
eaubin/master</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/24b9e1e08a097f1c30f2d235b63f9eb25ba47974"><code>24b9e1e</code></a>
misc tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/2a9e4e82ddba07c5dd6d126e23a4745b76ea49c8"><code>2a9e4e8</code></a>
contrib.concurrent: fix no-len iterables</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/8d6ff8de5a9066de77d0a9df3e80a022a3dcf146"><code>8d6ff8d</code></a>
Merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1819">#1819</a> from
tqdm/devel</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/bed379609c2c8300671c784c8f85a185c8cf6fb3"><code>bed3796</code></a>
tests: major overhaul</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/4d3d3194d5467e0701bc0f4b836a735273ef0868"><code>4d3d319</code></a>
AI policy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/5dcb022b55553b60ed2131b64aa5bf1e65470df1"><code>5dcb022</code></a>
minor syntax update</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/309effe4244bf45427c5add7f1bcf33f98a7b421"><code>309effe</code></a>
tests: pre-commit coverage</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/604193aa03b5f5c0ad5f3d441951f0fbb515f1e4"><code>604193a</code></a>
tests: slight tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/17f1cac07c89943eb0e6082875b3821205308d4f"><code>17f1cac</code></a>
CI: bump workflow actions</li>
<li>See full diff in <a
href="https://github.com/tqdm/tqdm/compare/v4.70.0...v4.70.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.53.7 to 4.54.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.54.5 - MCP Server: Patch 14</h2>
<h2>MCP Server: Patch 14</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/753846cca13b6ead76603781b09f725b3236ae79">Update
the MCP Server</a>
--&gt; Going for a top tool score in Glama.</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fda62a2b83b9de176342f1c21c5f72032ffd4628">Update
the MCP Server ReadMe</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b6cd1e7c787cbe2c580e624e3576112d0a0de959">Refresh
optional Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 14 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4501">seleniumbase/SeleniumBase#4501</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.4...v4.54.5">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.4...v4.54.5</a></p>
<h2>4.54.4 - MCP Server: Patch 13</h2>
<h2>MCP Server: Patch 13</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ec41b905a0202e13e9ed0b2f767cd755ea0f891c">Update
CDP Mode (add timeout to a few methods)</a>
--&gt; (One of the ReadMe files should've been committed in the next
commit with a different message)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/eaef20040fe624f2b51e369e1ea8bf5c34bb4d9c">Update
the MCP Server</a>
--&gt; (The MCP ReadMe was updated in the previous commit with the wrong
commit message)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 13 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4500">seleniumbase/SeleniumBase#4500</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.3...v4.54.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.3...v4.54.4</a></p>
<h2>4.54.3 - MCP Server: Patch 12</h2>
<h2>MCP Server: Patch 12</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0d04ec82f7b2fa22bd84a67ad07a119c08a62d06">Update
the MCP Server</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f4a86268b1177044e0a4d03348f5fab76838b96b">Update
the MCP Server ReadMe</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 12 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4499">seleniumbase/SeleniumBase#4499</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.2...v4.54.3">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.2...v4.54.3</a></p>
<h2>4.54.2 - MCP Server: Patch 11</h2>
<h2>MCP Server: Patch 11</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7ea1bbfdae22951c3914a902c46a8520253eaf05">Update
CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1aa89a962424c6f3b930449844665a3fa2628d55">Update
the MCP Server</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 11 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4498">seleniumbase/SeleniumBase#4498</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.54.1...v4.54.2">https://github.com/seleniumbase/SeleniumBase/compare/v4.54.1...v4.54.2</a></p>
<h2>4.54.1 - MCP Server: Patch 10</h2>
<h2>MCP Server: Patch 10</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3de06e5e22a2f6fe629f47bf5859bc74eebcae48"><code>3de06e5</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4501">#4501</a>
from seleniumbase/mcp-server-patch-14</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4c0aaa7ca4fae594cc2826d3bdbb08cb91ea8ab3"><code>4c0aaa7</code></a>
Version 4.54.5</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b6cd1e7c787cbe2c580e624e3576112d0a0de959"><code>b6cd1e7</code></a>
Refresh optional Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/37cffca4f6333d87a9f86a3c1322922ddec85d0b"><code>37cffca</code></a>
Update MCP Server versioning</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fda62a2b83b9de176342f1c21c5f72032ffd4628"><code>fda62a2</code></a>
Update the MCP Server ReadMe</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/753846cca13b6ead76603781b09f725b3236ae79"><code>753846c</code></a>
Update the MCP Server</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/82e3b51cc6941649dda4eed08d7b3efc0eac734a"><code>82e3b51</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4500">#4500</a>
from seleniumbase/mcp-server-patch-13</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bc14832f52674fdf9ee574d87bd7b6fed6ae2f8e"><code>bc14832</code></a>
Version 4.54.4</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8945f2d745770ca06f316e990cd971e76476a1d1"><code>8945f2d</code></a>
Refresh MCP Server versioning</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/eaef20040fe624f2b51e369e1ea8bf5c34bb4d9c"><code>eaef200</code></a>
Update the MCP Server</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.53.7...v4.54.5">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.40.0 to 1.40.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/detachhead/basedpyright/releases">basedpyright's
releases</a>.</em></p>
<blockquote>
<h2>v1.40.1 (pyright 1.1.414)</h2>
<h2>What's Changed</h2>
<ul>
<li>Merge 1.1.414 by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1883">DetachHead/basedpyright#1883</a></li>
<li>fix multi-line display of indented lines in builtin docstrings by <a
href="https://github.com/tommyming"><code>@​tommyming</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1882">DetachHead/basedpyright#1882</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/DetachHead/basedpyright/compare/v1.40.0...v1.40.1">https://github.com/DetachHead/basedpyright/compare/v1.40.0...v1.40.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/e7fca69a08abb7cb28fc6bc5e30e24a387066694"><code>e7fca69</code></a>
1.40.1</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f7b6ad01edff0b53cd523a176c99ba62bf44156e"><code>f7b6ad0</code></a>
add checks when there are multiline indents for doc strings, update (<a
href="https://redirect.github.com/detachhead/basedpyright/issues/1882">#1882</a>)</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/1bc4879cb2a1cffea9ec6009eaa290b301ba4414"><code>1bc4879</code></a>
fix broken docs links</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/845bfe14f2862b3747c8146ebd53bef7644368e8"><code>845bfe1</code></a>
move and baseline basedpyright errors in new build scripts from
upstream</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/a9189ef5e15182e0627dd5a0f28fd2cede4f2bbc"><code>a9189ef</code></a>
prettier fix</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/756bfaa06709cd32c100a3fe3d15156ff3faef6a"><code>756bfaa</code></a>
fix <code>build:extension:dev</code> script</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/a7a2efdab70c919436ff593bdbd8c3b4acaa96b0"><code>a7a2efd</code></a>
syncpack fix</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/5f6749f16bc38608fbf6f0d48b216320676996b8"><code>5f6749f</code></a>
fix tests</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/bb9b24fddf007c547baafbd013270f2a6cb7a2cb"><code>bb9b24f</code></a>
fix zizmor errors in new workflows from upstream</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/b8ccd0e8cd6cc79be5158e7c4ec2691d9c332594"><code>b8ccd0e</code></a>
fix compile errors from merge</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.40.0...v1.40.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.5.2 to 0.5.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.5.3</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-13.</p>
<h3>Enhancements</h3>
<ul>
<li>Add PEP 740 attestations for PyPI releases (<a
href="https://redirect.github.com/j178/prek/pull/2705">#2705</a>)</li>
<li>Add a <code>check-jsonc</code> builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2682">#2682</a>)</li>
<li>Allow disabling automatic uv installation (<a
href="https://redirect.github.com/j178/prek/pull/2702">#2702</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix Julia additional dependency specifiers (<a
href="https://redirect.github.com/j178/prek/pull/2703">#2703</a>)</li>
<li>Update <code>granit-parser</code> to fix YAML flow indentation (<a
href="https://redirect.github.com/j178/prek/pull/2707">#2707</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/clbarnes"><code>@​clbarnes</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a
href="https://github.com/tisonkun"><code>@​tisonkun</code></a></li>
</ul>
<h2>Install prek 0.5.3</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.5.3/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.5.3/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.5.3</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-x86_64-apple-darwin.tar.gz">prek-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-aarch64-pc-windows-msvc.zip">prek-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-x86_64-pc-windows-msvc.zip">prek-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.3/prek-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.5.3</h2>
<p>Released on 2026-09-13.</p>
<h3>Enhancements</h3>
<ul>
<li>Add PEP 740 attestations for PyPI releases (<a
href="https://redirect.github.com/j178/prek/pull/2705">#2705</a>)</li>
<li>Add a <code>check-jsonc</code> builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2682">#2682</a>)</li>
<li>Allow disabling automatic uv installation (<a
href="https://redirect.github.com/j178/prek/pull/2702">#2702</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix Julia additional dependency specifiers (<a
href="https://redirect.github.com/j178/prek/pull/2703">#2703</a>)</li>
<li>Update <code>granit-parser</code> to fix YAML flow indentation (<a
href="https://redirect.github.com/j178/prek/pull/2707">#2707</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/clbarnes"><code>@​clbarnes</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a
href="https://github.com/tisonkun"><code>@​tisonkun</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/b7eb6027125de7e3b67dd94039a4f69abf3a5fb0"><code>b7eb602</code></a>
Bump version to 0.5.3 (<a
href="https://redirect.github.com/j178/prek/issues/2708">#2708</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/4644f81e1c86eeb8e22a1ba4aaa6dec99b4266c5"><code>4644f81</code></a>
Update granit-parser to fix YAML flow indentation (<a
href="https://redirect.github.com/j178/prek/issues/2707">#2707</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/87f2ea44c258dc6606ca5556a7b3ff0d9a0a601e"><code>87f2ea4</code></a>
Use self-repository syntax in CI workflows</li>
<li><a
href="https://github.com/j178/prek/commit/f39abae3cafd9ff245843b790fdd9b7c2e933b5c"><code>f39abae</code></a>
Add PEP 740 attestations for PyPI releases (<a
href="https://redirect.github.com/j178/prek/issues/2705">#2705</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f4924dccacd86afab22ae45e634d7f9ca12dd59e"><code>f4924dc</code></a>
Allow disabling automatic uv installation (<a
href="https://redirect.github.com/j178/prek/issues/2702">#2702</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/156c0cec12847513ba764d1d87543ab6d0785c64"><code>156c0ce</code></a>
Fix Julia additional dependency specifiers (<a
href="https://redirect.github.com/j178/prek/issues/2703">#2703</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c3ede77b83e7d578e31d076863b755b296256a21"><code>c3ede77</code></a>
Add a <code>check-jsonc</code> builtin hook (<a
href="https://redirect.github.com/j178/prek/issues/2682">#2682</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c0b9749c3ee43f42efd0116624a7922feded3fc2"><code>c0b9749</code></a>
Verify checksums for PyPI/mirror wheel installs (<a
href="https://redirect.github.com/j178/prek/issues/2688">#2688</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/fbe5c66737e679f31018dd438d16774c19c6774d"><code>fbe5c66</code></a>
Update prek hooks (<a
href="https://redirect.github.com/j178/prek/issues/2690">#2690</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/4687a2c57f8ae58cf0e66b65baf49ea72ccb62ba"><code>4687a2c</code></a>
Fix <code>check-hooks-apply</code> for builtin Windows filename
checks</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.5.2...v0.5.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.6 to 0.16.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.7</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-10.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Add rule for default values on method receivers
(<code>RUF077</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26700">#26700</a>)</li>
<li>[<code>ruff</code>] Recognize <code>re.prefixmatch</code>
(<code>RUF039</code>, <code>RUF055</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28311">#28311</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Alternate nested quotes inside format spec interpolations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28259">#28259</a>)</li>
<li>[<code>flake8-implicit-str-concat</code>] Mark fix unsafe when it
creates a docstring (<code>ISC003</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27981">#27981</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Skip fixes for multi-member
imports (<code>TID254</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26584">#26584</a>)</li>
<li>[<code>pylint</code>] Gate <code>ImportCycleError</code> on Python
3.15 (<code>PLW0133</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28310">#28310</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Correct <code>D211</code> and <code>D203</code> rule conflict
diagnostic (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28444">#28444</a>)</li>
<li>Recognize <code>slice</code> and <code>frozendict</code> generics
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28477">#28477</a>)</li>
<li>Stop defining <code>__cached__</code> for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28476">#28476</a>)</li>
<li>[<code>pyupgrade</code>] Stop recommending removed
<code>typing.no_type_check_decorator</code> (<code>UP035</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28475">#28475</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reuse parser name lookups when interning (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28399">#28399</a>)</li>
<li>Speed up inherited configuration resolution (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28299">#28299</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix <code>line-length</code> path in <code>--config</code> example
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28392">#28392</a>)</li>
<li>Remove the &quot;Who’s Using Ruff?&quot; list (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28455">#28455</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Embed archive checksums in the shell installer (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28281">#28281</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/The-Compiler"><code>@​The-Compiler</code></a></li>
<li><a
href="https://github.com/mdiniz97"><code>@​mdiniz97</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/gorewilliams"><code>@​gorewilliams</code></a></li>
<li><a
href="https://github.com/RafaelJohn9"><code>@​RafaelJohn9</code></a></li>
<li><a href="https://github.com/qatcod"><code>@​qatcod</code></a></li>
<li><a href="https://github.com/zanieb"><code>@​zanieb</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.7</h2>
<p>Released on 2026-09-10.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Add rule for default values on method receivers
(<code>RUF077</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26700">#26700</a>)</li>
<li>[<code>ruff</code>] Recognize <code>re.prefixmatch</code>
(<code>RUF039</code>, <code>RUF055</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28311">#28311</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Alternate nested quotes inside format spec interpolations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28259">#28259</a>)</li>
<li>[<code>flake8-implicit-str-concat</code>] Mark fix unsafe when it
creates a docstring (<code>ISC003</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27981">#27981</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Skip fixes for multi-member
imports (<code>TID254</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26584">#26584</a>)</li>
<li>[<code>pylint</code>] Gate <code>ImportCycleError</code> on Python
3.15 (<code>PLW0133</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28310">#28310</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Correct <code>D211</code> and <code>D203</code> rule conflict
diagnostic (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28444">#28444</a>)</li>
<li>Recognize <code>slice</code> and <code>frozendict</code> generics
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28477">#28477</a>)</li>
<li>Stop defining <code>__cached__</code> for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28476">#28476</a>)</li>
<li>[<code>pyupgrade</code>] Stop recommending removed
<code>typing.no_type_check_decorator</code> (<code>UP035</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28475">#28475</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reuse parser name lookups when interning (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28399">#28399</a>)</li>
<li>Speed up inherited configuration resolution (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28299">#28299</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix <code>line-length</code> path in <code>--config</code> example
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28392">#28392</a>)</li>
<li>Remove the &quot;Who’s Using Ruff?&quot; list (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28455">#28455</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Embed archive checksums in the shell installer (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28281">#28281</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/The-Compiler"><code>@​The-Compiler</code></a></li>
<li><a
href="https://github.com/mdiniz97"><code>@​mdiniz97</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/gorewilliams"><code>@​gorewilliams</code></a></li>
<li><a
href="https://github.com/RafaelJohn9"><code>@​RafaelJohn9</code></a></li>
<li><a href="https://github.com/qatcod"><code>@​qatcod</code></a></li>
<li><a href="https://github.com/zanieb"><code>@​zanieb</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/nightt5879"><code>@​nightt5879</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/b5dba861cc38e3f7fb4524c9ceba3e01a474ea13"><code>b5dba86</code></a>
Bump version to 0.16.7 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28496">#28496</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/5992d0504697d86565d8fc3a4d8245a5f4047d24"><code>5992d05</code></a>
Install rustfmt before linting releases (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28495">#28495</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/1713a1f4325494d883a080d590a25a1946f399e8"><code>1713a1f</code></a>
ensure prepare release changes pass prek (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28488">#28488</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/18cdbb4f3d14058794420e758864795f55336334"><code>18cdbb4</code></a>
use scoped token for release workflow (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28484">#28484</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c3813a501faf887fd01948c98bb8d58ad26488bd"><code>c3813a5</code></a>
add a workflow for preparing releases (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28486">#28486</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/00948c00a671b81f5358af9f038436bcbb993b38"><code>00948c0</code></a>
Remove the &quot;Who’s Using Ruff?&quot; list (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28455">#28455</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/86a2eba7b48e3c10386f7ab8a5425c7275d2b427"><code>86a2eba</code></a>
[<code>pyupgrade</code>] Stop recommending removed
<code>typing.no_type_check_decorator</code> (`UP...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/609e184aa35f0034b7ef63e3e04327081c484af6"><code>609e184</code></a>
Stop defining <code>__cached__</code> for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28476">#28476</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/859ff2f01670c43ffff1ea597c8a2e375ada0fbe"><code>859ff2f</code></a>
[ty] Track symlinked directory status in listings (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28482">#28482</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/77f653825800ddaf3bc221ae6db49a500e1002d5"><code>77f6538</code></a>
Use paid GitHub-hosted runners for Linux (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28478">#28478</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.6...0.16.7">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-17 15:53:10 -04:00
Vinicius Gabriel c53545d9fe Add configurable word separator for naming templates (#1333)
Closes #1230

## What
Adds a "Word Separator" setting (Space / Dot / Underscore / Hyphen /
Custom) that replaces internal whitespace in each naming-template
placeholder's rendered value — e.g. `{Author}` renders
"Arthur.Conan.Doyle" instead of "Arthur Conan Doyle" when Dot is
selected.

This follows option 2 from the issue rather than inventing new
dotted-keyword template syntax (`{Author.}`), since it's a smaller
surface: one setting applies uniformly across all four templates
(books/audiobooks × rename/organize) instead of needing a parallel token
for every existing one.

## How it works
- Literal characters typed into the template itself (e.g. the `.` in
`{Author}.-.{Title}`) are never touched — only whitespace *inside* a
placeholder's resolved value is affected.
- Default is "Space", which is a no-op: existing templates produce
byte-identical output after this change (verified via the existing test
suite, unmodified, still passing).

## Where
- `shelfmark/core/naming.py` — `word_separator` param on
`parse_naming_template` / `build_library_path`.
- `shelfmark/download/postprocess/policy.py` — `get_word_separator()`,
mirroring the existing `get_file_organization()` accessor.
- `shelfmark/download/postprocess/transfer.py` — wires the resolved
separator through the four existing template-rendering call sites.
- `shelfmark/config/settings.py` — new `Word Separator` / `Custom Word
Separator` fields next to the existing naming-template fields.
- `src/frontend/.../namingTemplatePreview.ts` +
`NamingTemplateField.tsx` — the settings UI has its own TS mirror of the
Python renderer for the live preview; updated it in lockstep so the
preview doesn't lie about what the separator will actually do.
- Tests added on both sides (pytest + vitest).

## Testing
- `uv run pytest tests/core/test_naming.py
tests/core/test_destination_file_organization.py` — all pass, including
new cases.
- `uv run pytest` (full suite) — same pre-existing failures as on `main`
before this change (browser/network-dependent bypass & e2e tests
unrelated to this diff), everything else green.
- `uv run ruff check` / `ruff format --check` / `basedpyright` — clean.
- `npm run lint` / `format:check` / `typecheck` / `test:unit` (196
tests) — clean.
2026-09-17 15:52:21 -04:00
Atirna 8f608f2e64 fix(download): complete consumed Blackhole handoffs (#1345)
A Blackhole watcher can consume the torrent before Shelfmark checks it,
leaving the task in error even though the handoff succeeded. Complete
the handoff when `add_download` successfully publishes the file, and
stop requiring a `HandoffResult` path to remain present.

Follow-up to #1312.

## Verification

- A watcher that immediately reads and removes the torrent receives the
exact bytes. The task changes from ERROR before this fix to COMPLETE
afterward, without running book postprocessing.
- The consumed-file regression fails on current main and passes here.
Resident files, write failures, cancellation, magnet rejection and
normal downloads remain covered: 81 focused tests pass.
- Ruff lint and formatting pass for the changed files.
2026-09-17 15:51:20 -04:00
David Young 2bb84a17a2 Extract archives when zip/rar are enabled as supported formats (#1343)
The default audiobook formats include `zip` and `rar`.
`scan_directory_tree` checks the supported-format list before checking
for archives, so a downloaded archive lands in `book_files` and is
imported as-is. The extraction branch in `collect_directory_files` is
never reached.

This keeps archives out of `book_files`, so they always take the archive
path: extracted when extraction is allowed, imported as-is when it isn't
(unchanged).

Tests added in `tests/download/test_postprocess_scan_archives.py`; three
of the four fail without the change.
2026-09-17 15:50:52 -04:00
Paul Rimmer 2ed2e9a5d4 Feature: Add Download counts to search result displays and Download sidebar (#1336)
Having the download counts from AA as an input on choosing which of the
many search results to pick for downloading is useful. This PR makes the
downloads numbers available on all the search result pages and also on
the Download sidebar after the user presses a download button for a
Direct Download.

I have also included a SKILL.md and associated download_books.py that
can be used just as a reference or with an LLM harness for automation.
The Downloads info is used by the script to pick which search result to
download out of the many available.

Since a picture is worth a thousand words:

<img width="1225" height="812" alt="search-results-with-downloads"
src="https://github.com/user-attachments/assets/e108ebe2-4cad-45e2-bb6a-d4f49b502de9"
/>

<img width="443" height="267" alt="download-sidebar-with-downloads"
src="https://github.com/user-attachments/assets/9ce9e6c4-dcf5-4f7c-ab22-71850398b534"
/>

Coded with llama.cpp and 🤖
2026-09-17 15:49:57 -04:00
Alex Guerrieri c6b70a6844 fix(sources): send a Referer when fetching libgen ads.php pages (#1340)
## What

libgen.li's `ads.php?md5=` now returns an **empty `200`** to any request
without a `Referer` — an anti-hotlinking check the mirrors added
recently. Both libgen paths fetch it without one, so the page comes back
blank and the download silently fails while **search keeps working**
(which is exactly why it looks like rate-limiting or mirror drift rather
than a bug).

Same one-line cause, two call sites: the Libgen search source
(`libgen/scraper.py:fetch_page`) and the AA-md5 → libgen fallback
(`direct_download/annas_archive.py:_extract_libgen_download_url`). Fix:
send a same-origin `Referer: <scheme>://<host>/` on the `ads.php` fetch
in both.

## Worth a look in review

- **The referer goes on the *resolution* fetch, not the download.**
`download_url(..., referer=...)` was already correct — the blank page
happens one step earlier, at the `ads.php` GET.
- Reproduced against live mirrors: `ads.php` returns `Content-Length: 0`
bare, the full page with a `Referer`, and resolvable files download
valid bytes again.

Regression tests in `tests/libgen/` and `tests/direct_download/` assert
the header on both paths. Lint/format/typecheck clean.

Follow-up to #1326.
2026-09-17 15:47:45 -04:00
CaliBrain 35b89b0d78 fix(sources): restore Direct Download search errors and language matches (#1339)
Fixes two regressions from the provider-driven refactor (#1337). First,
the composite search caught RuntimeError, TypeError, ValueError and
request errors from each provider and returned an empty list, so a
failed search looked like one with no hits. It now raises the first
provider failure when no provider returned releases. Second, the shared
parser re-matched every row's language locally, dropping rows Anna's
Archive had already matched with &lang= (free-text cells like 'English,
French' or 'unknown'). parse_search_items gains a filter_languages
option, which AA turns off, so AA's own language-from-path filter is
again the only local one.
2026-09-14 01:30:05 -04:00
Tom a5cd9f0bfb refactor: make direct download provider-driven (#1337)
This is the refactor for the download handler
2026-09-14 01:16:53 -04:00
Alex Guerrieri af21d1da1f feat(sources): add Libgen as a direct catalogue search source (#1326)
## What

Adds **Libgen as a search source**. Today Libgen is only a download
mirror (reached by an Anna's Archive md5), so anything in Libgen but not
in AA's search index is invisible — and that's where most of the CBZ/CBR
comics and manga live. A Libgen search for *One Piece*, for instance,
turns up ~99 volumes that AA search never shows.

It's a self-contained `release_sources/libgen/` package (source +
handler + settings) plus one line to register it. **No changes to
`direct_download.py`** — it reuses the existing `ads.php → get.php`
resolution and the mirrors already configured in `LIBGEN_MIRROR_URLS`.
Plain HTTP, no bypasser needed (libgen.li isn't behind DDoS-Guard).
Opt-in via a settings toggle.

## Worth a look in review

- **`source_id` is `libgen:<md5>`, not the bare md5.** The download
queue keys on `task_id` (= `source_id`), and `direct_download` already
uses the bare md5. Since AA indexes a lot of Libgen, the same md5 shows
up from both sources — a bare id would collide in the queue. The handler
strips the prefix before downloading.
- **Reachable like the other non-default sources** (Prowlarr,
AudiobookBay, …): it appears in the per-book release search, not the
free-text box (that stays wired to `direct_download`).

Tests in `tests/libgen/` cover parsing (both row layouts), the source,
the handler, and `get_record`. Lint/format/typecheck clean.
2026-09-14 01:08:08 -04:00
CaliBrain 1b17fe179a fix(irc): rank a surname-only result as partial, not wrong (#1332) (#1334)
"David Petrie" as "D. Petrie", then ranked the answer by the full name
to
recover the precision the surname gave up. The two halves disagreed.

author_affinity needs two agreeing tokens before it calls a name the
same
person, so "Petrie" - the name on the filenames a surname search exists
to
reach - matched one and came back AUTHOR_MISMATCH. It therefore sorted
below
"Unknown" and level with "Gordon Petrie", a different author who merely
shares
the surname. The widened query pulled those rows in and the ranker
buried them.

Falling short of agreement is now separated from disagreeing with it. A
name
whose every token fits the one asked for is an abbreviation of it and
ranks
AUTHOR_PARTIAL, between agreement and "no author reported"; a name
carrying a
token that fits nothing still ranks AUTHOR_MISMATCH. Nothing that agreed
before
changes tier - "Homer"/"Homer Simpson" is still a match, since the extra
token
must not demote a mononym that already met its one-token requirement -
so
Prowlarr's #1293 ordering is unchanged except that a tracker listing a
bare
surname stops being read as the wrong author.

Measured on the issue's own case, wanted "David Petrie":

  before: D Petrie, Unknown, Petrie, Gordon Petrie
  after:  D Petrie, Petrie, Unknown, Gordon Petrie

Second fix, same release: a book with no title posted the surname on its
own.
_build_query fell back to book.search_title or book.title, which is
empty on
exactly the path where the plan has no title variants, so the line
reaching the
channel was "@search Petrie" - not a search for anything, and the kind
of bare
over-broad post is_available refuses unaddressed queries to avoid. It
now
returns "" and the existing "No search query could be built" guard takes
it.

Tested with make python-lint, python-format, python-dead-code,
python-typecheck
and python-test.
2026-09-11 22:26:28 -04:00
Zoltán Szabó 35037b35fd fix(irc): search by surname, and rank the answer by author (#1331) (#1332)
Fixes #1331.

A search bot ANDs every term against a filename, so the given name is
the term
that empties the result set. Measured against irchighway's #ebooks:
"Revelations
David Petrie" is answered "no results", "Revelations Petrie" returns 9
matches,
6 of which parse, all filed as "D Petrie".

The query now carries the title and the surname, read off the search
variant so
the ISBN fallback and a manual query - which set author="" on purpose -
keep
their current shape.

Title-only, the shape #1295 settled on for Prowlarr, does not transfer:
the bot
caps an answer at 1000 matches, and a bare "Revelations" hits that cap
with 923
parsed rows across 500 authors, so the cap itself can drop the wanted
book. The
surname is the token the two spellings share and it keeps the answer
small.

The full author then orders what comes back, reusing author_affinity
from #1295,
since a surname also matches a different author who shares it. It sits
under
server availability the way indexer priority does in #1295: a download
addresses
one named bot and waits 120s for it, so a match from a bot that has left
the
channel must not outrank a mismatch that can answer. Ranking runs on the
way out
rather than before the cache, because one query identity is shared by
every book
that produced that query.

Two things found while testing:

- The parser writes the literal "Unknown" when a filename has no " - "
separator
  (parser.py:168). Ranked literally that sorts as a wrong author, so
author_affinity's middle tier was unreachable here; it is now read as
absent.
  5 of those 923 rows are affected.
- author_affinity moves to shelfmark/core/author_match.py, unchanged, so
IRC
does not import from the Prowlarr package. Prowlarr behaviour is
untouched and
  its tests pass as they are.

The three IRC assertions in the #1252 regression file move to the
surname form.
The invariant they pin - one contributor's name reaches the query, never
the
whole credit list - is unchanged.

Tested with make python-lint, python-format, python-dead-code,
python-typecheck
and python-test, and end to end against irchighway with the patched
source: it
posts "Revelations Petrie" and returns 6 releases.
2026-09-11 22:14:37 -04:00
dependabot[bot] 8c902d7f7a build(deps-dev): bump vitest from 4.1.11 to 5.0.0 in /src/frontend (#1330)
Bumps
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
from 4.1.11 to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<p>Vitest 5 is officially out! This release focuses on performance and
brings a lot of new features while fixing long-standing bugs. See our <a
href="https://vitest.dev/blog/vitest-5.html">blog post</a> for the
official announcement.</p>
<h3>   🚨 Breaking Changes</h3>
<ul>
<li>Replace <code>loupe.inspect</code> with pretty-format  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Claude Opus 5 (1M context)</strong> and <strong>OpenAI
Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/9609">vitest-dev/vitest#9609</a>
<a href="https://github.com/vitest-dev/vitest/commit/3f802da4b"><!-- raw
HTML omitted -->(3f802)<!-- raw HTML omitted --></a></li>
<li>Remove quotes from string values in <code>test.for/each</code> title
<code>$</code> variable (take 2)  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10170">vitest-dev/vitest#10170</a>
<a href="https://github.com/vitest-dev/vitest/commit/04d37e9d7"><!-- raw
HTML omitted -->(04d37)<!-- raw HTML omitted --></a></li>
<li>Default <code>attachmentsDir</code> from
<code>.vitest-attachements/</code> to <code>.vitest/attachments/</code>
 -  by <a
href="https://github.com/MdSadiqMd"><code>@​MdSadiqMd</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10186">vitest-dev/vitest#10186</a>
<a href="https://github.com/vitest-dev/vitest/commit/1ba7338c3"><!-- raw
HTML omitted -->(1ba73)<!-- raw HTML omitted --></a></li>
<li>Remove <code>sequential</code> test/suite options in favor of
<code>concurrent</code>  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> and
<strong>OpenAI Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10198">vitest-dev/vitest#10198</a>
<a href="https://github.com/vitest-dev/vitest/commit/9229f2edc"><!-- raw
HTML omitted -->(9229f)<!-- raw HTML omitted --></a></li>
<li>Represent locator as an object instead of a string  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10212">vitest-dev/vitest#10212</a>
<a href="https://github.com/vitest-dev/vitest/commit/80f07edf6"><!-- raw
HTML omitted -->(80f07)<!-- raw HTML omitted --></a></li>
<li>Inline <code>expect</code> package  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10221">vitest-dev/vitest#10221</a>
<a href="https://github.com/vitest-dev/vitest/commit/ad16223e7"><!-- raw
HTML omitted -->(ad162)<!-- raw HTML omitted --></a></li>
<li>Remove deprecated entry points  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10222">vitest-dev/vitest#10222</a>
<a href="https://github.com/vitest-dev/vitest/commit/994c6ddb9"><!-- raw
HTML omitted -->(994c6)<!-- raw HTML omitted --></a></li>
<li>Require Node.js 22 and Vite 6.4  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10178">vitest-dev/vitest#10178</a>
<a href="https://github.com/vitest-dev/vitest/commit/3876283e8"><!-- raw
HTML omitted -->(38762)<!-- raw HTML omitted --></a></li>
<li>Fail <code>expect.poll</code> when function didn't resolve in time
 -  by <a href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>
and <strong>OpenAI Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10233">vitest-dev/vitest#10233</a>
<a href="https://github.com/vitest-dev/vitest/commit/4df048c11"><!-- raw
HTML omitted -->(4df04)<!-- raw HTML omitted --></a></li>
<li>Throw an error if hoistable methods are outside the top level scope
 -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10460">vitest-dev/vitest#10460</a>
<a href="https://github.com/vitest-dev/vitest/commit/d0b4fddcb"><!-- raw
HTML omitted -->(d0b4f)<!-- raw HTML omitted --></a></li>
<li><code>toHaveTextContent</code> is strict, add
<code>toMatchTextContent</code> as alternative  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10473">vitest-dev/vitest#10473</a>
<a href="https://github.com/vitest-dev/vitest/commit/18f303079"><!-- raw
HTML omitted -->(18f30)<!-- raw HTML omitted --></a></li>
<li>Don't lookup config file from ancestor directories  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>OpenAI Codex</strong> and <strong>Hiroshi Ogawa</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10428">vitest-dev/vitest#10428</a>
<a href="https://github.com/vitest-dev/vitest/commit/945d9090e"><!-- raw
HTML omitted -->(945d9)<!-- raw HTML omitted --></a></li>
<li>Inline <code>@vitest/runner</code> package, do not publish it
anymore  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10511">vitest-dev/vitest#10511</a>
<a href="https://github.com/vitest-dev/vitest/commit/6d6e46b1e"><!-- raw
HTML omitted -->(6d6e4)<!-- raw HTML omitted --></a></li>
<li>Allow mutating happy-dom/jsdom window object  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenAI Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10373">vitest-dev/vitest#10373</a>
<a href="https://github.com/vitest-dev/vitest/commit/206e8cff8"><!-- raw
HTML omitted -->(206e8)<!-- raw HTML omitted --></a></li>
<li>Expose <code>concurrencyId</code>/<code>workerId</code> on
TestModule's diagnostics, make id 1-based  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10516">vitest-dev/vitest#10516</a>
<a href="https://github.com/vitest-dev/vitest/commit/bdd985433"><!-- raw
HTML omitted -->(bdd98)<!-- raw HTML omitted --></a></li>
<li>Add <code>screenshotDirectory</code> config to
<code>browser.expect.toMatchScreenshot</code>  -  by <a
href="https://github.com/macarie"><code>@​macarie</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10592">vitest-dev/vitest#10592</a>
<a href="https://github.com/vitest-dev/vitest/commit/a60ded0fb"><!-- raw
HTML omitted -->(a60de)<!-- raw HTML omitted --></a></li>
<li>Update <code>@sinonjs/fake-timers</code> and support mocking
<code>Temporal</code>  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode
(gpt-5.6-sol)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10654">vitest-dev/vitest#10654</a>
<a href="https://github.com/vitest-dev/vitest/commit/f8b1532fe"><!-- raw
HTML omitted -->(f8b15)<!-- raw HTML omitted --></a></li>
<li>Remove webdriverio package  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10675">vitest-dev/vitest#10675</a>
<a href="https://github.com/vitest-dev/vitest/commit/5fed68f72"><!-- raw
HTML omitted -->(5fed6)<!-- raw HTML omitted --></a></li>
<li>Clear mocks by default before each test  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10613">vitest-dev/vitest#10613</a>
<a href="https://github.com/vitest-dev/vitest/commit/0f6463bf2"><!-- raw
HTML omitted -->(0f646)<!-- raw HTML omitted --></a></li>
<li>Don't emit localStorage warnings on Node 26, fail gracefully when
worker fails to start  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10293">vitest-dev/vitest#10293</a>
<a href="https://github.com/vitest-dev/vitest/commit/334edef92"><!-- raw
HTML omitted -->(334ed)<!-- raw HTML omitted --></a></li>
<li>Separate config resolution from the server creation  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10554">vitest-dev/vitest#10554</a>
<a href="https://github.com/vitest-dev/vitest/commit/1c0ec3444"><!-- raw
HTML omitted -->(1c0ec)<!-- raw HTML omitted --></a></li>
<li>Inline projects extend the root config by default  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10750">vitest-dev/vitest#10750</a>
<a href="https://github.com/vitest-dev/vitest/commit/fec001ad3"><!-- raw
HTML omitted -->(fec00)<!-- raw HTML omitted --></a></li>
<li>Enable mocking Temporal without fake timers  -  by <a
href="https://github.com/fabon-f"><code>@​fabon-f</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode
(gpt-5.6-sol)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10757">vitest-dev/vitest#10757</a>
<a href="https://github.com/vitest-dev/vitest/commit/ac2d46b42"><!-- raw
HTML omitted -->(ac2d4)<!-- raw HTML omitted --></a></li>
<li>Support nested projects  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10846">vitest-dev/vitest#10846</a>
<a href="https://github.com/vitest-dev/vitest/commit/ec367cf2a"><!-- raw
HTML omitted -->(ec367)<!-- raw HTML omitted --></a></li>
<li>Use <code>&gt;</code> as separator in <code>-t</code>, calculate
<code>only</code> once  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10686">vitest-dev/vitest#10686</a>
<a href="https://github.com/vitest-dev/vitest/commit/a0b20bc86"><!-- raw
HTML omitted -->(a0b20)<!-- raw HTML omitted --></a></li>
<li>Fail the test when an asynchronous assertion is not awaited  -  by
<a href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a>
in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10868">vitest-dev/vitest#10868</a>
<a href="https://github.com/vitest-dev/vitest/commit/86d4a9da9"><!-- raw
HTML omitted -->(86d4a)<!-- raw HTML omitted --></a></li>
<li>Share the Vite server between inline projects  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10848">vitest-dev/vitest#10848</a>
<a href="https://github.com/vitest-dev/vitest/commit/d87c96ee4"><!-- raw
HTML omitted -->(d87c9)<!-- raw HTML omitted --></a></li>
<li>Parse files statically in vitest list by default  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/11088">vitest-dev/vitest#11088</a>
<a href="https://github.com/vitest-dev/vitest/commit/51e949416"><!-- raw
HTML omitted -->(51e94)<!-- raw HTML omitted --></a></li>
<li><strong>benchmark</strong>:
<ul>
<li>Rewrite the public API  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10113">vitest-dev/vitest#10113</a>
<a href="https://github.com/vitest-dev/vitest/commit/19f6e8947"><!-- raw
HTML omitted -->(19f6e)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>browser</strong>:
<ul>
<li>Iframe scale  -  by <a
href="https://github.com/macarie"><code>@​macarie</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/9745">vitest-dev/vitest#9745</a>
<a href="https://github.com/vitest-dev/vitest/commit/b639852cc"><!-- raw
HTML omitted -->(b6398)<!-- raw HTML omitted --></a></li>
<li>Enable <code>locators.exact</code> by default  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10430">vitest-dev/vitest#10430</a>
<a href="https://github.com/vitest-dev/vitest/commit/e203202f9"><!-- raw
HTML omitted -->(e2032)<!-- raw HTML omitted --></a></li>
<li>Require <code>sessionId</code> for orchestrator html request  -  by
<a href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenAI Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10522">vitest-dev/vitest#10522</a>
<a href="https://github.com/vitest-dev/vitest/commit/79b7d8fcc"><!-- raw
HTML omitted -->(79b7d)<!-- raw HTML omitted --></a></li>
<li>Save failure screenshots in <code>attachmentsDir</code>  -  by <a
href="https://github.com/macarie"><code>@​macarie</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10917">vitest-dev/vitest#10917</a>
<a href="https://github.com/vitest-dev/vitest/commit/3b5bbd8b4"><!-- raw
HTML omitted -->(3b5bb)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>coverage</strong>:
<ul>
<li><code>include/exclude</code> globs too eager  -  by <a
href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/9818">vitest-dev/vitest#9818</a>
<a href="https://github.com/vitest-dev/vitest/commit/edacb0fd4"><!-- raw
HTML omitted -->(edacb)<!-- raw HTML omitted --></a></li>
<li>Allow <code>thresholds.perFile</code> to accept an object  -  by <a
href="https://github.com/vladlenskiy"><code>@​vladlenskiy</code></a> and
<a href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10190">vitest-dev/vitest#10190</a>
<a href="https://github.com/vitest-dev/vitest/commit/13b78d98b"><!-- raw
HTML omitted -->(13b78)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>expect</strong>:
<ul>
<li>Fix <code>toThrow(&quot;&quot;)</code> behavior by reverting <a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/6710">#6710</a>
 -  by <a href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>
in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/9643">vitest-dev/vitest#9643</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/6710">vitest-dev/vitest#6710</a>
<a href="https://github.com/vitest-dev/vitest/commit/6c3e4bdbf"><!-- raw
HTML omitted -->(6c3e4)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>mocker</strong>:
<ul>
<li>Deserialize automock as automock  -  by <a
href="https://github.com/nami8824"><code>@​nami8824</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10192">vitest-dev/vitest#10192</a>
<a href="https://github.com/vitest-dev/vitest/commit/2f892712d"><!-- raw
HTML omitted -->(2f892)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>reporters</strong>:
<ul>
<li><code>blob</code> reporter and <code>--merge-reports</code> default
to <code>.vitest/blob/</code>  -  by <a
href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10232">vitest-dev/vitest#10232</a>
<a href="https://github.com/vitest-dev/vitest/commit/d22b029ae"><!-- raw
HTML omitted -->(d22b0)<!-- raw HTML omitted --></a></li>
<li>Write json and junit reporter output files to <code>.vitest</code>
by default  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong>, <strong>OpenCode (gpt-5.6-sol)</strong>
and <a
href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10621">vitest-dev/vitest#10621</a>
<a href="https://github.com/vitest-dev/vitest/commit/58577290a"><!-- raw
HTML omitted -->(58577)<!-- raw HTML omitted --></a></li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitest-dev/vitest/commit/f441c6fab25e579c5b7dd3dd50538416f415fbae"><code>f441c6f</code></a>
chore: release v5.0.0 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11130">#11130</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/d46a7472266d5bb43595ea51dcdd64ab0f560f12"><code>d46a747</code></a>
fix: treat test.describe as a suite during static collection (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11128">#11128</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/584cf308437069385b0fb905fa3ff7d7b7f65a90"><code>584cf30</code></a>
fix: add a warning if inline project has duplicate plugins due to
unexpected ...</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/f08ce4b7144542af128dcb884150c42074223653"><code>f08ce4b</code></a>
fix: apply queued mocks from doMock() in queue order (fixes <a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10706">#10706</a>)
(<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11127">#11127</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/897f51fd2493046c52ec9539b7d02fe3763bd63e"><code>897f51f</code></a>
chore: release v5.0.0-rc.4 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11107">#11107</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/1339b0655dc4679aeb8f905bacee83b6f76f6b23"><code>1339b06</code></a>
chore(deps): update all non-major dependencies (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11104">#11104</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/51e9494166d8d0108a621fce80c41b6dba760bae"><code>51e9494</code></a>
feat!: parse files statically in vitest list by default (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11088">#11088</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/2122ffdfb42d86c9a2f1238100d6a031312cae32"><code>2122ffd</code></a>
fix: propagate --maxWorkers to projects (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11102">#11102</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/dc10f5f8fb69b026afcf56f8a7a9dd36bd964d73"><code>dc10f5f</code></a>
fix(browser): report the action error when a task times out (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11101">#11101</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/d4fe1986fe334d22940039e815ccdbcc907baa6a"><code>d4fe198</code></a>
feat: promote clearCache out of experimental (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/11086">#11086</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vitest&package-manager=npm_and_yarn&previous-version=4.1.11&new-version=5.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 02:07:57 -04:00
dependabot[bot] 68de5de241 build(deps-dev): bump the npm-deps group in /src/frontend with 4 updates (#1329)
Bumps the npm-deps group in /src/frontend with 4 updates:
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node),
[@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom),
[oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) and
[oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint).

Updates `@types/node` from 26.4.0 to 26.5.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react-dom` from 19.2.5 to 19.2.7
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.65.0 to 0.67.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.67.0] - 2026-09-07</h2>
<h3>🛡️ Security</h3>
<ul>
<li>9a612d5 deps: Update npm packages (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26178">#26178</a>)
(renovate[bot])</li>
</ul>
<h2>[0.64.0] - 2026-08-18</h2>
<h3>🚀 Features</h3>
<ul>
<li>c07fe7c oxfmt: Support <code>experimentalOperatorPosition</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25643">#25643</a>)
(leaysgur)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>fed6681 oxfmt: Skip expanding overrides options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25572">#25572</a>)
(leaysgur)</li>
</ul>
<h2>[0.62.0] - 2026-08-03</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>e6e584b oxfmt: Type jsdoc. enum options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25008">#25008</a>)
(leaysgur)</li>
</ul>
<h2>[0.59.0] - 2026-07-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>415fe1e oxfmt: Error on ignorePatterns that cannot match files
outside the config directory (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24286">#24286</a>)
(leaysgur)</li>
</ul>
<h2>[0.55.0] - 2026-06-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>9a2788b linter/unicorn: Implement <code>prefer-export-from</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22935">#22935</a>)
(AliceLanniste)</li>
</ul>
<h2>[0.54.0] - 2026-06-08</h2>
<h3>📚 Documentation</h3>
<ul>
<li>dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22965">#22965</a>)
(Boshen)</li>
<li>f88961a oxfmt: Annotate each config option with supported languages
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22953">#22953</a>)
(leaysgur)</li>
</ul>
<h2>[0.52.0] - 2026-05-26</h2>
<h3>🚀 Features</h3>
<ul>
<li>16b8058 oxfmt: Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22454">#22454</a>)
(leaysgur)</li>
</ul>
<h2>[0.50.0] - 2026-05-15</h2>
<h3>🐛 Bug Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/b4da00b621ec2f6f67ed218f5366c45ed325331b"><code>b4da00b</code></a>
release(apps): oxlint v1.82.0 &amp;&amp; oxfmt v0.67.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26384">#26384</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/9a612d57e5f1ad9ee6f9f0d8d67692cd430f7ecf"><code>9a612d5</code></a>
chore(deps): update npm packages (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26178">#26178</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0b4e2e67f4193e7ebfcc64982275eb583ae82c83"><code>0b4e2e6</code></a>
release(apps): oxlint v1.81.0 &amp;&amp; oxfmt v0.66.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26199">#26199</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/5ff57f83c049e338db8b2435dd92f660bfe19ed4"><code>5ff57f8</code></a>
fix(formatter/sort-imports): handle custom side effect groups (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26217">#26217</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/63bc313934bf1fe94f8e0e6e59336f6036b8506e"><code>63bc313</code></a>
chore(npm): update funding URL (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26066">#26066</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.67.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.80.0 to 1.82.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.82.0 &amp; oxfmt v0.67.0</h2>
<h2>Table of Contents</h2>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxlint-v1.82.0">Oxlint
v1.82.0</a></li>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxfmt-v0.67.0">Oxfmt
v0.67.0</a></li>
</ul>
<h2>Oxlint v1.82.0</h2>
<h3>💥 BREAKING CHANGES</h3>
<ul>
<li>66744f0 parser: [<strong>BREAKING</strong>] Rename
<code>panicked</code> to <code>fatal_error</code> in
<code>ParserReturn</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26382">#26382</a>)
(overlookmotel)</li>
</ul>
<h3>🚀 Features</h3>
<ul>
<li>6a0e19c linter/eslint/no-unmodified-loop-condition: Support
<code>checkConditionalExpressions</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26249">#26249</a>)
(camc314)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>aa38ddf linter/unicorn/numeric-separators-style: Correct schema
defaults (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26393">#26393</a>)
(camc314)</li>
<li>562dd14 jsx-a11y/anchor-has-content: Allow anchors passed as custom
component props (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26360">#26360</a>)
(Mikhail Baev)</li>
<li>253cdb2 linter/eslint/id-length: Exempt TS interface/type-literal
members with never (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26310">#26310</a>)
(Pearce Ropion)</li>
<li>8c7ea76 ast_visit: Account for trimmed source offsets (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26223">#26223</a>)
(Cameron)</li>
<li>5f9cffc linter/typescript/no-explicit-any: Fix rest parameter to
<code>unknown[]</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26279">#26279</a>)
(camc314)</li>
<li>4de9fa3 linter/react/jsx-no-literals: Check nested JSX expression
literals (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26253">#26253</a>)
(camc314)</li>
<li>07851b9 parser: Fix debug assert failure when lexer error with
tokens enabled (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26229">#26229</a>)
(overlookmotel)</li>
<li>9cee146 oxlint/lsp: Don't try to parse fix message, always fallback
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26204">#26204</a>)
(Sysix)</li>
<li>a662c40 linter/eslint/no-useless-assignment: Handle destructuring
assignments (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25925">#25925</a>)
(camc314)</li>
<li>304bd9a linter/eslint/no-array-constructor: Handle ASI hazards in
fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26166">#26166</a>)
(Hamody We)</li>
<li>b41bb35 linter: Qualify rules in rules output (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26250">#26250</a>)
(camc314)</li>
<li>895c685 linter/typescript/no-extraneous-class: Avoid deleting class
expressions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26231">#26231</a>)
(camc314)</li>
<li>4ba33c8 linter/eslint/no-unused-vars: Handle stored arrow references
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26225">#26225</a>)
(camc314)</li>
</ul>
<h3>🛡️ Security</h3>
<ul>
<li>9a612d5 deps: Update npm packages (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26178">#26178</a>)
(renovate[bot])</li>
</ul>
<h2>Oxfmt v0.67.0</h2>
<h3>💥 BREAKING CHANGES</h3>
<ul>
<li>66744f0 parser: [<strong>BREAKING</strong>] Rename
<code>panicked</code> to <code>fatal_error</code> in
<code>ParserReturn</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26382">#26382</a>)
(overlookmotel)</li>
<li>2c9a947 parser: [<strong>BREAKING</strong>] Reduce
<code>MAX_LEN</code> to 256 bytes below <code>u32::MAX</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26352">#26352</a>)
(overlookmotel)</li>
</ul>
<h3>🚀 Features</h3>
<ul>
<li>68e12ab formatter_css: Follow the oxc-css-parser's acceptance line
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26337">#26337</a>)
(leaysgur)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>f7acdc0 formatter: Treat a JSDoc cast target as opaque in chain
layouts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26375">#26375</a>)
(leaysgur)</li>
<li>104061b formatter: Keep JSDoc cast parens with a comment inside them
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26374">#26374</a>)
(leaysgur)</li>
<li>3d00a76 formatter_css: Keep comment inside important and simple-vars
colon (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26370">#26370</a>)
(leaysgur)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.82.0] - 2026-09-07</h2>
<h3>🚀 Features</h3>
<ul>
<li>6a0e19c linter/eslint/no-unmodified-loop-condition: Support
<code>checkConditionalExpressions</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26249">#26249</a>)
(camc314)</li>
</ul>
<h2>[1.81.0] - 2026-08-31</h2>
<h3>📚 Documentation</h3>
<ul>
<li>d5be037 linter/typescript/switch-exhaustiveness-check: Clarify
default case comment pattern (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26100">#26100</a>)
(camc314)</li>
</ul>
<h2>[1.79.0] - 2026-08-18</h2>
<h3>💥 BREAKING CHANGES</h3>
<ul>
<li>8c4552d linter: [<strong>BREAKING</strong>] Split
react/react-compiler into per-category rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25500">#25500</a>)
(Boshen)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>228e8e0 linter: Resolve inactive React compiler rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25830">#25830</a>)
(Boshen)</li>
<li>aa49d86 linter: Allow spread rule options in config types (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25675">#25675</a>)
(ch3rry)</li>
<li>36f8451 linter/eslint/no-eval: Align indirect default with ESLint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25656">#25656</a>)
(camc314)</li>
<li>beb724d linter/eslint/no-unused-vars: Report bare underscore
parameters (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25663">#25663</a>)
(camc314)</li>
<li>4004c10 linter/eslint/no-irregular-whitespace: Check comments by
default (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25660">#25660</a>)
(camc314)</li>
<li>285820e linter/no-large-snapshots: Precompile and document allowed
snapshot matchers (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25611">#25611</a>)
(Mikhail Baev)</li>
<li>4df5835 linter: Allow capitalized built-in calls (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25516">#25516</a>)
(Boshen)</li>
</ul>
<h2>[1.78.0] - 2026-08-10</h2>
<h3>🚀 Features</h3>
<ul>
<li>ccb8fe8 linter/jsdoc: Implement <code>no-blank-blocks</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25207">#25207</a>)
(Mikhail Baev)</li>
<li>d4a897c linter/eslint: Implement <code>one-var</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24470">#24470</a>)
(Cole Ellison)</li>
<li>5ab9340 linter/jsx-a11y/anchor-has-content: Add options to match
eslint (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24571">#24571</a>)
(Cole Ellison)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>9573937 linter/typescript: Validate <code>ban-ts-comment</code>
description_format (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25320">#25320</a>)
(Mikhail Baev)</li>
</ul>
<h2>[1.77.0] - 2026-08-03</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>5c0fa61 linter/eslint/no-warning-comments: Unify config structs and
remove manual options docs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25151">#25151</a>)
(Mikhail Baev)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>9dc7756 linter/typescript/no-unnecessary-condition: Clarify options
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25110">#25110</a>)
(camc314)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/b4da00b621ec2f6f67ed218f5366c45ed325331b"><code>b4da00b</code></a>
release(apps): oxlint v1.82.0 &amp;&amp; oxfmt v0.67.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26384">#26384</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/aa38ddfbea657a9d332f86e42e235ff8cbdcac6d"><code>aa38ddf</code></a>
fix(linter/unicorn/numeric-separators-style): correct schema defaults
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26393">#26393</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6a0e19cfaae35ec882de6bc8dde7668d1b0cc58e"><code>6a0e19c</code></a>
feat(linter/eslint/no-unmodified-loop-condition): support
`checkConditionalEx...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0b4e2e67f4193e7ebfcc64982275eb583ae82c83"><code>0b4e2e6</code></a>
release(apps): oxlint v1.81.0 &amp;&amp; oxfmt v0.66.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26199">#26199</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d5be0375e6303202fcd6d34fa520103eceea0238"><code>d5be037</code></a>
docs(linter/typescript/switch-exhaustiveness-check): clarify default
case com...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/63bc313934bf1fe94f8e0e6e59336f6036b8506e"><code>63bc313</code></a>
chore(npm): update funding URL (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26066">#26066</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.82.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 02:07:23 -04:00
dependabot[bot] 9eb47989ec build(deps): bump the docker-base-image-digests group with 2 updates (#1328)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps the docker-base-image-digests group with 2 updates: node and
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `node` from `e67514e` to `50c8e8c`

Updates `astral-sh/uv` from 0.12.9 to 0.12.13
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.12.13</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-10.</p>
<h3>Python</h3>
<ul>
<li>Add GraalPy 3.13.0 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21431">#21431</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Verify hashes when downloading PEP 658 metadata sidecars (<a
href="https://redirect.github.com/astral-sh/uv/pull/21563">#21563</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Respect <code>ty</code> exclusions when <code>uv check</code>
automatically selects members of a virtual workspace (<a
href="https://redirect.github.com/astral-sh/uv/pull/21555">#21555</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid full wheel downloads during resolution by reusing supported
hashes from direct URL fragments when metadata is available separately
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21279">#21279</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Edit Windows entry-point launcher resources in memory to support
Nano Server and reduce antivirus contention (<a
href="https://redirect.github.com/astral-sh/uv/pull/18713">#18713</a>)</li>
<li>Prefer <code>core-metadata</code> over legacy aliases in JSON index
responses (<a
href="https://redirect.github.com/astral-sh/uv/pull/21563">#21563</a>)</li>
</ul>
<h2>Install uv 0.12.13</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-installer.ps1
| iex&quot;
</code></pre>
<h2>Download uv 0.12.13</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-apple-darwin.tar.gz">uv-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-x86_64-apple-darwin.tar.gz">uv-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-pc-windows-msvc.zip">uv-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-i686-pc-windows-msvc.zip">uv-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-x86_64-pc-windows-msvc.zip">uv-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-unknown-linux-gnu.tar.gz">uv-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.13/uv-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.13</h2>
<p>Released on 2026-09-10.</p>
<h3>Python</h3>
<ul>
<li>Add GraalPy 3.13.0 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21431">#21431</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Verify hashes when downloading PEP 658 metadata sidecars (<a
href="https://redirect.github.com/astral-sh/uv/pull/21563">#21563</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Respect <code>ty</code> exclusions when <code>uv check</code>
automatically selects members of a virtual workspace (<a
href="https://redirect.github.com/astral-sh/uv/pull/21555">#21555</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid full wheel downloads during resolution by reusing supported
hashes from direct URL fragments when metadata is available separately
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21279">#21279</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Edit Windows entry-point launcher resources in memory to support
Nano Server and reduce antivirus contention (<a
href="https://redirect.github.com/astral-sh/uv/pull/18713">#18713</a>)</li>
<li>Prefer <code>core-metadata</code> over legacy aliases in JSON index
responses (<a
href="https://redirect.github.com/astral-sh/uv/pull/21563">#21563</a>)</li>
</ul>
<h2>0.12.12</h2>
<p>Released on 2026-09-09.</p>
<p>The executables in our macOS and Windows release archives and
<code>uv</code> and <code>uv_build</code> wheels are now code-signed.
macOS executables are signed with an Apple Developer ID certificate and
notarized by Apple. Windows executables have timestamped Authenticode
signatures from Azure Artifact Signing. This enables verification of the
release publisher and binary integrity, supports publisher-based
allowlisting, and should reduce security warnings and antivirus false
positives.</p>
<h3>Bug fixes</h3>
<ul>
<li>Exclude distributions uploaded after the <code>exclude-newer</code>
cutoff from lockfiles and generated requirement hashes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21539">#21539</a>)</li>
</ul>
<h2>0.12.11</h2>
<p>Released on 2026-09-08.</p>
<h3>Preview features</h3>
<ul>
<li>Generate missing artifact hashes when exporting
<code>pylock.toml</code> files to ensure they conform to PEP 751 (<a
href="https://redirect.github.com/astral-sh/uv/pull/20146">#20146</a>)</li>
<li>Warn when <code>pylock.toml</code> artifact hash tables are empty,
which will be rejected in a future uv release (<a
href="https://redirect.github.com/astral-sh/uv/pull/21462">#21462</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up installs that overwrite existing files by eliminating
per-file temporary directories for atomic hard-link, symlink, and
reflink replacements (<a
href="https://redirect.github.com/astral-sh/uv/pull/21478">#21478</a>)</li>
<li>Speed up installs that merge copied wheels into existing
environments by replacing per-file temporary directories with adjacent
temporary files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21468">#21468</a>)</li>
<li>Speed up local wheel installs by replacing the shared ZIP cursor
lock with positioned reads (<a
href="https://redirect.github.com/astral-sh/uv/pull/21500">#21500</a>)</li>
<li>Speed up local wheel installs by reusing ZIP readers and buffers
across extracted files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21499">#21499</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/0ebbd9274a55a8a53a13970be3b97e4209598e17"><code>0ebbd92</code></a>
Bump version to 0.12.13 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21594">#21594</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/17ccae34815e249c66e53abe21916c3c0b6413e5"><code>17ccae3</code></a>
Use separate Depot projects for Docker development builds (<a
href="https://redirect.github.com/astral-sh/uv/issues/21591">#21591</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/8c18e15bd36dff0e17509cc68c3721798ae1ec2b"><code>8c18e15</code></a>
Use the workflow revision for PR security review configuration (<a
href="https://redirect.github.com/astral-sh/uv/issues/21592">#21592</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/9ebb1f6a72db257a689049ee060b7cf93638aada"><code>9ebb1f6</code></a>
Clarify release pipeline job names (<a
href="https://redirect.github.com/astral-sh/uv/issues/21561">#21561</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/d87450d82b3941507e48ac8b57f72a9d00709289"><code>d87450d</code></a>
Omit unused <code>exclude-newer-package</code> entries from script locks
(<a
href="https://redirect.github.com/astral-sh/uv/issues/21589">#21589</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/911f3a208c104b07b2f4da3a2283564d9a95c403"><code>911f3a2</code></a>
Refactor release artifact handling (<a
href="https://redirect.github.com/astral-sh/uv/issues/21556">#21556</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/a712e811024933ec441667659d6df73c04f5b678"><code>a712e81</code></a>
Separate Docker release builds from publishing (<a
href="https://redirect.github.com/astral-sh/uv/issues/21586">#21586</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/4196dae60a0cc542bd43c0188f8b4c6dbfa0df98"><code>4196dae</code></a>
Use xhigh effort for PR security review (<a
href="https://redirect.github.com/astral-sh/uv/issues/21530">#21530</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/a51624b4791456260f72068ae878796233f72809"><code>a51624b</code></a>
Reduce PR security review reporting work (<a
href="https://redirect.github.com/astral-sh/uv/issues/21528">#21528</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/63e28b69821b4b55b90287d799cbf97ff6ba0f74"><code>63e28b6</code></a>
Use <code>editpe</code> for trampoline resource edits (<a
href="https://redirect.github.com/astral-sh/uv/issues/18713">#18713</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.12.9...0.12.13">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 02:07:12 -04:00
Austin Brogle 99e0cfde3d fix: prevent Anna's Archive download countdown resets by preserving browser sessions (#1325)
## Observed bug

Anna's Archive slow-download pages can return a JavaScript countdown
before a download link is available. The internal browser returns that
waiting-room HTML and closes its incognito session. The downloader then
sleeps and fetches the URL again, which can create a new queue session
and **restart the countdown instead of reaching the download link**.

## Fix

- **Preserve the queue session:** keep the original browser tab open
while the site's own countdown and automatic navigation finish. HTTP 200
and cached-cookie waiting-room responses enter the same flow.
- **Return a consistent page:** capture HTML and readiness together in
one browser evaluation so navigation cannot pair a new page's status
with stale protection-page HTML. Share cache validation and
page-readiness rules across their callers.
- **Keep waiting cancellable and bounded:** poll cancellation while a
slow browser read remains pending, rather than repeatedly cancelling and
reissuing it. Apply a **300-second waiting-room limit** within the
existing browser watchdog.
- **Report queue timeouts accurately:** preserve the timeout across the
helper-process boundary and stop the solve without restarting the
browser or rotating mirrors.

Waiting-room detection is limited to Anna's Archive `/slow_download/`
pages containing an actual `.js-partner-countdown` element. The site
controls the countdown and refresh. External-bypasser behavior and
file-transfer timeouts are unchanged; the PR adds no deployment
configuration or dependencies.

## Validation

Validated at `c81e0a2`:

| Check | Result |
| --- | --- |
| Full Linux unit suite | **2,978 passed** on Python 3.14 in a non-root
environment with entrypoint test stubs enabled |
| Focused regression coverage | **30 passed**, covering countdown
completion, zero timers, navigation, both cookie-cache paths,
cancellation, stuck queues, slow reads, and timeout propagation |
| Navigation-race regression | Fails against the previous PR
implementation and passes with the fix |
| Python static checks | Ruff lint/format, BasedPyright for backend and
tests, and Vulture passed |
| Real Chromium fixture | Queue cookie persisted through 1.5-second DOM
reads and one automatic refresh; the CDP connection survived multiple
polling intervals |
| Live source check | Observed **19 → 14 → 9 → 4 → download link** while
retaining the browser session; the patched browser path also completed
the waiting room |

Full unit-suite command:

```sh
pytest tests/ -n 2 --tb=short -m "not integration and not e2e"
```

The live check validates waiting-room completion and link resolution.
Remote file-host availability remains a separate concern. The unit suite
emitted two existing Authlib deprecation warnings.
2026-09-11 00:51:48 -04:00
Jorge Lima c45d342931 fix(prowlarr): skip indexers in Prowlarr failure back-off (#1324)
## What

Read `/api/v1/indexerstatus` once per search and skip indexers whose
`disabledTill` is still ahead. Skipped is neither attempted nor failed.
One client method, one counter on `_IndexerSearchOutcome`, ten tests.

## Why

Prowlarr's own search leaves out an indexer it has disabled after
repeated failures. Shelfmark queries each indexer through its Torznab
endpoint, which answers 429 instead:

```
Prowlarr Torznab error response: <error code="429" description="Indexer is disabled till 09/09/2026 15:00:34 due to recent failures." />
Prowlarr: 1 of 5 indexer searches failed (indexer 2 search failed: 429 Client Error: Too Many Requests ...)
Release search failed for source prowlarr: 1 of 5 indexer searches failed (...)
```

That counted as a failed search, so with one indexer in back-off and the
other four answering empty, `/api/releases?source=prowlarr` returned 503
for every book for the length of the back-off (one hour here).

`/api/v1/indexerstatus` on Prowlarr 2.5.2:

```json
[{"indexerId": 2, "disabledTill": "2026-09-09T15:00:34Z", "mostRecentFailure": "2026-09-09T14:00:34Z", "initialFailure": "2026-09-09T14:00:34Z"}]
```

## Behaviour

| indexers | before | after |
|---|---|---|
| 1 in back-off, 4 answer empty | 503 "1 of 5 indexer searches failed" |
"No releases found" |
| 1 in back-off, 1 answers with releases | releases | releases, one
Torznab call fewer |
| 1 in back-off, 1 times out, 3 answer empty | "1 of 5 failed" | "1 of 4
failed" |
| every indexer in back-off | 503 "5 of 5 failed" | "every indexer is
disabled by Prowlarr after recent failures (until ...)" |
| status endpoint unreachable | n/a | as before, nothing skipped |

Auto-expand no longer retries a pass in which nothing was asked.

## Tests

`uv run pytest tests/prowlarr`: 563 passed, 42 skipped. `ruff check` and
`ruff format` clean.
2026-09-11 00:49:33 -04:00
oliver 1e3fd48b8b fix: share rotating log file handlers (#1316)
This patch shares (for each log file) the `RotatingFileHandler` for
logging across all modules, reducing the number of open file descriptors
from ~78 to 1.

I had originally assumed this issue was a resource leak, but it seems to
just be a large fixed number of file descriptors. So this change mostly
just (1) shrinks the number of open file descriptors to a reasonable
level and (2) prevents two modules in the same process competing to
write to a log file.
2026-09-11 00:48:22 -04:00
Vinicius GabrielandClaude Sonnet 5 c576003319 feat(naming): add {FirstAuthor} template token (#1322)
Closes #930.

## What

New `{FirstAuthor}` naming-template token. It renders only the first
author when metadata lists several ("Author1, Author2, Author3"), so
multi-author books can be filed alongside the rest of that author's work
instead of getting their own "Author1, Author2, ..." folder.

```
{Author}       -> Terry Pratchett, Neil Gaiman
{FirstAuthor}  -> Terry Pratchett
```

## How

- Added to `KNOWN_TOKENS` in `shelfmark/core/naming.py`, positioned
before `author` so `{FirstAuthor}` isn't parsed as literal `First` +
`{Author}`.
- Derived inside `parse_naming_template` from the existing `Author`
value (split on `,` / `;`), so every caller — folder transfer, rename,
the settings preview — picks it up with no extra wiring. An explicit
`FirstAuthor` key in the metadata still wins if one is ever passed.
- `{Author}` behaviour is unchanged.
- Frontend `namingTemplatePreview.ts` token list + `KNOWN_TOKENS` kept
in lockstep (there's a test enforcing that), with a matching
`firstAuthor` helper.
- Settings field descriptions + `docs/environment-variables.md` list the
new token.

## Known limitation

A lone author written `Last, First` is split on the comma too and
renders as `Last` — the source metadata doesn't mark which form it is.
Called out in the token help text and covered by a test. `{Author}`
remains available for anyone who wants the raw string.

## Checks

- `make python-test` — 2963 passed
- `make python-lint` / `make python-format` / `make python-typecheck` /
vulture — clean
- `make frontend-test` — 187 passed · `frontend-lint` /
`frontend-format` / `frontend-typecheck` — clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 00:47:37 -04:00
Atirna 265da07d7f feat(download): add Blackhole torrent handoff (#1312)
## Why

Blackhole users need Shelfmark to hand a torrent file to their existing
downloader instead of importing the downloaded book itself.

## Change

- add Blackhole as a torrent client with a configurable watched
directory
- prefer a fetched `.torrent` file for Blackhole while preserving magnet
preference for other clients
- complete the queue task after the handoff without invoking book
post-processing

## Verification

- `uv run pytest -q tests/prowlarr/test_blackhole_client.py
tests/prowlarr/test_handler.py tests/newznab/test_handler.py
tests/download/test_orchestrator_lifecycle.py`
- `uv run basedpyright shelfmark/download/clients/blackhole.py
shelfmark/download/clients/__init__.py
shelfmark/download/clients/base_handler.py
shelfmark/download/clients/settings.py
shelfmark/download/orchestrator.py shelfmark/release_sources/__init__.py
shelfmark/release_sources/prowlarr/utils.py
shelfmark/release_sources/prowlarr/handler.py
shelfmark/release_sources/newznab/handler.py
tests/prowlarr/test_blackhole_client.py tests/prowlarr/test_handler.py
tests/newznab/test_handler.py
tests/download/test_orchestrator_lifecycle.py`

Fixes #1229
2026-09-11 00:46:47 -04:00
Nicholas Velten 96d1b7c33a Keep default filters out of the URL hash (#1314)
Follow up to #1311, per your "no use keeping empty / default values in
the url".

A plain author search was coming out as

```
#q=herbert&search_by=author&sort=relevance&lang=default&format=epub&format=mobi&format=azw3&format=fb2&format=djvu&format=cbz&format=cbr
```

The builder serialized every advanced filter regardless of whether the
user had touched it. Now `sort` drops when it equals the sort the app
would apply anyway (the provider default in Universal, the configured
one in Direct), `lang` drops while it is still the `default` sentinel,
and `format` drops when the selection matches `supported_formats` from
the config. Formats are compared as a set, so reselecting everything in
a different order still counts as default. Anything the user actually
changed stays.

That also makes the comment I left in the builder true: a default-state
URL now carries no hash at all.

The second commit is an ordering bug that omitting defaults made
visible. `loadConfig`'s `initial` branch seeds `formats` from
`supported_formats` and `sort` from the mode default. The URL bootstrap
is gated on config being loaded, so it normally runs after that and wins
on its own, but nothing guarantees only one `initial` load happens, and
a second one landing after the bootstrap resets `formats` to the full
supported list and drops the sort the link asked for. StrictMode
double-invokes the mount effect that triggers it, so it reproduces in
development: `#q=dune&format=epub&lang=en` intermittently loses its
`format=epub`. The seeding is now skipped once the bootstrap has
applied, so a link's filters win over the defaults they were meant to
override.

Five new unit tests on the builder. I also drove both the dev server and
a production build in Chromium with `/api` mocked:
`#search_by=author&q=herbert` settles at `#q=herbert&search_by=author`,
typing a plain query gives `#q=dune`, direct mode at rest carries no
hash, and `#q=dune&format=epub&lang=en` keeps both filters in the hash
and in the request. That last one was 3 for 5 on the dev server before
the second commit and 5 for 5 after.
2026-09-11 00:36:55 -04:00
dependabot[bot] 6addae9d7c build(deps): bump the python-deps group across 1 directory with 4 updates (#1327)
Bumps the python-deps group with 4 updates in the / directory:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase),
[basedpyright](https://github.com/detachhead/basedpyright),
[prek](https://github.com/j178/prek) and
[ruff](https://github.com/astral-sh/ruff).

Updates `seleniumbase` from 4.53.5 to 4.53.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.53.7 - MCP Server: Patch 7</h2>
<h2>MCP Server: Patch 7</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/698672b1d14d397c8fabef17c14c36efb01047fa">Update
the MCP Server</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f5c40a2de161745c0de5130ad7479dc823aaf08e">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 7 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4493">seleniumbase/SeleniumBase#4493</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.53.6...v4.53.7">https://github.com/seleniumbase/SeleniumBase/compare/v4.53.6...v4.53.7</a></p>
<h2>4.53.6 - MCP Server: Patch 6</h2>
<h2>MCP Server: Patch 6</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b477cb359f466e5d6f712c6c30a03150076e1420">Update
the MCP server</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 6 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4491">seleniumbase/SeleniumBase#4491</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.53.5...v4.53.6">https://github.com/seleniumbase/SeleniumBase/compare/v4.53.5...v4.53.6</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4ee7dfc4ae83c19385f5ac129f2cda0cfa863d80"><code>4ee7dfc</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4493">#4493</a>
from seleniumbase/mcp-server-patch-7</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a9c9253eec504274d3dbe19202ec858201fe4fd8"><code>a9c9253</code></a>
Version 4.53.7</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f5c40a2de161745c0de5130ad7479dc823aaf08e"><code>f5c40a2</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/698672b1d14d397c8fabef17c14c36efb01047fa"><code>698672b</code></a>
Update the MCP Server</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/db0d4041dde54142a2dd9810b23b30b6aa40fd97"><code>db0d404</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4491">#4491</a>
from seleniumbase/mcp-server-patch-6</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7b835cfbad6becff033a9ae059b84775f42a4e2e"><code>7b835cf</code></a>
Version 4.53.6</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b477cb359f466e5d6f712c6c30a03150076e1420"><code>b477cb3</code></a>
Update the MCP server</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.53.5...v4.53.7">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.10 to 1.40.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/detachhead/basedpyright/releases">basedpyright's
releases</a>.</em></p>
<blockquote>
<h2>v1.40.0 (pyright 1.1.412)</h2>
<h2>What's Changed</h2>
<ul>
<li>drop support for python 3.8 and 3.9 in the pypi package, which are
EOL by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1876">DetachHead/basedpyright#1876</a>
<ul>
<li>users who still need to use unsupported Python versions can still
install <a href="https://npmjs.com/basedpyright">the basedpyright npm
package</a></li>
</ul>
</li>
<li>fix rendering of newlines for builtin docstrings by <a
href="https://github.com/tommyming"><code>@​tommyming</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1871">DetachHead/basedpyright#1871</a></li>
<li>migrate the docs site to zensical by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1795">DetachHead/basedpyright#1795</a></li>
<li>move locale env variable docs to the more appropriate
&quot;Environment Variables&quot; page by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1878">DetachHead/basedpyright#1878</a></li>
<li>Support new Python Environments API when enabled by <a
href="https://github.com/Weidav"><code>@​Weidav</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1860">DetachHead/basedpyright#1860</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tommyming"><code>@​tommyming</code></a>
made their first contribution in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1871">DetachHead/basedpyright#1871</a></li>
<li><a href="https://github.com/Weidav"><code>@​Weidav</code></a> made
their first contribution in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1860">DetachHead/basedpyright#1860</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/DetachHead/basedpyright/compare/v1.39.10...v1.40.0">https://github.com/DetachHead/basedpyright/compare/v1.39.10...v1.40.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/d64b2274480bc64c146f5b387127d4bb35eb403e"><code>d64b227</code></a>
1.40.0</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/1a9ec37d0cffde93059b5993fb094f7dc9e91242"><code>1a9ec37</code></a>
Support new Python Environments API when enabled (<a
href="https://redirect.github.com/detachhead/basedpyright/issues/1860">#1860</a>)</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/37ab66d1bcc6c3e00b391f50b1da9a313e785a96"><code>37ab66d</code></a>
move locale env variable docs to the more appropriate &quot;Environment
Variables&quot;...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/db9be3ceda3b101695574b24761e1bf42b0c5701"><code>db9be3c</code></a>
zensical (<a
href="https://redirect.github.com/detachhead/basedpyright/issues/1795">#1795</a>)</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f408bd7ab1adb419fd1986ccc3a79723e29f4c8e"><code>f408bd7</code></a>
fix rendering of newlines for builtin docstrings (<a
href="https://redirect.github.com/detachhead/basedpyright/issues/1871">#1871</a>)</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/0310a8d3cf6346978ea511e4fb9b1d857fc837d8"><code>0310a8d</code></a>
drop support for python 3.8 and 3.9 in the pypi package, which are
EOL.</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/8a06544547fd26b32fe0f3ff334ce125ba8ca5e7"><code>8a06544</code></a>
bump gg deps and python deps</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/01ffa7fa80ece700dc0e824de7da761f6554e5fa"><code>01ffa7f</code></a>
bump gg to fix download indicator interfering with primer output</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/d5db35dd53d3af48809e5d04e1d0714113363092"><code>d5db35d</code></a>
workaround gg download progress indicator interfering with primer
output</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/dc53c61a95a5d60a348033ed4fba09e3f73d7cba"><code>dc53c61</code></a>
fix primer</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.10...v1.40.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.5.0 to 0.5.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.5.2</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-03.</p>
<h3>Enhancements</h3>
<ul>
<li>Allow unknown tags by default in <code>check-yaml</code> (<a
href="https://redirect.github.com/j178/prek/pull/2678">#2678</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.5.2</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.5.2/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.5.2/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.5.2</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-apple-darwin.tar.gz">prek-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-pc-windows-msvc.zip">prek-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-pc-windows-msvc.zip">prek-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-unknown-linux-gnu.tar.gz">prek-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-unknown-linux-gnu.tar.gz">prek-x86_64-unknown-linux-gnu.tar.gz</a></td>
<td>x64 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-unknown-linux-musl.tar.gz">prek-aarch64-unknown-linux-musl.tar.gz</a></td>
<td>ARM64 MUSL Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-aarch64-unknown-linux-musl.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-unknown-linux-musl.tar.gz">prek-x86_64-unknown-linux-musl.tar.gz</a></td>
<td>x64 MUSL Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.5.2/prek-x86_64-unknown-linux-musl.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<h2>Verifying GitHub Artifact Attestations</h2>
<p>The artifacts in this release have attestations generated with GitHub
Artifact Attestations. These can be verified by using the <a
href="https://cli.github.com/manual/gh_attestation_verify">GitHub
CLI</a>:</p>
<pre lang="sh"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.5.2</h2>
<p>Released on 2026-09-03.</p>
<h3>Enhancements</h3>
<ul>
<li>Allow unknown tags by default in <code>check-yaml</code> (<a
href="https://redirect.github.com/j178/prek/pull/2678">#2678</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>0.5.1</h2>
<p>Released on 2026-09-01.</p>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--hide-status &lt;passed|failed|skipped&gt;</code> for
hook reports (<a
href="https://redirect.github.com/j178/prek/pull/2644">#2644</a>)</li>
<li>Add <code>prek init</code> for repository setup (<a
href="https://redirect.github.com/j178/prek/pull/2636">#2636</a>)</li>
<li>Apply hook <code>env</code> during environment creation (<a
href="https://redirect.github.com/j178/prek/pull/2650">#2650</a>)</li>
<li>Disable error snippets in <code>check-yaml</code> diagnostics (<a
href="https://redirect.github.com/j178/prek/pull/2664">#2664</a>)</li>
<li>Show hooks excluded by skip selectors (<a
href="https://redirect.github.com/j178/prek/pull/2645">#2645</a>)</li>
<li>Support Pixi for Conda environments (<a
href="https://redirect.github.com/j178/prek/pull/2667">#2667</a>)</li>
<li>Support <code>cargo-binstall</code> for Rust CLI dependencies (<a
href="https://redirect.github.com/j178/prek/pull/2658">#2658</a>)</li>
<li>Warn about unused keys in user settings (<a
href="https://redirect.github.com/j178/prek/pull/2665">#2665</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Reject unsupported YAML tags in check-yaml (<a
href="https://redirect.github.com/j178/prek/pull/2656">#2656</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Clarify local hook documentation (<a
href="https://redirect.github.com/j178/prek/pull/2640">#2640</a>)</li>
<li>Clarify pre-commit command compatibility (<a
href="https://redirect.github.com/j178/prek/pull/2635">#2635</a>)</li>
<li>Document automatic PR fixes with autofix.ci (<a
href="https://redirect.github.com/j178/prek/pull/2643">#2643</a>)</li>
<li>Document check-yaml unsafe support (<a
href="https://redirect.github.com/j178/prek/pull/2632">#2632</a>)</li>
<li>Improve setup and workflow documentation (<a
href="https://redirect.github.com/j178/prek/pull/2637">#2637</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Drop low-usage release targets (<a
href="https://redirect.github.com/j178/prek/pull/2651">#2651</a>)</li>
<li>Generate a prek manifest JSON schema (<a
href="https://redirect.github.com/j178/prek/pull/2648">#2648</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/bfaa03cc998a43b1092e7ea918d0c9437a3ade64"><code>bfaa03c</code></a>
Bump version to 0.5.2 (<a
href="https://redirect.github.com/j178/prek/issues/2679">#2679</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f0ce4c249ef17f9be0162e3c42ed765d073619ff"><code>f0ce4c2</code></a>
Allow unknown tags by default in <code>check-yaml</code> (<a
href="https://redirect.github.com/j178/prek/issues/2678">#2678</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/78bb3fe7d901289b3f45c5a5280147860d87cf30"><code>78bb3fe</code></a>
Show verbose builtin details by default (<a
href="https://redirect.github.com/j178/prek/issues/2676">#2676</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/57ea73d2ac28ae8d13fdf25c98c9b4b092a64945"><code>57ea73d</code></a>
Add <code>--allow-unknown-tags</code> to <code>check-yaml</code> to
disable tag checks (<a
href="https://redirect.github.com/j178/prek/issues/2675">#2675</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/695f3d0d7f113ccbbcad6555103107d6866e6b28"><code>695f3d0</code></a>
Show hook selectors first in prek run help (<a
href="https://redirect.github.com/j178/prek/issues/2673">#2673</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/edf43d5014da3566f5ea2f4bdee4f578f9381386"><code>edf43d5</code></a>
Reapply &quot;Reject unsupported YAML tags in check-yaml (<a
href="https://redirect.github.com/j178/prek/issues/2656">#2656</a>)&quot;
(<a
href="https://redirect.github.com/j178/prek/issues/2672">#2672</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ed225b182dba642745ee1f79e185b6afa1928420"><code>ed225b1</code></a>
Bump version to 0.5.2 (<a
href="https://redirect.github.com/j178/prek/issues/2671">#2671</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/de6e61481c610de0836b2628407bfaa353aa3fcd"><code>de6e614</code></a>
Revert unsupported YAML tag rejection in check-yaml (<a
href="https://redirect.github.com/j178/prek/issues/2670">#2670</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/10a896eb63d60dd1175cc7b10ff0798e7070e56f"><code>10a896e</code></a>
Bump version to 0.5.1 (<a
href="https://redirect.github.com/j178/prek/issues/2669">#2669</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/864870940e0d246aa2ce9c3a9a693092e3f8002f"><code>8648709</code></a>
Support Pixi for Conda environments (<a
href="https://redirect.github.com/j178/prek/issues/2667">#2667</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.5.0...v0.5.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.5 to 0.16.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.6</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-03.</p>
<h3>Preview features</h3>
<ul>
<li>Move <code>pytest-fixture-autouse</code> to the
<code>restriction</code> category (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28219">#28219</a>)</li>
<li>[<code>flake8-pytest-style</code>] Add an autofix for
<code>PT020</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27993">#27993</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Prevent fix loop between
<code>TID254</code> and <code>TID255</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28262">#28262</a>)</li>
<li>[<code>isort</code>] Exclude pragma comments from line length
calculation (<code>I001</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27313">#27313</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Validate unary expressions when parsing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28233">#28233</a>)</li>
<li>[<code>flake8-async</code>, <code>pylint</code>] Recognize
<code>builtins.open</code> (<code>ASYNC230</code>, <code>PLW1514</code>)
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28021">#28021</a>)</li>
<li>[<code>flake8-bugbear</code>] Fix panic on <code>match</code>
subjects (<code>B031</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27781">#27781</a>)</li>
<li>[<code>flake8-datetimez</code>] Reject <code>tzinfo=None</code> for
<code>datetime</code> bounds (<code>DTZ901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28022">#28022</a>)</li>
<li>[<code>flake8-pytest-style</code>] Avoid duplicate
<code>PT017</code> diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27918">#27918</a>)</li>
<li>[<code>ruff</code>] Remove <code>lint.external</code> hint for
Ruff-specific suppressions (<code>RUF102</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27923">#27923</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-use-pathlib</code>] Add display-only fix for
<code>os.listdir</code> (<code>PTH208</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28027">#28027</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add another example and glob reference for
<code>lint.per-file-ignores</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28106">#28106</a>)</li>
<li>Add duplicate work guidance (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28229">#28229</a>)</li>
<li>[<code>flake8-async</code>] Document thread offloading
(<code>ASYNC240</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28008">#28008</a>)</li>
<li>[<code>pyupgrade</code>] Clarify default <code>encoding</code>
argument handling (<code>UP012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27315">#27315</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Allow unary plus in match patterns on Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28231">#28231</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/flying-sheep"><code>@​flying-sheep</code></a></li>
<li><a
href="https://github.com/pikammmmm"><code>@​pikammmmm</code></a></li>
<li><a href="https://github.com/fly1d"><code>@​fly1d</code></a></li>
<li><a
href="https://github.com/waterWang"><code>@​waterWang</code></a></li>
<li><a
href="https://github.com/Pierre-Sassoulas"><code>@​Pierre-Sassoulas</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/jelle-openai"><code>@​jelle-openai</code></a></li>
<li><a
href="https://github.com/ericbuehl"><code>@​ericbuehl</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/AbhinavMir"><code>@​AbhinavMir</code></a></li>
<li><a
href="https://github.com/Whning0513"><code>@​Whning0513</code></a></li>
<li><a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.6</h2>
<p>Released on 2026-09-03.</p>
<h3>Preview features</h3>
<ul>
<li>Move <code>pytest-fixture-autouse</code> to the
<code>restriction</code> category (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28219">#28219</a>)</li>
<li>[<code>flake8-pytest-style</code>] Add an autofix for
<code>PT020</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27993">#27993</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Prevent fix loop between
<code>TID254</code> and <code>TID255</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28262">#28262</a>)</li>
<li>[<code>isort</code>] Exclude pragma comments from line length
calculation (<code>I001</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27313">#27313</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Validate unary expressions when parsing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28233">#28233</a>)</li>
<li>[<code>flake8-async</code>, <code>pylint</code>] Recognize
<code>builtins.open</code> (<code>ASYNC230</code>, <code>PLW1514</code>)
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28021">#28021</a>)</li>
<li>[<code>flake8-bugbear</code>] Fix panic on <code>match</code>
subjects (<code>B031</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27781">#27781</a>)</li>
<li>[<code>flake8-datetimez</code>] Reject <code>tzinfo=None</code> for
<code>datetime</code> bounds (<code>DTZ901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28022">#28022</a>)</li>
<li>[<code>flake8-pytest-style</code>] Avoid duplicate
<code>PT017</code> diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27918">#27918</a>)</li>
<li>[<code>ruff</code>] Remove <code>lint.external</code> hint for
Ruff-specific suppressions (<code>RUF102</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27923">#27923</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-use-pathlib</code>] Add display-only fix for
<code>os.listdir</code> (<code>PTH208</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28027">#28027</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add another example and glob reference for
<code>lint.per-file-ignores</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28106">#28106</a>)</li>
<li>Add duplicate work guidance (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28229">#28229</a>)</li>
<li>[<code>flake8-async</code>] Document thread offloading
(<code>ASYNC240</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28008">#28008</a>)</li>
<li>[<code>pyupgrade</code>] Clarify default <code>encoding</code>
argument handling (<code>UP012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27315">#27315</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Allow unary plus in match patterns on Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28231">#28231</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/flying-sheep"><code>@​flying-sheep</code></a></li>
<li><a
href="https://github.com/pikammmmm"><code>@​pikammmmm</code></a></li>
<li><a href="https://github.com/fly1d"><code>@​fly1d</code></a></li>
<li><a
href="https://github.com/waterWang"><code>@​waterWang</code></a></li>
<li><a
href="https://github.com/Pierre-Sassoulas"><code>@​Pierre-Sassoulas</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/jelle-openai"><code>@​jelle-openai</code></a></li>
<li><a
href="https://github.com/ericbuehl"><code>@​ericbuehl</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/AbhinavMir"><code>@​AbhinavMir</code></a></li>
<li><a
href="https://github.com/Whning0513"><code>@​Whning0513</code></a></li>
<li><a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/22f65a2ab5052990503985c7c794de37598d531e"><code>22f65a2</code></a>
Bump 0.16.6 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28280">#28280</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/7cc9f1ed53e5ce175f17fde3a75fe792ac41e8cd"><code>7cc9f1e</code></a>
[ty] Document <code>CallableTypeKind</code> variants (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28277">#28277</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/056ce07a895c217dab7929a616540c246cf8a078"><code>056ce07</code></a>
Add UV_LOCKED to all workflows (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28261">#28261</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6d6e35d03a72d23d3b0f23fb348692b03c9b81b6"><code>6d6e35d</code></a>
[<code>flake8-pytest-style</code>] Avoid duplicate <code>PT017</code>
diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27918">#27918</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/80b4891b64cb916dce080e8fa15af5c2179d776a"><code>80b4891</code></a>
[ty] Temporarily disable tuple types in property tests (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28275">#28275</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/3f7a54d1d7b9480a18d86a8211bf676354a2f8a0"><code>3f7a54d</code></a>
[<code>flake8-tidy-imports</code>] Prevent fix loop between
<code>TID254</code> and <code>TID255</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28262">#28262</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/35656cf37d34f30116d4f4a9cb13853a6ad9fd0d"><code>35656cf</code></a>
[ty] Preserve deprecations on decorated callables (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28256">#28256</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d2626c866ee08495cfa0da5236e130030d37e0cf"><code>d2626c8</code></a>
[ty] Reject missing attributes on <code>type[]</code> aliases (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28267">#28267</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ee6a6d19aa0707df942febe9768488d39f383c8c"><code>ee6a6d1</code></a>
[ty] Support ParamSpecs in <code>ConstraintSet</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28028">#28028</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/7f6a170080dab08f754ef086369a2623c70f753d"><code>7f6a170</code></a>
[ty] Move bound APIs to constraint owners (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28094">#28094</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.5...0.16.6">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 00:20:11 -04:00
Nicholas Velten 46d21cafbc Deep-link Search By mode via URL hash (#1311)
Closes #1228.

Search By mode (General/Author/Title/Series/Manual), content type and
the search query now live in the URL as a hash fragment, updated live as
you search, not just parsed once on load. A shared/bookmarked link like
`#search_by=manual&q=foundation` reopens in that exact mode with the
query filled in.

Following the direction from the issue thread:
- Hash fragment instead of query string, so it stays browser side only.
- Live updates via `history.replaceState`, no history spam per
keystroke.
- Default Search By persisted in a client side cookie as fallback when
there's no hash, no user accounts needed.

Tested manually against a local build (search-by switching, hash live
update, deep link reload, cookie fallback when there's no hash, and hash
overriding a stale cookie).
2026-09-05 01:13:59 -04:00
dependabot[bot] 22aa59e567 build(deps): bump the docker-base-image-digests group with 2 updates (#1306)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps the docker-base-image-digests group with 2 updates: node and
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `node` from `d32cdf6` to `e67514e`

Updates `astral-sh/uv` from 0.12.5 to 0.12.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.12.9</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-01.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21413">#21413</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/21415">#21415</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--no-locked</code> and <code>--no-frozen</code> to disable
lock modes enabled by <code>UV_LOCKED</code> and <code>UV_FROZEN</code>
for a single invocation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21408">#21408</a>)</li>
<li>Report the exact command-line lock-mode flag in warnings and errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21402">#21402</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up cold wheel installs by extracting each streaming ZIP
archive in a single blocking task and reusing buffers across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21372">#21372</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Update <code>async_http_range_reader</code> to 0.11.1 to address a
potential memory-safety issue when reading metadata ranges from
untrusted wheels (<a
href="https://redirect.github.com/astral-sh/uv/pull/21401">#21401</a>)</li>
<li>Remove sensitive headers when redirects cross authentication realms,
including same-host redirects that change URL schemes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21382">#21382</a>)</li>
<li>Redact secrets in signed URLs from retry diagnostics, including
nested request errors (<a
href="https://redirect.github.com/astral-sh/uv/pull/21381">#21381</a>)</li>
<li>Give <code>--locked</code>, <code>--frozen</code>,
<code>--check</code>, and <code>--check-exists</code> precedence over
conflicting <code>UV_LOCKED</code> and <code>UV_FROZEN</code> values (<a
href="https://redirect.github.com/astral-sh/uv/pull/21396">#21396</a>)</li>
<li>Prevent concurrent uv processes from redundantly extracting the same
local or source-built wheel (<a
href="https://redirect.github.com/astral-sh/uv/pull/21400">#21400</a>)</li>
</ul>
<h2>Install uv 0.12.9</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-installer.ps1
| iex&quot;
</code></pre>
<h2>Download uv 0.12.9</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-apple-darwin.tar.gz">uv-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-apple-darwin.tar.gz">uv-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-pc-windows-msvc.zip">uv-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-i686-pc-windows-msvc.zip">uv-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-pc-windows-msvc.zip">uv-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-unknown-linux-gnu.tar.gz">uv-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.9</h2>
<p>Released on 2026-09-01.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21413">#21413</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/21415">#21415</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--no-locked</code> and <code>--no-frozen</code> to disable
lock modes enabled by <code>UV_LOCKED</code> and <code>UV_FROZEN</code>
for a single invocation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21408">#21408</a>)</li>
<li>Report the exact command-line lock-mode flag in warnings and errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21402">#21402</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up cold wheel installs by extracting each streaming ZIP
archive in a single blocking task and reusing buffers across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21372">#21372</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Update <code>async_http_range_reader</code> to 0.11.1 to address a
potential memory-safety issue when reading metadata ranges from
untrusted wheels (<a
href="https://redirect.github.com/astral-sh/uv/pull/21401">#21401</a>)</li>
<li>Remove sensitive headers when redirects cross authentication realms,
including same-host redirects that change URL schemes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21382">#21382</a>)</li>
<li>Redact secrets in signed URLs from retry diagnostics, including
nested request errors (<a
href="https://redirect.github.com/astral-sh/uv/pull/21381">#21381</a>)</li>
<li>Give <code>--locked</code>, <code>--frozen</code>,
<code>--check</code>, and <code>--check-exists</code> precedence over
conflicting <code>UV_LOCKED</code> and <code>UV_FROZEN</code> values (<a
href="https://redirect.github.com/astral-sh/uv/pull/21396">#21396</a>)</li>
<li>Prevent concurrent uv processes from redundantly extracting the same
local or source-built wheel (<a
href="https://redirect.github.com/astral-sh/uv/pull/21400">#21400</a>)</li>
</ul>
<h2>0.12.8</h2>
<p>Released on 2026-08-31.</p>
<h3>Enhancements</h3>
<ul>
<li>Warn about invalid tool directories and continue upgrading valid
tools with <code>uv tool upgrade --all</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21368">#21368</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Deduplicate identical files within and across cached wheels with the
<code>content-addressed-cache</code> preview feature (<a
href="https://redirect.github.com/astral-sh/uv/pull/21327">#21327</a>)</li>
<li>Reduce allocations while extracting content-addressed wheels by
reusing the hashing buffer across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21340">#21340</a>)</li>
<li>Speed up content-addressed cache cleanup on macOS by reading
hard-link counts in bulk (<a
href="https://redirect.github.com/astral-sh/uv/pull/21344">#21344</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Prevent concurrent uv processes from downloading and extracting the
same remote wheel more than once (<a
href="https://redirect.github.com/astral-sh/uv/pull/21379">#21379</a>)</li>
<li>Speed up dependency graph construction from large lockfiles by
indexing packages during traversal (<a
href="https://redirect.github.com/astral-sh/uv/pull/21373">#21373</a>)</li>
<li>Extend indexed lockfile traversal to exports, dependency trees,
audits, and freshness checks (<a
href="https://redirect.github.com/astral-sh/uv/pull/21377">#21377</a>)</li>
<li>Speed up warm resolutions by reducing repeated marker interner work
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21300">#21300</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Do not trust hashes from direct URLs discovered only in wheel
metadata when installing with <code>--require-hashes</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21348">#21348</a>)</li>
<li>Use a compatible Azure Storage API version for anonymous and
authenticated requests, allowing credential retries when public access
is disabled (<a
href="https://redirect.github.com/astral-sh/uv/pull/21366">#21366</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/9f928602938ac5cf1cd6b294a725833c16f5720e"><code>9f92860</code></a>
Bump version to 0.12.9 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21422">#21422</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/29c546228ed6ba8970bb063960c9a767fae19236"><code>29c5462</code></a>
Skip invalid scripts in <code>uv workspace list --scripts</code> (<a
href="https://redirect.github.com/astral-sh/uv/issues/21416">#21416</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/bf1d7e8049017a363565185a7df7e86f33041452"><code>bf1d7e8</code></a>
Encapsulate wheel extraction directory ownership (<a
href="https://redirect.github.com/astral-sh/uv/issues/21419">#21419</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6dacee042f58cea9184267ffb70c6960582bb210"><code>6dacee0</code></a>
Run streaming ZIP extraction in a blocking task (<a
href="https://redirect.github.com/astral-sh/uv/issues/21372">#21372</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/91d1ebf1b4ea1fc00928b412a9da23639aacb086"><code>91d1ebf</code></a>
Sync latest Python releases (<a
href="https://redirect.github.com/astral-sh/uv/issues/21415">#21415</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6a61ddb2c094ab44e55a2cc5bb4a88b7c08d733a"><code>6a61ddb</code></a>
Revert &quot;Limit CI planner checkout depth&quot; (<a
href="https://redirect.github.com/astral-sh/uv/issues/21414">#21414</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/e9d1816b538468e7deb8f267f28775007706b866"><code>e9d1816</code></a>
Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21413">#21413</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/e888329afc22fa3e34f93d5ae5e23fbc87328952"><code>e888329</code></a>
Remove unreachable lock configuration sources (<a
href="https://redirect.github.com/astral-sh/uv/issues/21409">#21409</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/bf041f9245952ba7c9e3c29aebe0a8acc2bc983d"><code>bf041f9</code></a>
Allow negating locked and frozen modes (<a
href="https://redirect.github.com/astral-sh/uv/issues/21408">#21408</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/feffc0b5bbf8aeca1dff4a6f042a58e44a5daf09"><code>feffc0b</code></a>
Bump async_http_range_reader to 0.11.1 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21401">#21401</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.12.5...0.12.9">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-04 11:03:26 -04:00
dependabot[bot] b317dd1110 build(deps): bump python from cae66f2 to cad9a2c (#1307)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps python from `cae66f2` to `cad9a2c`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.7-slim&new-version=3.14.7-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-04 11:03:15 -04:00
dependabot[bot] 223d8a2256 build(deps): bump the npm-deps group in /src/frontend with 4 updates (#1308)
Bumps the npm-deps group in /src/frontend with 4 updates:
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom),
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node),
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
and [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip).

Updates `react-router-dom` from 7.18.2 to 7.18.3
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/react-router-dom@7.18.3/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.18.3</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.18.3"><code>react-router@7.18.3</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/23166dfe7f61323f0d2775af67d2691f9ed0843d"><code>23166df</code></a>
Release v7.18.3 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15424">#15424</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.18.3/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 26.3.0 to 26.4.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.1.0 to 6.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/releases">@​vitejs/plugin-react's
releases</a>.</em></p>
<blockquote>
<h2>plugin-react@6.1.1</h2>
<h3>Add <code>compiler.logDiagnostics</code> option</h3>
<p>Recoverable React Compiler diagnostics are no longer logged by
default. Set <code>compiler.logDiagnostics</code> to <code>true</code>
to log them through Vite. Fatal diagnostics are always logged and fail
the transform.</p>
<h3>Respect environment sourcemap option for React Compiler transform
when <code>builder.sharedPlugins</code> is enabled (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1439">#1439</a>)</h3>
<p>The React Compiler transform was using the top-level sourcemap option
instead of the environment sourcemap option. This caused a problem when
the experimental <code>builder.sharedPlugins</code> was enabled.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.1.1 (2026-08-28)</h2>
<h3>Add <code>compiler.logDiagnostics</code> option</h3>
<p>Recoverable React Compiler diagnostics are no longer logged by
default. Set <code>compiler.logDiagnostics</code> to <code>true</code>
to log them through Vite. Fatal diagnostics are always logged and fail
the transform.</p>
<h3>Respect environment sourcemap option for React Compiler transform
when <code>builder.sharedPlugins</code> is enabled (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1439">#1439</a>)</h3>
<p>The React Compiler transform was using the top-level sourcemap option
instead of the environment sourcemap option. This caused a problem when
the experimental <code>builder.sharedPlugins</code> was enabled.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/04cac5020e349f452d76c5a4f6d788ad4b38930a"><code>04cac50</code></a>
release: plugin-react@6.1.1 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1440">#1440</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/82d35abe4946eddd4e6456802bf2b53444e264f2"><code>82d35ab</code></a>
fix(react): respect environment sourcemap option when
<code>builder.sharedPlugins</code>...</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/397e8471a559f18a16dd21bd797ac01a369dabdc"><code>397e847</code></a>
fix(react): make logging diagnostics an opt-in for React Compiler (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1431">#1431</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/61006e6f52124821c24121a78712f7162ae36f5b"><code>61006e6</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1433">#1433</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/e2a649cbaa7334d6991f843563683975667e1be1"><code>e2a649c</code></a>
chore: use <code>deps.neverBundle</code> instead of
<code>external</code> in tsdown config (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1430">#1430</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/fb2d6f3635acbb0f3acbd0e9a914f6c620460957"><code>fb2d6f3</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1427">#1427</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.1/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.32.2 to 6.34.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.34.0</h2>
<ul>
<li>fix: report types used only in private parameters (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1950">#1950</a>)
(3c785f55ce608d7921e37e41dd5fc61b623e5da2)</li>
<li>💡 Add support for <code>node:fs/promises</code> <code>glob</code>
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1977">#1977</a>)
(44faf08e7f56ce695d1541a6c337b76bea0328d1) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>Respect JSDoc tags on URL dependencies (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1943">#1943</a>)
(f93ad0997e1b8fc644f6487df52803cba6f7a9ad)</li>
<li>Make prop access consistent while at it
(1c90b49b1b196795df6dcf9d7e85bc1b1399667a)</li>
<li>Set an explicit Bun test timeout
(964085dfab0165db2658e51cb787e2301886f9ce)</li>
<li>Add note re. one scoped PRs
(8f9490a581874e0fd7246e60223b20938bf4ebb1)</li>
<li>fix(cli): validate numeric options instead of passing NaN through
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1975">#1975</a>)
(ab90e2428a16ff50fe5323ce73172f6f1efb9730) - thanks <a
href="https://github.com/devYRPauli"><code>@​devYRPauli</code></a>!</li>
<li>fix: compile files with workspace-scoped compilers (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1997">#1997</a>)
(462ae45df33a5ee2e2185f3b2db756b13dfbadd3) - thanks <a
href="https://github.com/gioboa"><code>@​gioboa</code></a>!</li>
<li>Resolve Nuxt <code>#shared</code> imports from the shared directory
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1991">#1991</a>)
(cc470611042b01761491c21f6987549db4c11df8) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>Update dependencies (c4e0f082fbd7fb508a411c7dd0a782ea4556527c)</li>
<li>Declare webpack directly instead of through
<code>@types/webpack</code>
(96ff2df58dd1d229d077212e1cd80f10889650ca)</li>
<li>Assert counters in targeted regression tests
(f0cf11dfcfbdeac053bba0dd12212356a67f6464)</li>
</ul>
<h2>Release 6.33.0</h2>
<ul>
<li>Support package manifest resolution under Yarn PnP (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1946">#1946</a>)
(a82efb62b290e004bdabee40bcb337baf3701a1b) - thanks <a
href="https://github.com/WooWan"><code>@​WooWan</code></a>!</li>
<li>Resolve oxlint jsPlugins from .oxlintrc.jsonc (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1973">#1973</a>)
(d055023182789555a574eaefde80dac997190437) - thanks <a
href="https://github.com/DreierF"><code>@​DreierF</code></a>!</li>
<li>Update dependency bun to v1.4.0 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1964">#1964</a>)
(937ab38ad514a00edafecff4ca04603b015bf921) - thanks <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot]!</li>
<li>Expose <code>defineConfig</code> on a <code>./config</code>
entrypoint (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1960">#1960</a>)
(17f7a6051d9781860f248cc2a745dbe837713cd9) - thanks <a
href="https://github.com/theRizwan"><code>@​theRizwan</code></a>!</li>
<li>Preserve all environment variables in exec.ts (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1979">#1979</a>)
(c0a9ecf8d1c0cdd7789c1e1bea893706c060239d) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>Add support for TypeScript content mappers (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1978">#1978</a>)
(db67f9bd8cebf0ea3c298690d462c154827aa462) - thanks <a
href="https://github.com/remcohaszing"><code>@​remcohaszing</code></a>!</li>
<li>fix(vitest): resolve array entries and root-relative setup
dependencies (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1982">#1982</a>)
(0ecf48538c339437e6f9dfe9a6013d307783cbd3) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>Fix type annotation in dynamic configuration function example
(ada88c7f01563b73643af34a147a71fd9ab9d2dc)</li>
<li>Format docs with remark
(7764c2a4ebecdbf226c19494d255d9cb14550822)</li>
<li>Throw on configuration that is not an object
(d7ac0cf1de8f79be6ec53412cac9f7edf8f35ba7)</li>
<li>Clarify dependency inputs, isTypeOnly and toConfig in plugin docs
(2bd367961554ad1addb520bdfad5e31125885969)</li>
<li>Resolve content mapper process from
package.json#typescript.contentMapper.exec
(74640c03e450624409692f4cc17699775108fd7e)</li>
<li>Encode argv arrays before parsing them as shell commands
(b79234c15153fbf592e82c94e4e4e9f41b4479e0)</li>
<li>Update dependencies (28510146c2b97d88f7188f1239b9307aac7dbf0c)</li>
<li>Replace non-breaking space in module graph comment
(4e22bfcd09deccc92ed158f5554fe3e03f3a2c51)</li>
<li>Update fix format test for oxfmt package.json key sorting
(65011bf6054d03fb5580f3381867b07d1b8a9a0c)</li>
<li>fix(webpack): resolve entry descriptors using import field (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1981">#1981</a>)
(cad8910e7fb89c2510fc9f5885289335dd4e60da) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>fix: count enum element access as a whole-object read (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1958">#1958</a>)
(5a47d603aa23b388ae7ce4fe301656f1abc43b14) - thanks <a
href="https://github.com/addielaruee"><code>@​addielaruee</code></a>!</li>
<li>Resolve oxlint/vite-plus import resolvers from <code>settings</code>
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1983">#1983</a>)
(c1165b70efe27398b86fa50bcea7d85c253d3ee7) - thanks <a
href="https://github.com/DreierF"><code>@​DreierF</code></a>!</li>
<li>fix(nuxt): resolve string extends configs (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1984">#1984</a>)
(4a5d7068d6264ea45c78c832abe7ba052763517e) - thanks <a
href="https://github.com/DreamLongYT"><code>@​DreamLongYT</code></a>!</li>
<li>Wrap up webpack entry resolution
(505decdb821f9b76d194742cee7e98c75ef7d8e9)</li>
<li>Keep element access precise for number-like enum member names
(bcbac3a8b8283da3b32256584b3cc6569ae5c02f)</li>
<li>Resolve <code>Object.*</code> enum enumeration through import
aliases (347967daaed817ca20e1ad6148388a66ec8b421b)</li>
<li>Resolve named string-key access on namespace-qualified enums
(2ac1fbc1e92f3dae662ca4d4701cf010346be49a)</li>
<li>Normalize line endings in nuxt-config-string fixture
(9fe2b2b2db8690685ec7c6cf8b3d39b9ed7b3fdc)</li>
<li>Resolve nuxt layer sources from all <code>extends</code> entry
shapes (db136151d9f98801837b33646ef7b02ae7b5a86d)</li>
<li>Report unused exports behind Vitest module promise mocks (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1966">#1966</a>)
(74954c219367ca1577184cca08c30dbb3fb6222e)</li>
<li>Check line endings against <code>.gitattributes</code> in <code>pnpm
run ci</code> (ddc9fd0cc3328260665203c8573702bb6c9d0dd6)</li>
</ul>
<h2>Release 6.32.3</h2>
<ul>
<li>Update sentry production snapshot
(9f18cba93c91de8554636b13692d6e7a937b7697)</li>
<li>Pin TypeScript ecosystem test
(de5162952d223050f3135afb02d4e8de6d46f381)</li>
<li>Update query snapshot
(f6964dd577d8f7967f9be6778f5c3953632e3c96)</li>
<li>fix(tsup): match config files with .cts and .mts extensions (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1938">#1938</a>)
(68d6f52f7913cfa1e36618e6b03f90734da34149) - thanks <a
href="https://github.com/codeAnqiang-ma"><code>@​codeAnqiang-ma</code></a>!</li>
<li>fix(lefthook): match all config file names and extensions (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1940">#1940</a>)
(4015ae0330c78e97360a2c8f697d17f82c5c24ae) - thanks <a
href="https://github.com/codeAnqiang-ma"><code>@​codeAnqiang-ma</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/4ffebb746c630147c5d94c14da0bafb60af3c027"><code>4ffebb7</code></a>
Release knip@6.34.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f0cf11dfcfbdeac053bba0dd12212356a67f6464"><code>f0cf11d</code></a>
Assert counters in targeted regression tests</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/96ff2df58dd1d229d077212e1cd80f10889650ca"><code>96ff2df</code></a>
Declare webpack directly instead of through
<code>@types/webpack</code></li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c4e0f082fbd7fb508a411c7dd0a782ea4556527c"><code>c4e0f08</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/cc470611042b01761491c21f6987549db4c11df8"><code>cc47061</code></a>
Resolve Nuxt <code>#shared</code> imports from the shared directory (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1991">#1991</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/462ae45df33a5ee2e2185f3b2db756b13dfbadd3"><code>462ae45</code></a>
fix: compile files with workspace-scoped compilers (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1997">#1997</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/ab90e2428a16ff50fe5323ce73172f6f1efb9730"><code>ab90e24</code></a>
fix(cli): validate numeric options instead of passing NaN through (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1975">#1975</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/964085dfab0165db2658e51cb787e2301886f9ce"><code>964085d</code></a>
Set an explicit Bun test timeout</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/1c90b49b1b196795df6dcf9d7e85bc1b1399667a"><code>1c90b49</code></a>
Make prop access consistent while at it</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f93ad0997e1b8fc644f6487df52803cba6f7a9ad"><code>f93ad09</code></a>
Respect JSDoc tags on URL dependencies (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1943">#1943</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.34.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-04 11:02:22 -04:00
dependabot[bot] 7b5853f35d build(deps): bump the gh-actions group with 3 updates (#1310)
Bumps the gh-actions group with 3 updates:
[github/codeql-action/init](https://github.com/github/codeql-action),
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
and
[github/codeql-action/analyze](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.37.8 to 4.37.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.9</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<ul>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and download the native <code>linux-arm64</code> CodeQL
bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/cdf488f595d80d6e07e03d4674febd5ab45fa938"><code>cdf488f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4107">#4107</a>
from github/update-v4.37.9-920ba7cd1</li>
<li><a
href="https://github.com/github/codeql-action/commit/7243f38558d187dde99730d224bb47aa26a95306"><code>7243f38</code></a>
Update changelog for v4.37.9</li>
<li><a
href="https://github.com/github/codeql-action/commit/920ba7cd1596037e042122c00381eb16b397d68e"><code>920ba7c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4106">#4106</a>
from github/update-bundle/codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/ecfa6e16817b8f490bc9a59baa391baf4fa3e3c2"><code>ecfa6e1</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/adcdf4a70d247343cf9c29e0f7a6658b51c3a2b1"><code>adcdf4a</code></a>
Update default bundle to codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/486fec2a3ea2626afcd8c7e9208b4f515078dd7e"><code>486fec2</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4099">#4099</a>
from github/update-supported-enterprise-server-versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/134624c67b20869c2aaa36dafa726375b78a5d76"><code>134624c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4101">#4101</a>
from github/dependabot/npm_and_yarn/npm-minor-457d82...</li>
<li><a
href="https://github.com/github/codeql-action/commit/ff43db8f982a368288f117354fb8d046e937124c"><code>ff43db8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4103">#4103</a>
from github/mergeback/v4.37.8-to-main-db488dde</li>
<li><a
href="https://github.com/github/codeql-action/commit/4605e03a74cf891614c4d76f82384a16c1c11816"><code>4605e03</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/099c869cad6bf3b88657154d4ae47ffed27e632d"><code>099c869</code></a>
Update changelog and version after v4.37.8</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.8 to 4.37.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.9</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<ul>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and download the native <code>linux-arm64</code> CodeQL
bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/cdf488f595d80d6e07e03d4674febd5ab45fa938"><code>cdf488f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4107">#4107</a>
from github/update-v4.37.9-920ba7cd1</li>
<li><a
href="https://github.com/github/codeql-action/commit/7243f38558d187dde99730d224bb47aa26a95306"><code>7243f38</code></a>
Update changelog for v4.37.9</li>
<li><a
href="https://github.com/github/codeql-action/commit/920ba7cd1596037e042122c00381eb16b397d68e"><code>920ba7c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4106">#4106</a>
from github/update-bundle/codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/ecfa6e16817b8f490bc9a59baa391baf4fa3e3c2"><code>ecfa6e1</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/adcdf4a70d247343cf9c29e0f7a6658b51c3a2b1"><code>adcdf4a</code></a>
Update default bundle to codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/486fec2a3ea2626afcd8c7e9208b4f515078dd7e"><code>486fec2</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4099">#4099</a>
from github/update-supported-enterprise-server-versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/134624c67b20869c2aaa36dafa726375b78a5d76"><code>134624c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4101">#4101</a>
from github/dependabot/npm_and_yarn/npm-minor-457d82...</li>
<li><a
href="https://github.com/github/codeql-action/commit/ff43db8f982a368288f117354fb8d046e937124c"><code>ff43db8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4103">#4103</a>
from github/mergeback/v4.37.8-to-main-db488dde</li>
<li><a
href="https://github.com/github/codeql-action/commit/4605e03a74cf891614c4d76f82384a16c1c11816"><code>4605e03</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/099c869cad6bf3b88657154d4ae47ffed27e632d"><code>099c869</code></a>
Update changelog and version after v4.37.8</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.8 to 4.37.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.9</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<ul>
<li>The CodeQL Action now supports CodeQL releases that are compatible
with Linux Arm64 and download the native <code>linux-arm64</code> CodeQL
bundle when available. <a
href="https://redirect.github.com/github/codeql-action/pull/4072">#4072</a></li>
</ul>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/cdf488f595d80d6e07e03d4674febd5ab45fa938"><code>cdf488f</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4107">#4107</a>
from github/update-v4.37.9-920ba7cd1</li>
<li><a
href="https://github.com/github/codeql-action/commit/7243f38558d187dde99730d224bb47aa26a95306"><code>7243f38</code></a>
Update changelog for v4.37.9</li>
<li><a
href="https://github.com/github/codeql-action/commit/920ba7cd1596037e042122c00381eb16b397d68e"><code>920ba7c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4106">#4106</a>
from github/update-bundle/codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/ecfa6e16817b8f490bc9a59baa391baf4fa3e3c2"><code>ecfa6e1</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/adcdf4a70d247343cf9c29e0f7a6658b51c3a2b1"><code>adcdf4a</code></a>
Update default bundle to codeql-bundle-v2.26.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/486fec2a3ea2626afcd8c7e9208b4f515078dd7e"><code>486fec2</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4099">#4099</a>
from github/update-supported-enterprise-server-versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/134624c67b20869c2aaa36dafa726375b78a5d76"><code>134624c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4101">#4101</a>
from github/dependabot/npm_and_yarn/npm-minor-457d82...</li>
<li><a
href="https://github.com/github/codeql-action/commit/ff43db8f982a368288f117354fb8d046e937124c"><code>ff43db8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4103">#4103</a>
from github/mergeback/v4.37.8-to-main-db488dde</li>
<li><a
href="https://github.com/github/codeql-action/commit/4605e03a74cf891614c4d76f82384a16c1c11816"><code>4605e03</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/099c869cad6bf3b88657154d4ae47ffed27e632d"><code>099c869</code></a>
Update changelog and version after v4.37.8</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-04 11:02:15 -04:00
Ama Senevirathneandamasen02 c18da92569 fix(postprocess): attach unmatched chaptered audio files to existing book group (#1176) (#1309)
### Summary
Fixes #1176

When downloading an audiobook with many chaptered tracks (e.g. 250+
`.flac` or `.mp3` files), indexer XML or release metadata often caps the
file list at ~100-110 entries. When the release extracts on disk,
`match_plan_to_files()` matched those first ~110 files to the planned
book group, while the remaining 140+ files fell into `unmatched` and
triggered fallback heuristic grouping.

Because heuristic grouping parsed the folder name (`Westwell - Hot &
Cold (2023)`) and stripped the series/author prefix, it generated a
second book titled `Hot & Cold` containing the remaining tracks,
resulting in two split book folders.

### Changes
- In `match_plan_to_files()`
(`shelfmark/download/postprocess/packs.py`), check `unmatched` files
before falling back to heuristic multi-book splitting.
- If an unmatched file is chaptered audio (`.flac`, `.mp3`, `.aac`,
etc.) and shares the directory with an existing book group, or if the
plan was a single-book plan, append it to that group instead of creating
a secondary book.
- Non-chaptered standalone books (e.g. `.m4b`, `.epub`) or files in
separate subfolders continue to fall back to heuristic grouping as
before.
- Added unit tests in `tests/download/test_packs.py` verifying:
1. Truncated track list in single folder properly appends remaining
chaptered tracks without splitting.
2. Single-book plan with multi-disc audio files (`CD1`/`CD2`) groups
together cleanly.
3. Multi-book packs with unmatched chaptered tracks route each track to
its respective book folder.

### Testing
Ran `uv run pytest tests/download/test_packs.py` and `uv run pytest
tests/core/test_processing_packs.py` (all passed cleanly). Checked type
annotations with `basedpyright` (0 errors) and formatting with `ruff`.

Co-authored-by: amasen02 <amasen02@users.noreply.github.com>
2026-09-04 11:01:55 -04:00
Jorge Lima 97d1bb0df4 fix(bypass): keep Anna's Archive's aa_ddg_check so clearance replays (#1305)
## What

Add `aa_ddg_check` to the cookie-store allowlist. One name, one test.

## Why

Every replay of stored clearance ends in the `?check=1` redirect loop,
so each search pays a fresh browser solve. On this instance (v1.3.15,
WireGuard egress, 0 VPN restarts across the traces) not one replay was
accepted in three days of DEBUG logs.

The `__ddg*` cookies are stored and replayed correctly. Anna's Archive
also sets a cookie of its own, `aa_ddg_check`, and its `?check=1` hop
only answers with the page when that cookie is present too. The
allowlist keeps `cf_*` and `__ddg*` names, so this one was never stored.

## Measured, same egress IP, cookies taken from one solve

| replayed | plain `requests` | `curl_cffi`, Chrome TLS fingerprint |
|---|---|---|
| filtered `__ddg*` only (current behaviour) | 302 → 302 → 302 … loop |
302 → 302 → 302 … loop |
| filtered + `__ddg8_/9_/10_` | loop | loop |
| filtered + `aa_ddg_check` | **302 → 200, real search page** | 302 →
200 |
| `aa_ddg_check` alone | 302 → 403 | — |

So the TLS fingerprint is not the problem, the per-check trio is not the
answer, and the cookie needs the `__ddg*` clearance next to it. Cookie
attributes as issued: domain `.annas-archive.gl`, path `/`, expiry 90
days. It is not bound to the query, and it is accepted with a stock
Python User-Agent.

## Through the real fetch path

Same process, `html_get_page`, the name allowlisted, three different
queries:

```
1st: solve expected         25.8s  bypass_calls=1  title='frankenstein shelley - search - an'  md5=True
2nd: other query             9.5s  bypass_calls=0  title='pride and prejudice austen - searc'  md5=True
3rd: third query             4.8s  bypass_calls=0  title='dracula stoker - search - anna's a'  md5=True
```

## Notes

- `tests/bypass/test_ddg_cookie_reuse.py` gains
`test_aa_check_cookie_is_stored`; its docstring table gains the row. The
bypass tests need seleniumbase to import and do not run on my macOS
host, so this leans on CI. `ruff check` and `ruff format --check` pass.
The logic was checked directly against `cookie_store` with the settings
registry stubbed.
- `__ddgmark_` carries a 24 h expiry, so the store's clearance is good
for about a day before the next solve, which is what a browser would see
too.
- Follow-up to #1286. Same instance, same method: DEBUG trace, then a
probe script inside the container.
2026-09-03 23:20:48 -04:00
Matt Van HornandMatt Van Horn 9f11e83e1f fix: keep polling queued Real-Debrid torrents (#1303)
Add `queued` to the existing set of non-terminal Real-Debrid torrent
states so `_handle_torrent_info` returns an in-progress `DownloadStatus`
and leaves the mutable download state eligible for subsequent polling.
Keep the change within the existing status-classification path rather
than introducing a new helper or changing the broader handling of
unknown statuses. The native Real-Debrid client currently treats the
documented `queued` torrent status as a terminal error because it is
absent from `_STATUS_DOWNLOADING`. This occurs after a torrent has been
added and its files selected, particularly for uncached torrents that
wait before downloading.

A torrent-info payload with `status: queued`, zero progress, and a
filename returns a non-complete `DownloadState.DOWNLOADING` result
rather than `DownloadState.ERROR`; After handling `queued`, the internal
download state remains non-terminal so a later status poll can be
processed instead of returning a cached error.

Fixes #1268

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-09-03 23:19:50 -04:00
dependabot[bot] b98c2cb83e build(deps): bump the python-deps group with 2 updates (#1302)
Bumps the python-deps group with 2 updates:
[authlib](https://github.com/authlib/authlib) and
[apprise](https://github.com/caronc/apprise).

Updates `authlib` from 1.7.2 to 1.8.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/authlib/authlib/releases">authlib's
releases</a>.</em></p>
<blockquote>
<h2>v1.8.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Prefer <code>id_token_signed_response_alg</code> client metadata to
guess algs by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/888">authlib/authlib#888</a></li>
<li>fix: Catch InvalidKeyIdError in RFC 9068 JWTBearerTokenValidator by
<a
href="https://github.com/liudonggalaxy"><code>@​liudonggalaxy</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/891">authlib/authlib#891</a></li>
<li>fix: make leeway configurable in JWTBearerTokenValidator by <a
href="https://github.com/mondi04"><code>@​mondi04</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/903">authlib/authlib#903</a></li>
<li>feat: add default jti claim to sign_jwt_bearer_assertion by <a
href="https://github.com/liudonggalaxy"><code>@​liudonggalaxy</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/897">authlib/authlib#897</a></li>
<li>fix(oauth): cast sub claim to string in JWTBearerTokenGenerator by
<a href="https://github.com/levinKaus"><code>@​levinKaus</code></a> in
<a
href="https://redirect.github.com/authlib/authlib/pull/911">authlib/authlib#911</a></li>
<li>Declare lower bounds for dependencies by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/912">authlib/authlib#912</a></li>
<li>feat(client): use httpx2 instead of httpx by <a
href="https://github.com/levinKaus"><code>@​levinKaus</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/909">authlib/authlib#909</a></li>
<li>Fix RFC7523 malformed claims handling by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/916">authlib/authlib#916</a></li>
<li>Fix httpx oauth1 binary form data by <a
href="https://github.com/shc261392"><code>@​shc261392</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/779">authlib/authlib#779</a></li>
<li>fix(starlette_client): remove default= keyword from config.get calls
by <a
href="https://github.com/aliaksei-protchanka"><code>@​aliaksei-protchanka</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/770">authlib/authlib#770</a></li>
<li>Added client_id parameter to AssertionClient by <a
href="https://github.com/vilmar-hillow"><code>@​vilmar-hillow</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/476">authlib/authlib#476</a></li>
<li>fix(oauth): save device credential with authenticated client id by
<a
href="https://github.com/arpitjain099"><code>@​arpitjain099</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/908">authlib/authlib#908</a></li>
<li>fix(oauth1): correct protocol name in InsecureTransportError
description by <a
href="https://github.com/RavSinghChandan"><code>@​RavSinghChandan</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/919">authlib/authlib#919</a></li>
<li>fix(client): client can be flexible with jwt's header by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/922">authlib/authlib#922</a></li>
<li>fix(oidc): omit claims when the value is None by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/923">authlib/authlib#923</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/mondi04"><code>@​mondi04</code></a> made
their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/903">authlib/authlib#903</a></li>
<li><a href="https://github.com/levinKaus"><code>@​levinKaus</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/911">authlib/authlib#911</a></li>
<li><a
href="https://github.com/aliaksei-protchanka"><code>@​aliaksei-protchanka</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/770">authlib/authlib#770</a></li>
<li><a
href="https://github.com/vilmar-hillow"><code>@​vilmar-hillow</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/476">authlib/authlib#476</a></li>
<li><a
href="https://github.com/arpitjain099"><code>@​arpitjain099</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/908">authlib/authlib#908</a></li>
<li><a
href="https://github.com/RavSinghChandan"><code>@​RavSinghChandan</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/919">authlib/authlib#919</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0">https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/authlib/authlib/commit/1a86748b31a2b1940b09cf627d1b70e03d85c077"><code>1a86748</code></a>
chore: release 1.8.0</li>
<li><a
href="https://github.com/authlib/authlib/commit/e4fb941d4959a11e875b34880c41f46ba7cd8c67"><code>e4fb941</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/923">#923</a>
from authlib/fix-921</li>
<li><a
href="https://github.com/authlib/authlib/commit/9f2cd2e4c8c2d88cd8c7831d2c612ad38a4b0958"><code>9f2cd2e</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/922">#922</a>
from authlib/fix-902</li>
<li><a
href="https://github.com/authlib/authlib/commit/5d53239e8a0ca7ea1c241e84bfd5fd453203a94a"><code>5d53239</code></a>
fix(oidc): omit claims when the value is None</li>
<li><a
href="https://github.com/authlib/authlib/commit/772bc72fe8440e6c5dd0a6615fb42d7466f85546"><code>772bc72</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/919">#919</a>
from RavSinghChandan/fix-oauth1-insecure-transport-de...</li>
<li><a
href="https://github.com/authlib/authlib/commit/11794b00375127bbc4397e7ebd46e047c3935b64"><code>11794b0</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/908">#908</a>
from arpitjain099/chore/device-cred-authenticated-cli...</li>
<li><a
href="https://github.com/authlib/authlib/commit/13f2eb0589cec6df53c4e1146b11dc0cdd3012c7"><code>13f2eb0</code></a>
fix(client): Added client_id parameter to AssertionClient (<a
href="https://redirect.github.com/authlib/authlib/issues/476">#476</a>)</li>
<li><a
href="https://github.com/authlib/authlib/commit/dde5b7a8015904aba63dad76d7286aa431249783"><code>dde5b7a</code></a>
fix(client): rollback</li>
<li><a
href="https://github.com/authlib/authlib/commit/e4aec8c5c1e333951f49ba6aa3fe7487c6fce670"><code>e4aec8c</code></a>
fix(client): remove default= keyword from starlette client config.get
calls (...</li>
<li><a
href="https://github.com/authlib/authlib/commit/62f41cc2f55c15e658f7a0d2bdcb23feeeb93410"><code>62f41cc</code></a>
fix(client): httpx oauth1 binary form data (<a
href="https://redirect.github.com/authlib/authlib/issues/779">#779</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/authlib/authlib/compare/v1.7.2...v1.8.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `apprise` from 1.13.0 to 1.13.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/caronc/apprise/releases">apprise's
releases</a>.</em></p>
<blockquote>
<h2>Release v1.13.1</h2>
<h2>What's Changed</h2>
<p>Just a small update to fix a small stability issue with Attachments
under some circumstances and the few PR's made by others in one more
small bundle.</p>
<p><strong>Note:</strong> ⚠️ <strong>This will be the last version of
Apprise v1.x</strong> (this time i mean it 😉 ) . Future releases
will be under Apprise v2.x. Again, I strongly want to urge Developers:
<em>please</em> make sure you pin your <code>projects.toml</code> or
<code>requirements.txt</code> to <code>apprise &gt;=1.0.0,
&lt;2.0.0</code>. v2.x will be awesome, but it WILL introduce breaking
changes your software may need to adapt to. I will still continue
supporting the v1.x branch should security issues arise for at year or
two, but eventually v2.x would be the way to go.</p>
<h3>📣 New Notification Services:</h3>
<ul>
<li>Add Signalgrid notification service plugin by <a
href="https://github.com/signalgridco"><code>@​signalgridco</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1710">caronc/apprise#1710</a></li>
<li>Add Lauther notification support by <a
href="https://github.com/csanadymiklos"><code>@​csanadymiklos</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1715">caronc/apprise#1715</a></li>
</ul>
<h3>🐞  Bugfixes</h3>
<ul>
<li>Fixes Gento Linux issue with memory based attachment handling in <a
href="https://redirect.github.com/caronc/apprise/pull/1709">caronc/apprise#1709</a>
<ul>
<li>☝️ This is the core reason for this minor update</li>
</ul>
</li>
<li>Allow periods in Pingram API keys (JWT format) by <a
href="https://github.com/lipusal"><code>@​lipusal</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1714">caronc/apprise#1714</a></li>
<li>fixes intermittent test failures for matrix in <a
href="https://redirect.github.com/caronc/apprise/pull/1717">caronc/apprise#1717</a></li>
</ul>
<h3>💡 Features</h3>
<p>n/a</p>
<h3>❤️ Life-Cycle Support</h3>
<ul>
<li>Allow Py 3.13+, please by <a
href="https://github.com/milos-korenciak"><code>@​milos-korenciak</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1711">caronc/apprise#1711</a></li>
<li>fix(matrix): typofix in label by <a
href="https://github.com/arthurlutz"><code>@​arthurlutz</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1707">caronc/apprise#1707</a></li>
<li>docs: fix typo recomended -&gt; recommended by <a
href="https://github.com/vaibhav8a"><code>@​vaibhav8a</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1716">caronc/apprise#1716</a></li>
</ul>
<h2>Installation</h2>
<p>Apprise is available <a href="https://pypi.org/project/apprise/">on
PyPI</a> through <em>pip</em>:</p>
<pre lang="bash"><code># Install Apprise v1.13.1 from PyPI
pip install apprise==1.13.1
</code></pre>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/arthurlutz"><code>@​arthurlutz</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1707">caronc/apprise#1707</a></li>
<li><a
href="https://github.com/milos-korenciak"><code>@​milos-korenciak</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1711">caronc/apprise#1711</a></li>
<li><a href="https://github.com/vaibhav8a"><code>@​vaibhav8a</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1716">caronc/apprise#1716</a></li>
<li><a
href="https://github.com/signalgridco"><code>@​signalgridco</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1710">caronc/apprise#1710</a></li>
<li><a
href="https://github.com/csanadymiklos"><code>@​csanadymiklos</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1715">caronc/apprise#1715</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/caronc/apprise/compare/v1.13.0...v1.13.1">https://github.com/caronc/apprise/compare/v1.13.0...v1.13.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/caronc/apprise/commit/cf4da87eab713370a62d7a4f9ca64dcd3bffdf61"><code>cf4da87</code></a>
bumped version to v1.13.1</li>
<li><a
href="https://github.com/caronc/apprise/commit/0386b1cc093b3c55cfcebf4bdce17fc4309e0bd7"><code>0386b1c</code></a>
Add Lauther notification support (<a
href="https://redirect.github.com/caronc/apprise/issues/1715">#1715</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/3299eb37aa60ed729f935f039b79a9f9786e7424"><code>3299eb3</code></a>
Add Signalgrid notification support (<a
href="https://redirect.github.com/caronc/apprise/issues/1710">#1710</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/e05331ba9b5d2ace834b23e49728065ffebcb377"><code>e05331b</code></a>
relaxed some noisy logging</li>
<li><a
href="https://github.com/caronc/apprise/commit/8f73f6a0cdb83e6187624715a12e8f36dd8a1bbc"><code>8f73f6a</code></a>
Fixes intermittent test failures for matrix on py39 (<a
href="https://redirect.github.com/caronc/apprise/issues/1717">#1717</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/0af1bb2097dad2557f55a523d09269341fa3fdfb"><code>0af1bb2</code></a>
docs: fix typo recomended -&gt; recommended (<a
href="https://redirect.github.com/caronc/apprise/issues/1716">#1716</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/8df288a1824711bc6b1bdb59c1b5b356e4da3fd5"><code>8df288a</code></a>
Allow periods in Pingram API keys (JWT format) (<a
href="https://redirect.github.com/caronc/apprise/issues/1714">#1714</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/aa7221b7cabe757e000a1e6e019fc8f91ec517a0"><code>aa7221b</code></a>
Allow Py 3.13+ (<a
href="https://redirect.github.com/caronc/apprise/issues/1711">#1711</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/e93c9360c5ae2ed729a282bc454f6ceeb4abd9e1"><code>e93c936</code></a>
Fixes Gento Linux issue with memory based attachment handling (<a
href="https://redirect.github.com/caronc/apprise/issues/1709">#1709</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/4e6f4b117fa356f7ba0a076080c4927fcf78bc47"><code>4e6f4b1</code></a>
typofix in matrix:// label (<a
href="https://redirect.github.com/caronc/apprise/issues/1707">#1707</a>)</li>
<li>See full diff in <a
href="https://github.com/caronc/apprise/compare/v1.13.0...v1.13.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 01:14:41 -04:00
CaliBrain 9452ebc70d fix(bypass): stop handing solvers DDoS-Guard's ?check=1 probe URL (#1300)
html_get_page follows Anna's Archive redirects by hand, and DDoS-Guard's
gate
answers /search with a 302 to the same path plus `check=1`. The follower
walks
that handshake by reassigning `current_url`, so every downstream handoff
- the
403 branch, the 503-challenge branch, both redirect-loop rescues -
passed the
*probe* URL to the bypasser rather than the page we actually wanted.

A solver opens that in a fresh browser holding none of the cookies the
probe
exists to collect, so DDoS-Guard cannot verify it automatically and
serves the
manual CAPTCHA page that nothing can solve. The #1292 log is exactly
that: a 403
handed off on `&check=1`, FlareSolverr answering "Challenge solved!",
and a
4721-byte DDOS-GUARD captcha page coming back.

- `_solvable_url()` strips the probe parameter, applied at the single
choke point
in `_run_bypasser` so all four handoffs are covered. Scoped to the hosts
whose
redirects we follow manually; a URL without the parameter is returned by
  identity, so nothing else is re-encoded.

The same reports showed three further defects, all of which stand
whatever the
host was reacting to:

- The external bypasser logged that the solve had not cleared the
protection and
then returned the challenge page as a success. That skipped the one
recovery
left - get_bypassed_page's retry-and-rotate loop, where the next mirror
is a
different DDoS-Guard host - and filed the captcha page's own __ddg
cookies as
that host's clearance, to be replayed on every later request. It now
raises
  ChallengeNotSolvedError before storing anything.

- "Check that the bypasser is reachable and working" was the one piece
of advice
guaranteed to waste the reporter's time: it was reachable, it ran a full
solve,
and it returned a captcha. ChallengeNotSolvedError carries the marker so
the
  search layer can name the host as the cause instead of the bypasser.

- The untabled-page fingerprint logged `attempt_url`, which
html_get_page has
since rotated past. The #1298 bundle reported the page against
annas-archive.gl
when the body had come from .pk - the triage cost #1289 added the line
to
remove. The search now asks for the response URL and logs that. Its
give-up
shape is the tuple ("", url), which is truthy, so the exhaustion check
reads
  the body rather than the response.

Regression fixtures are built from the pages in the reports. The two
behavioural
handoff tests were checked against the unfixed code: both fail there,
reproducing
the reporter's log line verbatim.

Refs #1292
Refs #1298
2026-09-02 16:12:52 -04:00
CaliBrain d3f4ccd79a seleniumbase==4.53.5 (#1299)
replaces #1296
2026-09-02 15:48:48 -04:00
CaliBrain cb690b45b8 fix(prowlarr): rank releases by author instead of querying for it (#1293) (#1295)
MyAnonamouse is the only indexer Shelfmark treats as enriched, and it
alone was sent {title} {author} while every other indexer got the title
on its own. MAM matches all search terms conjunctively, so whenever the
metadata provider spelled the author differently to the tracker -
Hardcover says Timothy Ferriss, MAM lists Tim Ferriss - the search came
back empty and the UI reported No releases found for this book, with the
release sitting on the tracker the whole time.

The enriched flag is a statement about responses: MAM returns clean
author and bookTitle attributes, which is why it earns format detection
and preferential ordering. Using that same flag to shape the request is
the actual defect, and it is why turning the flag off recovers the
search but takes format detection down with it.

So the query is title-only for every indexer now, and the author orders
the results rather than narrowing them. MAM already hands us its author
field, so agreement is judged on data we hold instead of by an AND we
cannot control. The ranking is three-way on purpose - agrees, no
metadata, disagrees - so an indexer reporting no author does not sort
below one reporting the wrong author.

A wrong verdict costs a release its position, never its visibility: a
transliteration such as Dostoevsky against Dostoyevsky sorts last
instead of vanishing. That is what makes the loose token comparison safe
to ship without a tuning knob.

Falling back to a title-only query on zero results was the alternative.
It only rescues total failure - if two of six editions happen to use the
provider's spelling, the search returns those two, no fallback fires,
and the user quietly gets a truncated list. It also spends a round trip
inside the search deadline and stacks a retry on an indexer that may
still be solving a challenge (#1249).

Manual queries skip author ranking: they are the user's own words and
should not be reordered against the metadata they were typed to
override.
2026-09-01 12:59:33 -04:00
CaliBrain 3d7ea40088 fix(search): reach the server's deadline, query one author (#1285, #1252) (#1287)
Two independent reasons a working search reported failure to the user.

1. The client gave up before the server did (#1285)

`/api/releases` bounds one release search with RELEASE_SEARCH_TIMEOUT
(default
300s) and answers a spent budget with a sentence naming the real cause -
the
machinery added for #1276. The frontend then aborted the direct_download
search
at a hard-coded 180s, so it always won the race: the user saw "Request
timed
out. Check your network connection or proxy configuration." instead, and
raising RELEASE_SEARCH_TIMEOUT changed nothing they could observe, the
180s
being baked into the hashed bundle inside the image.

- /api/config reports the effective (clamped) budget, and the client
derives its
  abort from it plus a margin, so the server always answers first.
- Direct-mode search shows what the server actually said. Every non-auth
failure
was relabelled "Unable to reach download source. Network may be
restricted or
mirrors blocked.", which discarded the explanation and blamed the user's
network. ApiResponseError now carries `serverMessage`, set only when the
server
  explained itself, so the status-line placeholder still falls back.

Two latency fixes for the cost that made the timeout reachable at all:

- Fetch each distinct AA search URL once per search. The language-filter
retry
re-runs every title variant, and with DIRECT_DOWNLOAD_LANGUAGE_FROM_PATH
on
both passes build a byte-identical URL - behind DDoS-Guard each repeat
is a
  fresh browser solve.
- Drop the solve-only bypass method. `_bypass_method_cdp_gui_click`
opens with
exactly that call and returns the moment it works, so the entry ahead of
it
could only repeat the half that had already failed, plus the backoff
before
the method that does work started. Reported at 0/19 successes and ~5.5s
of
  each ~26s solve against DDoS-Guard.

2. The query carried every contributor, not one author (#1252)

`_pick_search_author` returned `book.search_author` verbatim while the
authors[]
fallback beside it deliberately narrowed to the first name before a
comma. Both
fields routinely arrive holding every contributor joined with ", ": the
frontend
builds `book.author` as `authors.join(', ')` for display
(bookTransformers.ts)
and the release modal sends that display string straight back as the
`author`
parameter, and `browse_record_to_book_metadata` and the manual-search
branch
both split the joined text into `authors` while still passing the
unsplit string
as `search_author`, so the split was never used.

A book whose metadata lists translators was therefore searched for as

    Blindness Jose Saramago, Giovanni Pontiero, <persian translator>

which matches nothing on Anna's Archive. The bypass succeeds, the search
comes
back empty, and the user is told the book has no releases.

Narrowed in one place, `search_plan.first_author`, so the two branches
cannot
drift apart again, and applied to the IRC source, which built its query
with the
same verbatim preference. Hardcover is unaffected: it already sets
`search_author` from `_simplify_author_for_search(authors[0])`, which
resolves
"Last, First" itself and never yields a multi-author string.
2026-09-01 12:38:57 -04:00
CaliBrain 633004ecf0 fix(search): stop reading real Anna's Archive pages as unsolved challenges (#1294)
`_looks_like_challenge_page` substring-matched "ddos-guard"/"cloudflare"
over
the whole document. DDoS-Guard-fronted sites carry those strings on
their own
pages - Anna's Archive ships a `DDOS-GUARD` comment in the inline JS it
serves
on every page - so every real AA response that was not a results table
was
reported as an unsolved protection challenge, sending users off to fix a
bypasser that had just succeeded.

Measured against live pages: a served AA page (HTTP 200) is 182,685
bytes and
matched the old detector; the real interstitial is 902 bytes.

- `_looks_like_challenge_page` now delegates to the shared
`challenge_marker()`,
whose 64 KB cap is what separates a few-KB interstitial from the page
behind
it. `download/http.py` already used it; this module carried an unguarded
  private copy.
- `_looks_like_aa_page` is checked ahead of the challenge branch. A
genuine
interstitial carries no AA markers, so nothing actually blocked leaks
through.

Also adds the diagnostics whose absence made #1289 guesswork: the debug
bundle
carries no response bodies, so "unsolved protection challenge" and
FlareSolverr's
"Challenge solved!" were indistinguishable after the fact.

- `_log_untabled_search_page()` fingerprints the one ambiguous shape at
INFO -
size, size-cap verdict, AA markers, challenge marker - with a bounded
700-char
  head at DEBUG. Best-effort: it swallows its own errors.
- The external bypasser records what it actually returned, and warns
when it
  reports success while handing back a challenge page.

Regression tests use fixtures built from the live pages rather than
invented
ones; the previous fixtures were two-line synthetic pages with no
"ddos-guard"
substring, which is why nothing caught this.

Closes #1289
Closes #1292
2026-09-01 11:19:01 -04:00
dependabot[bot] c06b8ce8ef build(deps): bump the python-deps group with 3 updates (#1288)
Bumps the python-deps group with 3 updates:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase),
[prek](https://github.com/j178/prek) and
[ruff](https://github.com/astral-sh/ruff).

Updates `seleniumbase` from 4.52.3 to 4.52.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.52.4 - Add Remote WebDriver Timeout setting</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cf4af2a92414010ca49c5ba14e59cf73dc8badea">Add
REMOTE_WEBDRIVER_TIMEOUT setting for Remote WebDriver HTTP
requests</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Add REMOTE_WEBDRIVER_TIMEOUT setting for Remote WebDriver HTTP
requests by <a
href="https://github.com/TaylorMcGinnis"><code>@​TaylorMcGinnis</code></a>
in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4473">seleniumbase/SeleniumBase#4473</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.3...v4.52.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.52.3...v4.52.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/5879697828e55a6c6ef8f7436c01023e3af92108"><code>5879697</code></a>
Version 4.52.4</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2182f3c9ece14ac0cc1d4fdb4c24470e0e0ac63e"><code>2182f3c</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4473">#4473</a>
from TaylorMcGinnis/remote-webdriver-timeout</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ffe06d572308b7cca77644dd22f7560dd3c4eda4"><code>ffe06d5</code></a>
Update GitHub Actions</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cf4af2a92414010ca49c5ba14e59cf73dc8badea"><code>cf4af2a</code></a>
Add REMOTE_WEBDRIVER_TIMEOUT setting for Remote WebDriver HTTP
requests</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.3...v4.52.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.14 to 0.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.5.0</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-27.</p>
<h3>Highlights</h3>
<h4>Choose where hook toolchains come from</h4>
<p><code>language_version</code> now accepts a source
<code>preference</code> alongside the version
<code>request</code>, letting you control where prek looks for a
compatible toolchain when
it creates a hook environment. Use <code>managed</code> (the default) or
<code>system</code> to choose
which source prek tries first while still allowing fallback and
downloads. Use
<code>only-managed</code> or <code>only-system</code> to require one
source.</p>
<p>For example, this local Ruff hook requires a Python 3.12 toolchain
managed by
prek:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: ruff
        name: ruff
        language: python
        entry: ruff check
        additional_dependencies: [ruff]
        language_version:
          request: &quot;3.12&quot;
          preference: only-managed
</code></pre>
<p>With <code>only-managed</code>, prek reuses a compatible toolchain
from its managed store
or downloads one when needed. It never falls back to Python from
<code>PATH</code>, an OS
package manager, or a version manager, so toolchain selection does not
depend on
the developer or CI machine's external environment.</p>
<p>Existing scalar values such as <code>language_version:
&quot;3.12&quot;</code> continue to work. See
<a
href="https://prek.j178.dev/0.5.0/languages/#toolchain-management-and-language_version">toolchain
management and <code>language_version</code></a>
for the full source-selection behavior. (<a
href="https://redirect.github.com/j178/prek/pull/2613">#2613</a>)</p>
<h3>Breaking changes</h3>
<p>The breaking changes in this release are mostly small cleanups, and
most users should not be affected.</p>
<ul>
<li>Group names can no longer start with <code>@</code>. This prefix is
now reserved for special group selectors such as the new
<code>@ungrouped</code> selector. (<a
href="https://redirect.github.com/j178/prek/pull/2617">#2617</a>)</li>
<li><code>PREK_MAX_CONCURRENCY</code> has been removed. Use
<code>PREK_CONCURRENT_HOOKS</code> and
<code>PREK_CONCURRENT_BATCHES</code> to control hook and per-hook batch
concurrency separately. (<a
href="https://redirect.github.com/j178/prek/pull/2620">#2620</a>)</li>
<li>The top-level <code>prek init-template-dir</code> command has been
removed. Use <code>prek util init-template-dir</code>, or <code>prek
init-templatedir</code> for drop-in compatibility with
<code>pre-commit</code>. (<a
href="https://redirect.github.com/j178/prek/pull/2623">#2623</a>)</li>
<li><code>prek auto-update</code> has been removed. Use <code>prek
update</code>, or <code>prek autoupdate</code> for drop-in compatibility
with <code>pre-commit</code>. (<a
href="https://redirect.github.com/j178/prek/pull/2619">#2619</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.5.0</h2>
<p>Released on 2026-08-27.</p>
<h3>Highlights</h3>
<h4>Choose where hook toolchains come from</h4>
<p><code>language_version</code> now accepts a source
<code>preference</code> alongside the version
<code>request</code>, letting you control where prek looks for a
compatible toolchain when
it creates a hook environment. Use <code>managed</code> (the default) or
<code>system</code> to choose
which source prek tries first while still allowing fallback and
downloads. Use
<code>only-managed</code> or <code>only-system</code> to require one
source.</p>
<p>For example, this local Ruff hook requires a Python 3.12 toolchain
managed by
prek:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: ruff
        name: ruff
        language: python
        entry: ruff check
        additional_dependencies: [ruff]
        language_version:
          request: &quot;3.12&quot;
          preference: only-managed
</code></pre>
<p>With <code>only-managed</code>, prek reuses a compatible toolchain
from its managed store
or downloads one when needed. It never falls back to Python from
<code>PATH</code>, an OS
package manager, or a version manager, so toolchain selection does not
depend on
the developer or CI machine's external environment.</p>
<p>Existing scalar values such as <code>language_version:
&quot;3.12&quot;</code> continue to work. See
<a
href="https://prek.j178.dev/0.5.0/languages/#toolchain-management-and-language_version">toolchain
management and <code>language_version</code></a>
for the full source-selection behavior. (<a
href="https://redirect.github.com/j178/prek/pull/2613">#2613</a>)</p>
<h3>Breaking changes</h3>
<p>The breaking changes in this release are mostly small cleanups, and
most users should not be affected.</p>
<ul>
<li>Group names can no longer start with <code>@</code>. This prefix is
now reserved for special group selectors such as the new
<code>@ungrouped</code> selector. (<a
href="https://redirect.github.com/j178/prek/pull/2617">#2617</a>)</li>
<li><code>PREK_MAX_CONCURRENCY</code> has been removed. Use
<code>PREK_CONCURRENT_HOOKS</code> and
<code>PREK_CONCURRENT_BATCHES</code> to control hook and per-hook batch
concurrency separately. (<a
href="https://redirect.github.com/j178/prek/pull/2620">#2620</a>)</li>
<li>The top-level <code>prek init-template-dir</code> command has been
removed. Use <code>prek util init-template-dir</code>, or <code>prek
init-templatedir</code> for drop-in compatibility with
<code>pre-commit</code>. (<a
href="https://redirect.github.com/j178/prek/pull/2623">#2623</a>)</li>
<li><code>prek auto-update</code> has been removed. Use <code>prek
update</code>, or <code>prek autoupdate</code> for drop-in compatibility
with <code>pre-commit</code>. (<a
href="https://redirect.github.com/j178/prek/pull/2619">#2619</a>)</li>
</ul>
<h3>Enhancements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/67f85359486c57b0fc145ae948283713bf33bf94"><code>67f8535</code></a>
Bump version to 0.5.0 (<a
href="https://redirect.github.com/j178/prek/issues/2631">#2631</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/4546befaacb22177be1a7590fb944cad0664ad73"><code>4546bef</code></a>
Remove legacy <code>init-template-dir</code> command (<a
href="https://redirect.github.com/j178/prek/issues/2623">#2623</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/e63bd4be1ead8c09effeac5c451c5efd94e1f643"><code>e63bd4b</code></a>
Remove hook marker schema 0 (<a
href="https://redirect.github.com/j178/prek/issues/2622">#2622</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/8c433ae73124cef61c390217e0163adbb6a17cd9"><code>8c433ae</code></a>
Remove config-tracking cache bootstrap (<a
href="https://redirect.github.com/j178/prek/issues/2621">#2621</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/62ca460aea7d5e24ca27e79cd1128ab91ce396c1"><code>62ca460</code></a>
Remove <code>PREK_MAX_CONCURRENCY</code> (<a
href="https://redirect.github.com/j178/prek/issues/2620">#2620</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/e2468eae017a0cb5e68fd54f96e6b66f5d6db598"><code>e2468ea</code></a>
Remove legacy update aliases (<a
href="https://redirect.github.com/j178/prek/issues/2619">#2619</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/795c3a46b3c1b20a343a5fe8ec0d1b9fea79ade9"><code>795c3a4</code></a>
Group run options in CLI help (<a
href="https://redirect.github.com/j178/prek/issues/2629">#2629</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/b27eb6edf4779994f4e484be605119291f858fc6"><code>b27eb6e</code></a>
Document prek run architecture (<a
href="https://redirect.github.com/j178/prek/issues/2630">#2630</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/7dd9aa9149854bb0a37bde6ed64e3d1b42c46fdb"><code>7dd9aa9</code></a>
Avoid persisting docs workflow credentials (<a
href="https://redirect.github.com/j178/prek/issues/2627">#2627</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/23815bdd83ce766e93647a98cfc091ec15b0d9ba"><code>23815bd</code></a>
Remove the <code>@builtin</code> group selector (<a
href="https://redirect.github.com/j178/prek/issues/2628">#2628</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.14...v0.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.4 to 0.16.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.5</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-27.</p>
<h3>Preview features</h3>
<ul>
<li>Allow rules without codes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28049">#28049</a>)</li>
<li>Introduce category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27666">#27666</a>)</li>
<li>Update preview default rules and categories (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27877">#27877</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-async</code>] Detect blocking generic HTTP requests
(<code>ASYNC210</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28024">#28024</a>)</li>
<li>[<code>flake8-datetimez</code>] Allow timezone-safe
<code>strptime</code> chains (<code>DTZ007</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28023">#28023</a>)</li>
<li>[<code>flake8-simplify</code>] Respect side effects in
<code>lambda</code> defaults (<code>SIM401</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28000">#28000</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix duplicated &quot;of&quot; in <code>ClientOptions</code> doc
comment (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27978">#27978</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document rule acceptance guidelines (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27910">#27910</a>)</li>
<li>Document the new category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27906">#27906</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a
href="https://github.com/jelle-openai"><code>@​jelle-openai</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/aarushkandukoori"><code>@​aarushkandukoori</code></a></li>
</ul>
<h2>Install ruff 0.16.5</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.5/ruff-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/ruff/releases/download/0.16.5/ruff-installer.ps1
| iex&quot;
</code></pre>
<h2>Download ruff 0.16.5</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.5</h2>
<p>Released on 2026-08-27.</p>
<h3>Preview features</h3>
<ul>
<li>Allow rules without codes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28049">#28049</a>)</li>
<li>Introduce category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27666">#27666</a>)</li>
<li>Update preview default rules and categories (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27877">#27877</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-async</code>] Detect blocking generic HTTP requests
(<code>ASYNC210</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28024">#28024</a>)</li>
<li>[<code>flake8-datetimez</code>] Allow timezone-safe
<code>strptime</code> chains (<code>DTZ007</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28023">#28023</a>)</li>
<li>[<code>flake8-simplify</code>] Respect side effects in
<code>lambda</code> defaults (<code>SIM401</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28000">#28000</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix duplicated &quot;of&quot; in <code>ClientOptions</code> doc
comment (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27978">#27978</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document rule acceptance guidelines (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27910">#27910</a>)</li>
<li>Document the new category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27906">#27906</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a
href="https://github.com/jelle-openai"><code>@​jelle-openai</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/aarushkandukoori"><code>@​aarushkandukoori</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/9e4938c4a60bed3e87a11ee1e1db1bd23f4d964a"><code>9e4938c</code></a>
Bump 0.16.5 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28110">#28110</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/aad0e909ef1390f4b2a3ba8aa0a67fb8ea5cbacd"><code>aad0e90</code></a>
Allow rules without codes (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28049">#28049</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/5fdab73c5052350400c36b08c5d7710210343bc4"><code>5fdab73</code></a>
Update preview default rules and categories (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27877">#27877</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/29c8e5b2d0a46eb7dc4ff11c1b0a0dc5ccea52e4"><code>29c8e5b</code></a>
Document rule acceptance guidelines (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27910">#27910</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/50a4d7fd106603a5616b01ac3bef3306252b248f"><code>50a4d7f</code></a>
Document the new category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27906">#27906</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ada87950ea188f882f69b7bd6e2213a9696e3ee2"><code>ada8795</code></a>
Introduce category selectors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27666">#27666</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d8947238863b61922bfc83f07edcc697c1cc07c0"><code>d894723</code></a>
[ty] Infer lambda parameters through callable type aliases (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28109">#28109</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/2685fdebbcf9938736fed8c45886a629f9c99a06"><code>2685fde</code></a>
[ty] Narrow functional enum members in <code>==</code> and
<code>match</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28103">#28103</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/efcffd2178ce62e9951a53d4c50cadc225a0cfec"><code>efcffd2</code></a>
[ty] Intersection simplifications with subtype-related generic
specialization...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/eb780488037504e11f145ed778654fd8a825028b"><code>eb78048</code></a>
[ty] Bump ecosystem-analyzer for HTML escaping (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28104">#28104</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.4...0.16.5">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 11:13:24 -04:00
Nicholas Velten 69ff0d6a78 fix: trim a credit list in search_author to the first name (#1290)
Fixes #1252 for the case in the second report.

`_pick_search_author` returns `search_author` untouched but trims
`authors[0]` to its first comma-separated name. So the same credit list
searches differently depending on which field carries it:

```
via authors[0]     -> "Blindness Jose Saramago"
via search_author  -> "Blindness Jose Saramago, Giovanni Pontiero, Zohreh Eftekhari"
```

Anna's Archive answers the second one with nothing. That is the query in
@theDoz12's log, and it explains the shape of the report: the bypass
succeeds, the search runs, and the UI still says no releases. Nothing in
the download path is broken, the query simply cannot match.

Measured against live AA on 1.3.14, same book, same source, only the
field carrying the author changed:

| query | releases |
| --- | --- |
| `Blindness Jose Saramago, Giovanni Pontiero, Zohreh Eftekhari` | 0 |
| `Blindness Jose Saramago` | 49 |
| `Blindness` | 50 |

With the patch the second form is produced from either field, and the
same search returns 49.

Three regression tests added, including one that asserts both fields
yield the same query. On `tests/core/test_search_plan.py` the run goes
from 5 failures to 3; the 3 that remain are the language tests, which
fail identically with and without this change on my machine.

Worth saying what this does not cover: the first report in that issue
ends with `Found 2 releases via ISBN` and still shows nothing, so that
one is a different fault further along. I could not reproduce it here.
2026-09-01 11:08:39 -04:00
Nathan H 3937ae119b feat(homepage): Always show controls (#1269)
I found using the main search menu frustrating. Often times, I would
type in what I want, then select the category, only for it to get
erased. And the menu closing over and over was distracting. So this PR
makes the buttons stick around permanently and it removes the search
field text changing with each button press.

Obviously, this is just what I want, but I figured I'd at least put a PR
up for it.

<img width="1017" height="423" alt="image"
src="https://github.com/user-attachments/assets/7b84fd69-d6d3-4749-842f-e04a6e792ccc"
/>
<img width="682" height="418" alt="image"
src="https://github.com/user-attachments/assets/82a251ee-cb4a-488f-b1ba-45fb2bb6714d"
/>
2026-09-01 10:51:49 -04:00
Jorge Lima d7fe28595c fix(bypass): wait for the solved page before reading its source (#1286)
Follow-up to #1276 with a measurement from the instance I reported
there. v1.3.13 solves the challenge again, but on my setup the solve was
being thrown away immediately afterwards:

```
19:26:08 Bypass successful using _bypass_method_cdp_gui_click
19:26:16 Bypass failed (attempt 1/10): TimeoutError: Time ran out while waiting for: {html}
```

`_get()` ends with `return await page.get_page_source()`, which is
`find("html", timeout=1)` in SeleniumBase. One second is enough for a
page that is already sitting on its content, but Anna's Archive answers
a cleared check with a redirect to the real page, so the document is not
there yet. The solve is discarded, the whole attempt restarts, and the
extra requests are what earn the 429 that `note_rate_limited()` then
parks the host for — 120 s, then 300 s.

## Change

`_read_page_source()` waits for the document itself, with a
`BYPASS_PAGE_SOURCE_TIMEOUT` setting (default 20 s, min 1, max 120) in
Direct Download → Cloudflare Bypass, next to the existing bypasser
timeouts.

## Measured on a live instance

I patched the wait in the running container (`find("html", timeout=1)` →
`timeout=20` in the installed seleniumbase, which is the same effect as
this PR) and re-ran the same searches on the same host, k3s behind a
Surfshark WireGuard exit, internal bypasser, v1.3.13:

| | 1 s wait | 20 s wait |
|---|---|---|
| `Time ran out while waiting for: {html}` | one per solve | none |
| 429 backoffs | 2 (120 s, then 300 s) | none |
| Search for a book AA has | 199 s and 200 s, both errored | 61 s, 2
epub releases |

A download after that took 5 s from LibGen, so the search was the whole
cost.

## Tests

Two tests in `tests/bypass/test_bypass_budgets.py`, the file already
covering #1276: a page that needs longer than a second still yields its
HTML, and `BYPASS_PAGE_SOURCE_TIMEOUT` overrides the default.

`uv run pytest tests/ --ignore=tests/e2e`: 2848 passed, 47 skipped. Ruff
check and format clean. The docs table is auto-generated, but running
`scripts/generate_env_docs.py` here rewrote unrelated entries (Newznab,
BOOK_LANGUAGE), so I added only the new entry by hand in the generator's
format rather than commit that churn.

One thing I could not judge from outside: whether 20 s is the right
default for hosts other than AA. It only costs anything when a solve
would otherwise be discarded, but I have measured it on one site.
2026-08-30 19:17:15 -04:00
dependabot[bot] 68c0e83330 build(deps): bump the python-deps group with 2 updates (#1277)
Bumps the python-deps group with 2 updates:
[gunicorn](https://github.com/benoitc/gunicorn) and
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `gunicorn` from 26.1.0 to 26.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/benoitc/gunicorn/releases">gunicorn's
releases</a>.</em></p>
<blockquote>
<h2>gunicorn 26.2.0</h2>
<p>Cleartext HTTP/2 lands, and an HTTP/2 security fix.</p>
<h2>Cleartext HTTP/2 (h2c)</h2>
<p><code>http2_cleartext</code> accepts <code>prior-knowledge</code>,
<code>upgrade</code>, <code>both</code> or <code>off</code> (the
default). Prior knowledge serves a connection that opens with the HTTP/2
preface; <code>upgrade</code> honours an HTTP/1.1 <code>Upgrade:
h2c</code> request. Both work on the
gthread, gevent and asgi workers.</p>
<p>This is for deployments where TLS is terminated by a proxy that
speaks HTTP/2
upstream, so the hop into gunicorn no longer drops to HTTP/1.1. Only
peers in
<code>forwarded_allow_ips</code> are considered; everyone else is served
HTTP/1.x exactly
as if the setting were off. Each mechanism is enabled separately, so
turning one
on does not turn the other on.</p>
<p>Do not expose a cleartext HTTP/2 port to the internet.</p>
<h2>Security</h2>
<p><code>HTTP2Request</code> built its headers straight from the stream,
so nothing the HTTP/1
path enforces applied over HTTP/2: the underscore and
<code>header_map</code> policy,
duplicate <code>Host</code> and <code>Content-Type</code>, control
characters in values, and the
<code>forwarded_allow_ips</code> trust gate. An untrusted client could
set <code>SCRIPT_NAME</code>
and forge <code>HTTP_*</code> entries in the WSGI environ, and decide
<code>wsgi.url_scheme</code>
through <code>:scheme</code>. Both request classes now share one policy
mixin, and the
scheme comes from the transport.</p>
<p>If you serve HTTP/2, this is the reason to upgrade.</p>
<h2>Other HTTP/2 fixes</h2>
<p>WSGI responses were buffered whole before anything was sent; they
stream now.
HEAD, 204 and 304 no longer carry a body. Events read while blocked on a
flow-control window were discarded, losing requests and body data
outright.
<code>sendfile()</code> is refused on HTTP/2 responses rather than
bypassing framing.</p>
<h2>Request bodies dropped on Upgrade requests</h2>
<p>On the ASGI worker with the fast parser, any request carrying an
<code>Upgrade</code>
header reached the application with an empty body, whatever the header's
value
and with HTTP/2 switched off entirely. Fixed in
<code>gunicorn_h1c</code> 0.6.9, which the
<code>fast</code> extra now requires.</p>
<p>Full changelog: <a
href="https://gunicorn.org/news/">https://gunicorn.org/news/</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/benoitc/gunicorn/commit/36f2a3c1b80dfa41d70859d12c5bfbbdc23a3c38"><code>36f2a3c</code></a>
gunicorn 26.2.0</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/cbba3505f423bfb91af3a87e49ed9d232f39a8fe"><code>cbba350</code></a>
test: cover the h2c edge paths that had none</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/988541112ebcf3f795c020fc394aa7eed75f9f53"><code>9885411</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3703">#3703</a>
from cormier/fix-inconsistency-in-control-socket-docs</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/86f0919806a2d4d4cce376cc2088352e7643b139"><code>86f0919</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3704">#3704</a>
from methane/doc-wsgi-h1c</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/585355122efe736946b977c5605e404ff2d6ddd4"><code>5853551</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3712">#3712</a>
from Rotzbua/patch-1</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/7bce87e2aa29a4a794eb2b113ff811cad6a80736"><code>7bce87e</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3700">#3700</a>
from benoitc/fix/sponsor-logo-path</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/972dfb03b110c430712c32a3d92ef6397ff8eff6"><code>972dfb0</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3690">#3690</a>
from melbinjp/docs/contributing-settings-path</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/7b3f16be8d9cc051538b7f0b58b236b37c9550f8"><code>7b3f16b</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3711">#3711</a>
from benoitc/docs/http2-changelog</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/5bf237c0c7ef5bcdc63046645a17d6bafd609a34"><code>5bf237c</code></a>
http2: require gunicorn_h1c 0.6.9 and drop the upgrade body
workaround</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/7cf03385c574228e28c4952fd410ed2df02acc94"><code>7cf0338</code></a>
test: skip the fast-parser cases when gunicorn_h1c is absent</li>
<li>Additional commits viewable in <a
href="https://github.com/benoitc/gunicorn/compare/26.1.0...26.2.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.52.2 to 4.52.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.52.3 - MCP Server: Patch 1</h2>
<h2>MCP Server: Patch 1</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9bdc1133d096562111d3cc6465c6b0cd5dbfc38d">Fix
the MCP Server on Python versions less than 3.14</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4471">seleniumbase/SeleniumBase#4471</a>
--&gt; (Due to this bug, the MCP Server only worked on Python 3.14+)
--&gt; (Caused by a missing line: <code>from __future__ import
annotations</code>)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0e14a09f2d2f2e62a85bacc890b1d9d48b9a0c79">Update
logging messages</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1584e5b1b83f7177c59810817942150d1ed3ecab">Update
the docs for MCP servers</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/213580314cb106bcb14d857289eb494395f491ae">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/405c7c68599108fc99d1cf929e01b17d2c62cd7a">Update
examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>MCP Server: Patch 1 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4472">seleniumbase/SeleniumBase#4472</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.2...v4.52.3">https://github.com/seleniumbase/SeleniumBase/compare/v4.52.2...v4.52.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9112244cfada5d002f3d08c6dbf2a68d34598c51"><code>9112244</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4472">#4472</a>
from seleniumbase/mcp-server-patch-1</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bf1abf63240338b9ee58f4dc6e907e627411c27b"><code>bf1abf6</code></a>
Version 4.52.3</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/405c7c68599108fc99d1cf929e01b17d2c62cd7a"><code>405c7c6</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/213580314cb106bcb14d857289eb494395f491ae"><code>2135803</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1584e5b1b83f7177c59810817942150d1ed3ecab"><code>1584e5b</code></a>
Update the docs for MCP servers</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0e14a09f2d2f2e62a85bacc890b1d9d48b9a0c79"><code>0e14a09</code></a>
Update logging messages</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9bdc1133d096562111d3cc6465c6b0cd5dbfc38d"><code>9bdc113</code></a>
Fix the MCP Server on Python versions less than 3.14</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cbd624a8697c763d7d68f3e92dcd31f4636ae9d8"><code>cbd624a</code></a>
Update the docs</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.2...v4.52.3">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 12:18:11 -04:00
dependabot[bot] faaa119884 build(deps): bump python from ce40764 to cae66f2 (#1278)
Bumps python from `ce40764` to `cae66f2`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.7-slim&new-version=3.14.7-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 12:18:03 -04:00
dependabot[bot] be41a92436 build(deps-dev): bump the npm-deps group in /src/frontend with 7 updates (#1279)
Bumps the npm-deps group in /src/frontend with 7 updates:

| Package | From | To |
| --- | --- | --- |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `26.2.0` | `26.3.0` |
|
[@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom)
| `19.2.4` | `19.2.5` |
|
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
| `6.0.5` | `6.1.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.63.0` | `0.65.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.78.0` | `1.80.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.2.1` | `8.2.2` |
|
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
| `4.1.10` | `4.1.11` |

Updates `@types/node` from 26.2.0 to 26.3.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react-dom` from 19.2.4 to 19.2.5
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.0.5 to 6.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/releases">@​vitejs/plugin-react's
releases</a>.</em></p>
<blockquote>
<h2>plugin-react@6.1.0</h2>
<h3>Add experimental native React Compiler support (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1419">#1419</a>)</h3>
<p>Add experimental native React Compiler support.</p>
<p>You can use it by installing <code>oxc-transform-react</code> and
enabling it via the <code>compiler</code> option:</p>
<pre lang="sh"><code>npm install -D oxc-transform-react
</code></pre>
<pre lang="js"><code>import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
<p>export default defineConfig({<br />
plugins: [<br />
react({ compiler: true })<br />
]<br />
})<br />
</code></pre></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.1.0 (2026-08-19)</h2>
<h3>Add experimental native React Compiler support (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1419">#1419</a>)</h3>
<p>Add experimental native React Compiler support.</p>
<p>You can use it by installing <code>oxc-transform-react</code> and
enabling it via the <code>compiler</code> option:</p>
<pre lang="sh"><code>npm install -D oxc-transform-react
</code></pre>
<pre lang="js"><code>import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
<p>export default defineConfig({<br />
plugins: [<br />
react({ compiler: true })<br />
]<br />
})<br />
</code></pre></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/39b31735bf79c2dd380eedaba7ed849256f92a29"><code>39b3173</code></a>
release: plugin-react@6.1.0 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1428">#1428</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/f1340b0c760b1c16e1b780eeba46fd933ddd52eb"><code>f1340b0</code></a>
feat(react): add native React Compiler support (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1419">#1419</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/9ab698eafc38ffa14861db450291ed2f6f557557"><code>9ab698e</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1375">#1375</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.0/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.63.0 to 0.65.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/97e99b85483776a72928d675cc05b1cfc1130ba0"><code>97e99b8</code></a>
release(apps): oxlint v1.80.0 &amp;&amp; oxfmt v0.65.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/26045">#26045</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0db127cc16d28b97d84bac4ebeb302caf1a78c7e"><code>0db127c</code></a>
release(apps): oxlint v1.79.0 &amp;&amp; oxfmt v0.64.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25866">#25866</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/c07fe7c217774fd404740d34ee91ac03a6b726c2"><code>c07fe7c</code></a>
feat(oxfmt): support <code>experimentalOperatorPosition</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25643">#25643</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/fed6681edaf3b9b45fbcc8fd7f987c86505d0b86"><code>fed6681</code></a>
docs(oxfmt): skip expanding overrides options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25572">#25572</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.65.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.78.0 to 1.80.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.80.0 &amp; oxfmt v0.65.0</h2>
<h2>Table of Contents</h2>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxlint-v1.80.0">Oxlint
v1.80.0</a></li>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxfmt-v0.65.0">Oxfmt
v0.65.0</a></li>
</ul>
<h2>Oxlint v1.80.0</h2>
<h3>🚀 Features</h3>
<ul>
<li>70c3e35 linter/typescript/no-confusing-non-null-assertion: Implement
suggestion (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26012">#26012</a>)
(Mikhail Baev)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>17ae11c linter/oxc/double-comparisons: Handle grouped logical
expressions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26044">#26044</a>)
(camc314)</li>
<li>8a353a7 linter/eslint/no-control-regex: Refine help message text (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25996">#25996</a>)
(Rahul Mishra)</li>
<li>8a9bdbd estree: Include decorators in <code>FormalParameterRest
</code> spans (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26021">#26021</a>)
(camc314)</li>
<li>8d94cd1 linter/eslint/no-useless-rename: Preserve type modifiers (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26020">#26020</a>)
(Cameron)</li>
<li>2cde1f6 rust: Address nightly deprecations (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25998">#25998</a>)
(Boshen)</li>
<li>51d36d7 linter/vue: Resolve <code>vue</code> imports via shared
import helpers (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25903">#25903</a>)
(Connor Shea)</li>
<li>83a68d2 linter/react/no-react-children: Resolve <code>react</code>
imports by symbol (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25901">#25901</a>)
(Connor Shea)</li>
<li>124e196 linter: Resolve globals by reference, not by name (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25905">#25905</a>)
(Connor Shea)</li>
<li>a701bcc linter: Remove invalid React compiler doc links (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25900">#25900</a>)
(Boshen)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>9b7e153 linter: Set <code>version</code> to 1.79.0 for rules shipped
in 1.79.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25902">#25902</a>)
(connorshea)</li>
</ul>
<h2>Oxfmt v0.65.0</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>bf37dd5 formatter: Preserve class decorators before export when the
statement is suppressed (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26034">#26034</a>)
(leaysgur)</li>
</ul>
<h2>oxlint v1.79.0 &amp; oxfmt v0.64.0</h2>
<h2>Table of Contents</h2>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxlint-v1.79.0">Oxlint
v1.79.0</a></li>
<li><a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/blob/HEAD/#oxfmt-v0.64.0">Oxfmt
v0.64.0</a></li>
</ul>
<h2>Oxlint v1.79.0</h2>
<h3>💥 BREAKING CHANGES</h3>
<ul>
<li>8c4552d linter: [<strong>BREAKING</strong>] Split
react/react-compiler into per-category rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25500">#25500</a>)
(Boshen)</li>
</ul>
<p>See <a
href="https://oxc.rs/blog/2026-08-18-react-compiler-support">React
Compiler Support</a> for details.</p>
<h3>🚀 Features</h3>
<ul>
<li>9b7394e linter/typescript/no-empty-object-type: Implement suggestion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25833">#25833</a>)
(Mikhail Baev)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this package will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0">Keep a Changelog</a>.</p>
<h2>[1.79.0] - 2026-08-18</h2>
<h3>💥 BREAKING CHANGES</h3>
<ul>
<li>8c4552d linter: [<strong>BREAKING</strong>] Split
react/react-compiler into per-category rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25500">#25500</a>)
(Boshen)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>228e8e0 linter: Resolve inactive React compiler rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25830">#25830</a>)
(Boshen)</li>
<li>aa49d86 linter: Allow spread rule options in config types (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25675">#25675</a>)
(ch3rry)</li>
<li>36f8451 linter/eslint/no-eval: Align indirect default with ESLint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25656">#25656</a>)
(camc314)</li>
<li>beb724d linter/eslint/no-unused-vars: Report bare underscore
parameters (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25663">#25663</a>)
(camc314)</li>
<li>4004c10 linter/eslint/no-irregular-whitespace: Check comments by
default (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25660">#25660</a>)
(camc314)</li>
<li>285820e linter/no-large-snapshots: Precompile and document allowed
snapshot matchers (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25611">#25611</a>)
(Mikhail Baev)</li>
<li>4df5835 linter: Allow capitalized built-in calls (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25516">#25516</a>)
(Boshen)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/97e99b85483776a72928d675cc05b1cfc1130ba0"><code>97e99b8</code></a>
release(apps): oxlint v1.80.0 &amp;&amp; oxfmt v0.65.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/26045">#26045</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0db127cc16d28b97d84bac4ebeb302caf1a78c7e"><code>0db127c</code></a>
release(apps): oxlint v1.79.0 &amp;&amp; oxfmt v0.64.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25866">#25866</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/228e8e0f85c0e7aeded02c5e27fd810004d3b41a"><code>228e8e0</code></a>
fix(linter): resolve inactive React compiler rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25830">#25830</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/aa49d860465e6c00b6edfcbb8973d8dc95cc11ca"><code>aa49d86</code></a>
fix(linter): allow spread rule options in config types (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25675">#25675</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/892238149b7c4dff808817ec5e27d1e0ecf63b11"><code>8922381</code></a>
refactor(linter): remove inactive react config rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25740">#25740</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/8c4552dfa6bce0a9f06f41ca13e45e50d842c38c"><code>8c4552d</code></a>
feat(linter)!: split react/react-compiler into per-category rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25500">#25500</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/36f845168ce854c1c970fea13997e16a18cbe55f"><code>36f8451</code></a>
fix(linter/eslint/no-eval): align indirect default with ESLint (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25656">#25656</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/beb724dce2e8b8466d851c04e16c38fa75623c5c"><code>beb724d</code></a>
fix(linter/eslint/no-unused-vars): report bare underscore parameters (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25663">#25663</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/4004c101ca349f8e92932f6d056b18bfb4dff9a7"><code>4004c10</code></a>
fix(linter/eslint/no-irregular-whitespace): check comments by default
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25660">#25660</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/285820eed6c49a45f8de18d3bfed1cc6b5d9da6d"><code>285820e</code></a>
fix(linter/no-large-snapshots): precompile and document allowed snapshot
matc...</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.80.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.2.1 to 8.2.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>plugin-legacy@8.2.2</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/plugin-legacy@8.2.2/packages/plugin-legacy/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.2.2</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.2.2/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.2.1...v8.2.2">8.2.2</a>
(2026-08-20)<!-- raw HTML omitted --></h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> widen <code>@vitejs/devtools</code> peer
range to v0.5.0 (<a
href="https://redirect.github.com/vitejs/vite/issues/23302">#23302</a>)
(<a
href="https://github.com/vitejs/vite/commit/495d9ff5a7d843ca876a9e49799947a5deb704c7">495d9ff</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>bundled-dev:</strong> handle lazy request error (<a
href="https://redirect.github.com/vitejs/vite/issues/23291">#23291</a>)
(<a
href="https://github.com/vitejs/vite/commit/3ba026dade4af56df08815310d3458fa110f5c5c">3ba026d</a>)</li>
<li><strong>bundled-dev:</strong> hot update through circular imports
instead of reloading (<a
href="https://redirect.github.com/vitejs/vite/issues/23259">#23259</a>)
(<a
href="https://github.com/vitejs/vite/commit/3dbddefaafc091a879b06f9279296f776691e455">3dbddef</a>)</li>
<li><strong>config:</strong> resolve sourcemap paths against sourcemap
location (<a
href="https://redirect.github.com/vitejs/vite/issues/23239">#23239</a>)
(<a
href="https://github.com/vitejs/vite/commit/05a003e6a17a84d75f907ea0f1598bc39b8dce6c">05a003e</a>)</li>
<li><strong>css:</strong> don't pass empty targets to lightningcss (<a
href="https://redirect.github.com/vitejs/vite/issues/23295">#23295</a>)
(<a
href="https://github.com/vitejs/vite/commit/2804636ff608d105928009d274ffba7cfbe55340">2804636</a>)</li>
<li><strong>define:</strong> fix match escaped dots to support
$-prefixed define keys (<a
href="https://redirect.github.com/vitejs/vite/issues/23249">#23249</a>)
(<a
href="https://github.com/vitejs/vite/commit/dcf88bd2ad2b1a8845f9029587cc8c825e382d42">dcf88bd</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/23217">#23217</a>)
(<a
href="https://github.com/vitejs/vite/commit/ba958bddfc9cabe302c6b34269dcf5c9634531e0">ba958bd</a>)</li>
<li><strong>deps:</strong> update rolldown-related dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/23218">#23218</a>)
(<a
href="https://github.com/vitejs/vite/commit/83ecb2c8059e8ce946a7cc835d4c14ef78aef4fd">83ecb2c</a>)</li>
<li><strong>module-runner:</strong> exclude completed modules from
in-flight cycle detection (fix <a
href="https://redirect.github.com/vitejs/vite/issues/22999">#22999</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/23009">#23009</a>)
(<a
href="https://github.com/vitejs/vite/commit/d9b10a98db1c293ee64300bd75d568b44c8ae931">d9b10a9</a>)</li>
<li><strong>optimizer:</strong> close custom extension analysis bundles
(<a
href="https://redirect.github.com/vitejs/vite/issues/23207">#23207</a>)
(<a
href="https://github.com/vitejs/vite/commit/8fb76752836f61224d3095b502fa237b478a06b2">8fb7675</a>)</li>
<li>reduce Windows 8.3-short-name detection false-positives (<a
href="https://redirect.github.com/vitejs/vite/issues/23066">#23066</a>)
(<a
href="https://github.com/vitejs/vite/commit/02cffa9e2d38d5d8f12e4043ee9d0f7abb1471e2">02cffa9</a>)</li>
<li>respect <code>resolve.preserveSymlinks</code> when resolving root
(fix <a
href="https://redirect.github.com/vitejs/vite/issues/23197">#23197</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/23198">#23198</a>)
(<a
href="https://github.com/vitejs/vite/commit/8413052731836d4aaf3eb94a0f25788dd35d2888">8413052</a>)</li>
<li><strong>ssr:</strong> rewrite computed key of destructing parameter
(<a
href="https://redirect.github.com/vitejs/vite/issues/23307">#23307</a>)
(<a
href="https://github.com/vitejs/vite/commit/9db0b61d4c9c7caad7ea1d9670b637faf2bb6c93">9db0b61</a>)</li>
<li><strong>vite:</strong> update outdated upstream file links in
license comments (<a
href="https://redirect.github.com/vitejs/vite/issues/23285">#23285</a>)
(<a
href="https://github.com/vitejs/vite/commit/c0f2fc607ee97ee4499337b04826420c00654065">c0f2fc6</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>build:</strong> note cssTarget precedence (<a
href="https://redirect.github.com/vitejs/vite/issues/23200">#23200</a>)
(<a
href="https://github.com/vitejs/vite/commit/a20a35ec0685e374519864d0f41dd5f6e9ba0271">a20a35e</a>)</li>
</ul>
<h3>Miscellaneous Chores</h3>
<ul>
<li>fix ts errors in build test cases (<a
href="https://redirect.github.com/vitejs/vite/issues/23209">#23209</a>)
(<a
href="https://github.com/vitejs/vite/commit/a0cfcf72f8ef8bf0f2f11d553333b9bb31f1d316">a0cfcf7</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>use JSON import attributes instead of readFileSync in constants (<a
href="https://redirect.github.com/vitejs/vite/issues/23258">#23258</a>)
(<a
href="https://github.com/vitejs/vite/commit/1d9fa392a43229241f80630236f8552ce8f7cd0f">1d9fa39</a>)</li>
<li>use named regex constants over inline literals (<a
href="https://redirect.github.com/vitejs/vite/issues/22964">#22964</a>)
(<a
href="https://github.com/vitejs/vite/commit/5c1c6c609718303202832f706884192e1f1e9223">5c1c6c6</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li><strong>define:</strong> close rolldown bundler after generate (<a
href="https://redirect.github.com/vitejs/vite/issues/23231">#23231</a>)
(<a
href="https://github.com/vitejs/vite/commit/b4d66fee14d970f45b8a6f3d7d6aee73ca9b88ab">b4d66fe</a>)</li>
<li><strong>module-runner:</strong> add TLA circular import case (<a
href="https://redirect.github.com/vitejs/vite/issues/23299">#23299</a>)
(<a
href="https://github.com/vitejs/vite/commit/4a261f242831bef92afd2f1aacfb81eab9dec371">4a261f2</a>)</li>
<li><strong>module-runner:</strong> simplify server-hmr tests (<a
href="https://redirect.github.com/vitejs/vite/issues/23300">#23300</a>)
(<a
href="https://github.com/vitejs/vite/commit/599b44b6600ec426e10cd556908d53b027b0c4fb">599b44b</a>)</li>
<li><strong>ssr:</strong> add destructing assignment case for
moduleRunnerTransform (<a
href="https://redirect.github.com/vitejs/vite/issues/23308">#23308</a>)
(<a
href="https://github.com/vitejs/vite/commit/cb77e2a93bad2a8ece00b4aa0ef507c092582c45">cb77e2a</a>)</li>
</ul>
<h3>Build System</h3>
<ul>
<li>use JSON import attributes instead of readFIleSync in rolldown
configs (<a
href="https://redirect.github.com/vitejs/vite/issues/23251">#23251</a>)
(<a
href="https://github.com/vitejs/vite/commit/d615bcdb23d96c1ca5ce1ee45e21d8d87381106f">d615bcd</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/de1111ab0be00879b404e7ed3b2a80e264edddc1"><code>de1111a</code></a>
release: v8.2.2</li>
<li><a
href="https://github.com/vitejs/vite/commit/cb77e2a93bad2a8ece00b4aa0ef507c092582c45"><code>cb77e2a</code></a>
test(ssr): add destructing assignment case for moduleRunnerTransform (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23308">#23308</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/9db0b61d4c9c7caad7ea1d9670b637faf2bb6c93"><code>9db0b61</code></a>
fix(ssr): rewrite computed key of destructing parameter (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23307">#23307</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/8413052731836d4aaf3eb94a0f25788dd35d2888"><code>8413052</code></a>
fix: respect <code>resolve.preserveSymlinks</code> when resolving root
(fix <a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23197">#23197</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23">#23</a>...</li>
<li><a
href="https://github.com/vitejs/vite/commit/05a003e6a17a84d75f907ea0f1598bc39b8dce6c"><code>05a003e</code></a>
fix(config): resolve sourcemap paths against sourcemap location (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23239">#23239</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/495d9ff5a7d843ca876a9e49799947a5deb704c7"><code>495d9ff</code></a>
feat(deps): widen <code>@vitejs/devtools</code> peer range to v0.5.0 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23302">#23302</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/1d9fa392a43229241f80630236f8552ce8f7cd0f"><code>1d9fa39</code></a>
refactor: use JSON import attributes instead of readFileSync in
constants (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/2">#2</a>...</li>
<li><a
href="https://github.com/vitejs/vite/commit/2804636ff608d105928009d274ffba7cfbe55340"><code>2804636</code></a>
fix(css): don't pass empty targets to lightningcss (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23295">#23295</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/599b44b6600ec426e10cd556908d53b027b0c4fb"><code>599b44b</code></a>
test(module-runner): simplify server-hmr tests (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23300">#23300</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/4a261f242831bef92afd2f1aacfb81eab9dec371"><code>4a261f2</code></a>
test(module-runner): add TLA circular import case (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23299">#23299</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v8.2.2/packages/vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `vitest` from 4.1.10 to 4.1.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.11</h2>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li>Revive global concurrency limit for test lifecycle [backport to v4]
 -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> and
<a href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10992">vitest-dev/vitest#10992</a>
<a href="https://github.com/vitest-dev/vitest/commit/5146df80b"><!-- raw
HTML omitted -->(5146d)<!-- raw HTML omitted --></a></li>
<li><strong>browser</strong>:
<ul>
<li>Encode iframeId in tester iframe URL [backport to v4]  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a>,
<strong>Pduhard</strong> and <strong>Claude Opus 4.8</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10955">vitest-dev/vitest#10955</a>
<a href="https://github.com/vitest-dev/vitest/commit/10b2cd201"><!-- raw
HTML omitted -->(10b2c)<!-- raw HTML omitted --></a></li>
<li>Trigger playwright/chromium gc on lower disk availability [backport
to v4]  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10951">vitest-dev/vitest#10951</a>
<a href="https://github.com/vitest-dev/vitest/commit/9851dbc41"><!-- raw
HTML omitted -->(9851d)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>mocker</strong>:
<ul>
<li>Restrict redirect mocks to the fs allowlist [backport to v4]  -  by
<a href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a>
in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10974">vitest-dev/vitest#10974</a>
<a href="https://github.com/vitest-dev/vitest/commit/fe5a11d3c"><!-- raw
HTML omitted -->(fe5a1)<!-- raw HTML omitted --></a></li>
</ul>
</li>
</ul>
<h5>    <a
href="https://github.com/vitest-dev/vitest/compare/v4.1.10...v4.1.11">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitest-dev/vitest/commit/9bd8d464e6328c567c2dbcd8fdd977d57a9425c2"><code>9bd8d46</code></a>
chore: release v4.1.11 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10995">#10995</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/9851dbc41c286a30abfb6b29cce65f3e5b7b40a1"><code>9851dbc</code></a>
fix(browser): trigger playwright/chromium gc on lower disk availability
[back...</li>
<li>See full diff in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 12:17:56 -04:00
dependabot[bot] 7de9319c7a build(deps): bump the gh-actions group with 3 updates (#1280)
Bumps the gh-actions group with 3 updates:
[github/codeql-action/init](https://github.com/github/codeql-action),
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
and
[github/codeql-action/analyze](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.37.7 to 4.37.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.8</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28"><code>db488dd</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4102">#4102</a>
from github/update-v4.37.8-9ee088e13</li>
<li><a
href="https://github.com/github/codeql-action/commit/1845f5ba8b4057590f49ee8e246c95ef2ba4b53f"><code>1845f5b</code></a>
Update changelog for v4.37.8</li>
<li><a
href="https://github.com/github/codeql-action/commit/9ee088e13615f8d1eaef4766f9dde95d3356a8f6"><code>9ee088e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4080">#4080</a>
from github/henrymercer/studious-giggle</li>
<li><a
href="https://github.com/github/codeql-action/commit/1aef003397c876c0ab5bd118e1b1f34c175622e9"><code>1aef003</code></a>
Address review feedback on overlay disk flags</li>
<li><a
href="https://github.com/github/codeql-action/commit/508b83bc415e8df76ce8ea08c0cf42c2529ebc63"><code>508b83b</code></a>
Merge main into overlay minimum disk feature branch</li>
<li><a
href="https://github.com/github/codeql-action/commit/d97b3428e8eebbb1810cf454d6397886d136b4ba"><code>d97b342</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4098">#4098</a>
from github/mbg/permission-error-as-configuration-error</li>
<li><a
href="https://github.com/github/codeql-action/commit/47fa6222231b12097f83215dd7a6b4a0915841fd"><code>47fa622</code></a>
Make <code>EACCES</code> a <code>ConfigurationError</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/45693cc6882bb175b58a06818c91876e201037c7"><code>45693cc</code></a>
Refactor <code>ENOSPC</code> check into
<code>isDiskConfigurationError</code> function</li>
<li><a
href="https://github.com/github/codeql-action/commit/c2fd8f54d19fa46c94ed79cb92e6dd6606d61762"><code>c2fd8f5</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4081">#4081</a>
from github/mario-campos/version-cache-to-disk</li>
<li><a
href="https://github.com/github/codeql-action/commit/c56f48e9bd458a387eb68a68534459e503e56b17"><code>c56f48e</code></a>
Log unexpected conditions during caching CLI output</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.7 to 4.37.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.8</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28"><code>db488dd</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4102">#4102</a>
from github/update-v4.37.8-9ee088e13</li>
<li><a
href="https://github.com/github/codeql-action/commit/1845f5ba8b4057590f49ee8e246c95ef2ba4b53f"><code>1845f5b</code></a>
Update changelog for v4.37.8</li>
<li><a
href="https://github.com/github/codeql-action/commit/9ee088e13615f8d1eaef4766f9dde95d3356a8f6"><code>9ee088e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4080">#4080</a>
from github/henrymercer/studious-giggle</li>
<li><a
href="https://github.com/github/codeql-action/commit/1aef003397c876c0ab5bd118e1b1f34c175622e9"><code>1aef003</code></a>
Address review feedback on overlay disk flags</li>
<li><a
href="https://github.com/github/codeql-action/commit/508b83bc415e8df76ce8ea08c0cf42c2529ebc63"><code>508b83b</code></a>
Merge main into overlay minimum disk feature branch</li>
<li><a
href="https://github.com/github/codeql-action/commit/d97b3428e8eebbb1810cf454d6397886d136b4ba"><code>d97b342</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4098">#4098</a>
from github/mbg/permission-error-as-configuration-error</li>
<li><a
href="https://github.com/github/codeql-action/commit/47fa6222231b12097f83215dd7a6b4a0915841fd"><code>47fa622</code></a>
Make <code>EACCES</code> a <code>ConfigurationError</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/45693cc6882bb175b58a06818c91876e201037c7"><code>45693cc</code></a>
Refactor <code>ENOSPC</code> check into
<code>isDiskConfigurationError</code> function</li>
<li><a
href="https://github.com/github/codeql-action/commit/c2fd8f54d19fa46c94ed79cb92e6dd6606d61762"><code>c2fd8f5</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4081">#4081</a>
from github/mario-campos/version-cache-to-disk</li>
<li><a
href="https://github.com/github/codeql-action/commit/c56f48e9bd458a387eb68a68534459e503e56b17"><code>c56f48e</code></a>
Log unexpected conditions during caching CLI output</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.7 to 4.37.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.8</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.9 - 26 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4">2.26.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4106">#4106</a></li>
</ul>
<h2>4.37.8 - 21 Aug 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28"><code>db488dd</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4102">#4102</a>
from github/update-v4.37.8-9ee088e13</li>
<li><a
href="https://github.com/github/codeql-action/commit/1845f5ba8b4057590f49ee8e246c95ef2ba4b53f"><code>1845f5b</code></a>
Update changelog for v4.37.8</li>
<li><a
href="https://github.com/github/codeql-action/commit/9ee088e13615f8d1eaef4766f9dde95d3356a8f6"><code>9ee088e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4080">#4080</a>
from github/henrymercer/studious-giggle</li>
<li><a
href="https://github.com/github/codeql-action/commit/1aef003397c876c0ab5bd118e1b1f34c175622e9"><code>1aef003</code></a>
Address review feedback on overlay disk flags</li>
<li><a
href="https://github.com/github/codeql-action/commit/508b83bc415e8df76ce8ea08c0cf42c2529ebc63"><code>508b83b</code></a>
Merge main into overlay minimum disk feature branch</li>
<li><a
href="https://github.com/github/codeql-action/commit/d97b3428e8eebbb1810cf454d6397886d136b4ba"><code>d97b342</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4098">#4098</a>
from github/mbg/permission-error-as-configuration-error</li>
<li><a
href="https://github.com/github/codeql-action/commit/47fa6222231b12097f83215dd7a6b4a0915841fd"><code>47fa622</code></a>
Make <code>EACCES</code> a <code>ConfigurationError</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/45693cc6882bb175b58a06818c91876e201037c7"><code>45693cc</code></a>
Refactor <code>ENOSPC</code> check into
<code>isDiskConfigurationError</code> function</li>
<li><a
href="https://github.com/github/codeql-action/commit/c2fd8f54d19fa46c94ed79cb92e6dd6606d61762"><code>c2fd8f5</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4081">#4081</a>
from github/mario-campos/version-cache-to-disk</li>
<li><a
href="https://github.com/github/codeql-action/commit/c56f48e9bd458a387eb68a68534459e503e56b17"><code>c56f48e</code></a>
Log unexpected conditions during caching CLI output</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-30 12:17:50 -04:00
CaliBrain 97e289ae13 fix: search, Prowlarr and qBittorrent follow-ups (#1276, #1283) (#1284) 2026-08-30 03:09:13 -04:00
Jorge Lima c95ee72ad5 fix(qbittorrent): keep magnets whose metadata is still pending (#1282)
## Problem

`QBittorrentClient.add_download()` waits 20 × 0.5 s for qBittorrent to
leave `metaDL`, then raises:

```
Failed to add to qbittorrent: Torrent metadata resolution was not confirmed within the visibility grace period
(response=TorrentsAddedMetadata({'added_torrent_ids': [], 'failure_count': 0, 'pending_count': 1, 'success_count': 0}))
```

The wait exists to learn qBittorrent's primary torrent ID, which for
hybrid torrents switches from the v1 hash to the truncated v2 hash once
metadata resolves. A magnet on a thin public swarm routinely needs
longer than 10 s to find a peer that will serve metadata, and the
download is then abandoned even though the add itself succeeded. The
torrent stays in qBittorrent (`base_handler` logs "leaving in
qbittorrent") and often completes minutes later with nobody watching it.

Seen on v1.3.12 with public indexers through Prowlarr: every magnet-only
release failed this way, while `.torrent` releases from a private
indexer were fine. qBittorrent showed the same torrents at `metaDL 0%
seeds=0/0`, and they resolved on their own well after shelfmark had
given up.

## Change

Return the info hash we already have instead of raising when the grace
period expires. Reads then resolve either identity:

- `get_status()` and `get_download_path()` use `_resolve_torrent()`
instead of `_get_torrent_info()`, so a v1 hash still matches after
qBittorrent re-keys the torrent to v2. `_torrent_matches_download_id`
already compares `hash`, `infohash_v1` and `infohash_v2`.
- `remove()` and `set_category()` address the torrent by its current
primary hash through a new `_current_hash()` helper, which falls back to
the ID it was given when the torrent cannot be resolved.
- The two magic numbers become `_METADATA_WAIT_POLLS` and
`_METADATA_WAIT_INTERVAL_SECONDS`.

The happy path does not change. When metadata resolves inside the grace
period the resolved primary hash comes back as before, and
`_resolve_torrent()` tries the exact-hash lookup first, so it costs no
extra request.

## Tests

`test_add_fails_when_metadata_never_resolves` asserted the old
behaviour, so it becomes
`test_add_keeps_torrent_when_metadata_never_resolves` and asserts the
info hash is returned.
`test_get_status_resolves_hash_after_metadata_switch` is new: it reads
status by the v1 hash after qBittorrent reports the torrent under its v2
hash.

`uv run pytest tests/ --ignore=tests/e2e` gives the same 55 failures
with and without this change (they are all in `tests/bypass/` and need
Chrome, which my machine has no headless setup for), and
`tests/prowlarr/` is green at 524 passed. Ruff check and format are
clean. I have not run this branch against a live qBittorrent, so a
second pair of eyes on the `remove()` path would help.
2026-08-30 02:00:42 -04:00
CaliBrain b25acdb2ad fix(packs): don't disrupt normal downloads when inspecting for packs (#1274)
Follow-ups to the multi-book pack feature (#1270), which inspects every
release before download. Two behaviours leaked into the ordinary
single-book
flow and are corrected here:

- A flat folder of chaptered audio (`01 - Chapter.mp3`, `02 - ...`) was
detected as a pack, because each track name parses to a series position,
so
clicking download popped the review panel for one normal audiobook. Flat
folders are now split one-book-per-file only with real evidence of
distinct
books: two or more series positions, more than one title, and no
chaptered
audio (only the single-file m4b/m4a containers and ebook formats
qualify).
  Subfolder packs and flat m4b/m4a packs are unchanged.

- Every release that couldn't be inspected (usenet, magnet-only, sources
  without a list_files hook, ABB single-file) showed an info toast on
download. That is now a console.warn, so a normal download is silent
again.

Adds regression tests for the chaptered-mp3 cases.
2026-08-27 01:00:54 -04:00
dependabot[bot] 7569aaecc5 build(deps): bump seleniumbase from 4.52.1 to 4.52.2 in the python-deps group (#1273)
Bumps the python-deps group with 1 update:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `seleniumbase` from 4.52.1 to 4.52.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.52.2 - MCP Server Support</h2>
<h2>MCP Server Support</h2>
<p><strong>If you love AI tools, this is one of the biggest releases
this year for SeleniumBase!</strong>
<strong>The new <code>seleniumbase-mcp</code> command starts the
&quot;Pure CDP Mode&quot; MCP Server.</strong>
<strong>(Be sure to install <code>seleniumbase[mcp]</code> to get
<code>mcp&gt;=2.0.0</code>!)</strong>
<strong>(To debug the MCP server from a <code>git clone</code> of
SeleniumBase, get <code>uv</code> as well before calling <code>mcp dev
server.py</code> from the <code>SeleniumBase/mcp_servers/</code>
folder.)</strong></p>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4014476e288d004a8de38eca582631c9c653fa22">Add
a SeleniumBase MCP server</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ac7e449fbbc8a6e9347e65e4ced8176ba1655112">Add
.mcp.json to the root folder</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/32fac6becaabbb288be42e98d6528108bdb05e73">Update
setup.cfg files</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/168500f45b547c914539057f76e3cd31e0121461">Update
.gitignore</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bb495cb23e405ab9a523068cdb64b48f487f22c5">Update
.dockerignore</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f030eae7b492f41d1c74c731e775f21b853afbdf">Add
configuration for using the new MCP server</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/422bb2fc11bd6ef58758c0eff1456f033a94db1f">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7b245c033dc47e356fdaa99b5db7ebf965329bfe">Update
ReadMe files</a></li>
</ul>
<p><strong>Note that you will need <code>mcp&gt;=2.0.0</code> for the
MCP Server to work!</strong></p>
<p>⚠️ Note: Due to a typing bug, (<a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4471">seleniumbase/SeleniumBase#4471</a>),
the MCP Server in this release only worked on Python 3.14+.
Upgrade to <a
href="https://github.com/seleniumbase/SeleniumBase/releases/tag/v4.52.3">https://github.com/seleniumbase/SeleniumBase/releases/tag/v4.52.3</a>
for the fix.</p>
<h2>What's Changed</h2>
<ul>
<li>MCP Server Support by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4470">seleniumbase/SeleniumBase#4470</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.1...v4.52.2">https://github.com/seleniumbase/SeleniumBase/compare/v4.52.1...v4.52.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a28aa518e34c859d3a3f90daf03c1aa926940931"><code>a28aa51</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4470">#4470</a>
from seleniumbase/mcp-server-support</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7b245c033dc47e356fdaa99b5db7ebf965329bfe"><code>7b245c0</code></a>
Update ReadMe files</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1e5ac8dd110ecb96add400a45f009735be5e8683"><code>1e5ac8d</code></a>
Version 4.52.2</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/422bb2fc11bd6ef58758c0eff1456f033a94db1f"><code>422bb2f</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f030eae7b492f41d1c74c731e775f21b853afbdf"><code>f030eae</code></a>
Add configuration for using the new MCP server</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bb495cb23e405ab9a523068cdb64b48f487f22c5"><code>bb495cb</code></a>
Update <code>.dockerignore</code></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/168500f45b547c914539057f76e3cd31e0121461"><code>168500f</code></a>
Update <code>.gitignore</code></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/32fac6becaabbb288be42e98d6528108bdb05e73"><code>32fac6b</code></a>
Update <code>setup.cfg</code> files</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ac7e449fbbc8a6e9347e65e4ced8176ba1655112"><code>ac7e449</code></a>
Add <code>.mcp.json</code> to the root folder</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4014476e288d004a8de38eca582631c9c653fa22"><code>4014476</code></a>
Add a SeleniumBase MCP server</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.1...v4.52.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=seleniumbase&package-manager=uv&previous-version=4.52.1&new-version=4.52.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-27 00:41:57 -04:00
Lance Marks f441b85da2 feat(packs): inspect multi-book releases and file each book separately (#1270)
## Multi-book packs: inspect a release before download and file each
book separately

Closes #576

### Problem

One queued release is always treated as one book. When a torrent is
actually a whole series
(`Series/Book 1 - Title/…`, or a flat folder of `Series 1.0 - Title.m4b`
files), post-processing
walks the whole tree, flattens every file into one list and renames them
`Title - 01…10` under the
searched book's `{Author}/{Title}`. Audiobookshelf then sees a single
10-file "book" and the user
has to re-file everything by hand.

### What this does

Most releases expose their file list *before* anything is downloaded, so
the split is decided up
front and approved by the user, then the download is fire-and-forget:

1. **Inspect** – clicking a release's download button now calls `POST
/api/releases/inspect`
first. A new optional `DownloadHandler.list_files(release_data)` hook
returns the release's
   files without downloading:
- **AudiobookBay** reads the torrent file table off the detail page it
already fetches (the
page is now cached for 120 s, so inspect + download cost ABB one
request).
- **Prowlarr** parses `info.files` from the `.torrent` it already
fetches (the existing 120 s
torrent-fetch cache is reused). Magnet-only and usenet releases report
"can't inspect".
   - Other sources default to `None`.
2. **Review** – if the plan contains more than one book, the Find
Releases modal swaps the list
for a review panel: one row per book with editable title / series
position / year, expandable
file lists, non-book sidecars (`.txt`, covers) shown as ignored, a
"Treat as a single book"
switch, and **Download N books**. Single-book releases queue
immediately, exactly as before.
3. **File** – the approved plan travels with the task
(`DownloadTask.book_plan`, retry-safe) and
post-processing files each book through the existing transfer code, one
book at a time
(`dataclasses.replace(task, title=…, series_position=…, year=…)`), so
organize/rename
templates, part numbering (now scoped per book), hardlinks, torrent
copy-preserve and usenet
   handling are unchanged. Status reads `Complete (N books, M files)`.
4. **Fallback** – when a release can't be inspected the user gets a
toast, and a small
"Multi-book pack" toggle in the modal header forces a heuristic split
(subfolder = book, or
   one book per file when the file names carry series positions).

Planning lives in `shelfmark/download/postprocess/packs.py` and is
shared by the inspect endpoint
and post-processing, so what the user approved is what gets filed. The
name parser strips
`Book 3 -`, `03 -`, `1.0 -`, `3.`, `[03]`, `#3`, a leading series name,
labels like
"An Expanse Novella -", repeated titles (`Gods of Risk 2.5 - Gods of
Risk`) and a trailing
`(Year)`; author and series name come from the book that was searched,
and the searched book's
own series position is never applied to its siblings.

### Files

- `shelfmark/download/postprocess/packs.py` (new) –
`PackFile/PackBook/PackPlan`, `plan_pack`,
`parse_pack_book_name`, `group_files_into_books`, `match_plan_to_files`
- `shelfmark/core/release_inspect_routes.py` (new) – `POST
/api/releases/inspect`
- `shelfmark/release_sources/__init__.py` – `DownloadHandler.list_files`
hook
- `shelfmark/release_sources/audiobookbay/{scraper,handler}.py` –
detail-page cache,
  `extract_file_list`, `list_files`
- `shelfmark/release_sources/prowlarr/handler.py`,
`download/clients/torrent_utils.py` –
  `extract_file_list_from_torrent`, `list_files`
- `shelfmark/core/models.py`, `download/orchestrator.py` – `multi_book`
/ `book_plan` fields,
  queue + retry serialization
- `shelfmark/download/postprocess/transfer.py`, `pipeline.py`,
`outputs/folder.py` – per-book
  transfer branch and status message
- `src/frontend`: `components/PackReviewPanel.tsx` (new),
`ReleaseModal.tsx`, `App.tsx`,
`services/api.ts`, `types/index.ts`, `utils/releasePayload.ts` (payload
builder moved out of
  `App.tsx`), `utils/packReview.ts`
- `docs/dev/release-sources-plugin-guide.md` – documents the
`list_files` hook

### Out of scope (follow-ups)

- Listing files from an NZB (Shelfmark already fetches the bytes; `<file
subject>` names are noisy)
- Inspecting magnet links via qBittorrent's files API after a paused add
- BookLore / email outputs (they ignore `book_plan`; noted in code)
- The combined ebook + audiobook flow

### Testing

**Automated** (`make checks`, `make python-test`, `make frontend-test`
all green; the only
failures on my machine are the pre-existing
`tests/config/test_entrypoint_permissions.py` cases,
which need bash ≥ 4 and fail identically on `main` under macOS bash
3.2):

- `tests/download/test_packs.py` – name parsing (markers, series name,
novella labels, repeated
titles, bare numeric titles like `1984`), nested / flat / mixed /
deeper-nested packs, single
wrapping folder not treated as a pack, plan-to-disk matching with
basename fallback
- `tests/core/test_processing_packs.py` – full `post_process_download`
runs on a real temp
filesystem: approved plan files each book under its own
`{Author}/{Title}`, heuristic split
of a nested pack, searched book's series position does not leak,
multi-file book inside a pack
keeps `- 01/- 02` per book, hardlinked torrent pack leaves the seeding
tree intact, no pack
fields ⇒ behaviour unchanged, single group degrades to the searched
title, status message
- `tests/core/test_release_inspect_routes.py` – plan response,
not-inspectable, handler errors
  never 500, unknown source / missing `source_id` ⇒ 400, login required
- `tests/audiobookbay/test_file_list.py` – file-table scraping from real
ABB markup (multi-file
and single-file pages), handler host validation, one page fetch shared
by magnet + file list
- `tests/prowlarr/test_torrent_file_list.py` – multi-file / single-file
`.torrent` parsing,
  handler behaviour for torrent URL vs magnet vs usenet vs cache miss
- `tests/download/test_orchestrator_pack_fields.py` – queue-time parsing
and retry round-trip
- Frontend: `releasePayload.test.ts`, `packReview.test.ts` (vitest)

**Manual, on a real deployment** (arm64 image built from this branch,
run as a side container
next to production with the same qBittorrent / Audiobookshelf setup,
`FILE_ORGANIZATION_AUDIOBOOK=organize`,
hardlinks on):

- AudiobookBay "The Expanse Complete 2.0" (7.87 GB, 36 files): clicking
download opened the review
panel in ~1 s showing **18 books · 18 files · 18 files ignored** (the
`.txt` sidecars), with
series positions 0.1–9.5 and years parsed from the file names; novella
labels stripped
("The Churn", "The Butcher of Anderson Station"). Editing a title in the
panel works.
Confirming queued one task; the magnet resolved from the cached page in
~30 ms; after the
download the task reported `Complete (18 books, 18 files)`, 18 hardlinks
landed as
`audiobooks/James S. A. Corey/<Title>/<Title>.m4b`, the torrent kept
seeding, and
Audiobookshelf scanned each folder as its own book (title, author,
embedded chapters).
- A second pack ("Expanse [01 - 9.5]", `Title N - Title` naming) was
inspected to verify the
  repeated-title rule and the Back button, without downloading.
- Single-book releases still queue immediately with no extra UI.
2026-08-27 00:40:08 -04:00
zab1996andRyan 02b7e9d958 feat(newznab): support multiple named indexers (#1271)
## Summary

- add a named Newznab indexer table with per-indexer URL and API key
settings
- search every configured indexer and retain the originating indexer
name on each result
- namespace cached release IDs across connections and isolate individual
indexer failures
- preserve the legacy single-indexer settings as a fallback
- support masked API-key cells and trusted SABnzbd prefetching for named
indexers

## Validation

- 121 Newznab and SABnzbd backend tests passed on Python 3.14
- Ruff passed for all changed Python files
- frontend TypeScript and strict lint checks passed
- all 134 frontend unit tests passed
- frontend formatting check passed

## Compatibility

Existing `NEWZNAB_URL` and `NEWZNAB_API_KEY` configurations continue to
work whenever `NEWZNAB_INDEXERS` is empty.

Co-authored-by: Ryan <zab1996@users.noreply.github.com>
2026-08-27 00:29:58 -04:00
CaliBrain ff06a1a581 fix(search): follow-ups to per-user book languages (#1267)
Review follow-ups to #1255, all in the code that PR touched.

Drop the dead user_id from the Prowlarr retry path.
ProwlarrSource.search
never reads plan.languages, and _refresh_release builds a synthetic book
with no titles_by_language, so the title variants came out identical
with
and without it. It also should not language-filter: it re-finds one
exact
release by its guid.

Pin the tab move in tests. BOOK_LANGUAGE moved from the General tab to
Search Mode with no migration, which only works because both tabs
persist
into the same settings.json. Nothing asserted that, so splitting the
files
later would silently reset every install to ["en"]. Covers the stored
value, a fresh install, and ENV precedence.

Stop the UI inventing a default language. An empty BOOK_LANGUAGE is a
deliberate "no default filter" that the backend preserves, but the two
frontend call sites replaced it with the first supported language, so
the
filter said English where the server filtered nothing.
resolveDefaultLanguageCodes
now falls back only when the value is absent.

Keep the normalized value for every validated search key.
validate_user_settings
gated the write-back on a hand-maintained subset of the keys the search
validator recognises, so METADATA_PROVIDER_COMBINED,
SHOW_COMBINED_SELECTOR
and FORCE_COMBINED_SEARCH were validated and then stored raw -- a padded
provider name was accepted and persisted with its padding. Reuse the
validator's own key set instead.

Skip blank language entries rather than rejecting them, so "" and "en,"
mean the same as [] and ["en"] instead of erroring on an unnamed
language.

Extract resolveListOverride for the list-override detection that was
copy-pasted between the two user-settings sections, and mention
languages
in the Search Preferences section description.
2026-08-24 18:11:29 -04:00
463ef49ac3 feat(search): let each user pick their own default book languages (#1255)
## Why

`BOOK_LANGUAGE` is a per-reader property, not a per-instance one. On a
shared install one household member searches in German while another
wants English and German — today whoever changes the setting changes it
for everyone, and the only escape is re-picking languages in the filter
on every single search.

The per-user override machinery already carries `SEARCH_MODE`, the
metadata providers and the default release sources, so the language
default mostly had to opt into it.

## What changed

**The field.** `BOOK_LANGUAGE` becomes `user_overridable` and moves from
the **General** tab to **Search Mode**, next to the other
user-overridable search defaults (per
[review](https://github.com/calibrain/shelfmark/pull/1255#issuecomment-5391189094)
— the first version had the Search section span two tabs, this one
doesn't). Admins set it per user in the user editor, users set it in
**My Account → Search Preferences**, and the Search Mode tab carries the
usual "N users override this" summary.

**No migration for the move.** `general` and `search_mode` both persist
into `settings.json`, and a field's value is resolved through
`load_config_file(tab)` for the tab it's declared on — so an install
that already stores `BOOK_LANGUAGE` keeps its value. Checked against a
`settings.json` written while the field still lived on General: the
stored value resolves unchanged, a fresh install still gets `["en"]`,
and `BOOK_LANGUAGE` in the environment still overrides both.

**The two places the default is read.**

- `/api/config` seeds the frontend's language filter, so it now resolves
`BOOK_LANGUAGE` for the session user.
- `build_release_search_plan` falls back to the default whenever a
request carries no language filter — which is exactly what the filter's
"Default" option sends. It takes an optional `user_id`, passed by
`/api/releases` from the session and by the Prowlarr retry path from
`task.user_id`, so a retry re-searches in the languages of whoever
queued the download.

**Validation.** Overrides go through `normalize_language()`, so
`"German"`, `"ger"` and `"de"` all store as `de`, and an unknown
language is rejected with a message naming it instead of being silently
searched for. An empty list stays an empty list (a deliberate "no
default filter"), `null` clears the override as everywhere else, and ENV
still wins: with `BOOK_LANGUAGE` set in the environment the field
reports `fromEnv` and overrides are ignored.

**Scope.** Only the language default becomes overridable. The two format
lists left behind under "Default Search Filters" stay admin-only — they
describe what the library and its post-processing accept, not what a
reader wants to read. There's a test pinning that.

## Verification

- 2681 unit tests pass (2670 before, 11 added)
- `ruff check`, `ruff format`, `basedpyright` over backend and tests,
and `vulture` all clean; frontend lint, format, typecheck and 126 unit
tests clean
- `docs/environment-variables.md` regenerated via
`scripts/generate_env_docs.py` (the `BOOK_LANGUAGE` row follows the
field into the Search Mode section)
- Manually against a two-user instance with builtin auth (first round,
before the tab move): with user A on German and user B on
English+German, `/api/config` returns each reader their own
`default_language` and an unfiltered `/api/releases` plans the matching
languages; an admin can set and read the same override for another user;
clearing it falls back to the global value; a stray `"klingon"` is
rejected; and `BOOK_LANGUAGE` in the environment overrides both users
with the field marked `fromEnv`
- After the tab move I re-ran the suites above plus the
stored-value/fresh-install/ENV check described under "No migration for
the move"; the behaviour it exercises is what the move could have broken

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-08-24 17:57:21 -04:00
CaliBrain a5595cf9f1 Change test for fake extension that wont work (#1266) 2026-08-24 17:54:10 -04:00
jakesterpdxandClaude Fable 5 9bcf595111 feat(prowlarr): warn when an indexer declares a format Shelfmark can't process (#1265)
## Problem

Companion to #1264, but general rather than mp4-specific.

MyAnonamouse titles carry a structured `[LANG / FORMATS]` bracket that
`_extract_mam_formats` parses. When every token in it is something
Shelfmark doesn't know — e.g. `The Martian by Andy Weir [ENG / MP4]` —
the release is rendered with **no format chip at all**, just the generic
headphones/book icon with an "Audiobook" tooltip. To a user that looks
like an ordinary result. It downloads fine and then fails
post-processing with *"No book files found in download"*.

The backend already *had* the signal (a format token it couldn't map);
it just threw it away.

## Change

**Backend** (`shelfmark/release_sources/prowlarr/source.py`)
- `_split_mam_formats(raw_title) -> (recognized, unrecognized)` replaces
the body of `_extract_mam_formats`, which is kept as a thin wrapper
returning `recognized` so nothing else changes.
- Releases gain `extra["unrecognized_formats"]` (list, or `None` when
empty / when format detection is off).

**Frontend**
- `getUnrecognizedReleaseFormats(release)` in `utils/releaseFormats.ts`
(normalised + deduped, same shape as `getReleaseFormats`).
- `ReleaseCell` `format_content_type`: when there is **no** recognised
format but the indexer named one, render an amber `MP4 Unsupported`
badge (compact view: amber `MP4`) with tooltip *"Unsupported format
(MP4) - Shelfmark cannot process this release"*. When a recognised
format exists the existing badge is untouched, even if extra unknown
tokens were present.

Only the chip changes — the download button still works, so a user can
still grab and hand-process the files if they want to. Happy to disable
the button instead if you'd prefer.

## Tests

- `tests/prowlarr/test_source.py`: `TestSplitMamFormats` (recognised /
unrecognised / mixed / no bracket / wrapper compat) and
`TestUnrecognizedFormatOnRelease` (lands in `extra`, empty when
recognised, absent without format detection).
- `src/frontend/src/tests/releaseFormats.test.ts`: 3 cases for the new
helper.
- `ruff check` clean; `pytest tests/prowlarr -m "not integration"` 511
passed; `tsc --noEmit`, `oxlint --deny warnings`, `vitest` all clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:50:27 -04:00
jakesterpdxandClaude Fable 5 65e2e3be20 feat(audiobook): recognise .mp4 as an audiobook format (#1264)
## Problem

Some trackers — MyAnonamouse in particular — distribute AAC audiobooks
as per-chapter `.mp4` files. That's the same ISO-BMFF container as
`.m4a`/`.m4b`, just with the generic extension (`ftyp isom`,
audio-only).

Today those releases:
1. show up in Prowlarr search results with **no format chip** — only the
generic "Audiobook" icon, because no format could be inferred;
2. download successfully; then
3. fail post-processing with **"No book files found in download"**,
because `.mp4` isn't in `AUDIOBOOK_FORMATS` (`shelfmark/core/utils.py`).

Real example: MAM #627978, *The Martian* (Andy Weir, 2020 edition) — 142
files `0001 … 0142 Andy Weir (2020) The Martian.mp4` + `cover.jpg`, 305
MB. Every file is a valid AAC-in-MP4 chapter.

Adding `mp4` to `SUPPORTED_AUDIOBOOK_FORMATS` in `settings.json` doesn't
help since the hard-coded tuple is what post-processing scans against.

## Change

- Add `"mp4"` to `AUDIOBOOK_FORMATS` (single source of truth — settings
UI, Prowlarr parsing, IRC parser, archive extraction and post-download
scan all derive from it), with a comment explaining why.
- Add `".mp4"` to the two hand-maintained debrid `_BOOK_EXTENSIONS`
lists (AllDebrid / Real-Debrid) so file selection matches.
- Slot `mp4` into the IRC `AUDIOBOOK_FORMAT_PRIORITY` table right after
`m4a` (same container family).
- Update the documented default in `docs/environment-variables.md`.
- New regression test
`test_audiobook_multifile_mp4_chapters_are_book_files` modelled on the
existing multi-file usenet test.

### Note for existing installs

The legacy-default migration only widens configs that still hold the old
`m4b,mp3` list, so users on the current widened default won't pick up
`mp4` automatically — they'll need to tick it in Settings → Audiobook
formats. New installs get it by default. Happy to extend the migration
if you'd rather it be automatic.

## Testing

- `ruff check` / `ruff format --check`: clean
- `pytest tests/core tests/config tests/irc tests/prowlarr
tests/download -m "not integration and not e2e"`: 2296 passed, new test
+ `test_audiobook_format_consistency.py` all green. The 10 failures in
`test_entrypoint_permissions.py` / `test_orchestrator_stall.py`
reproduce identically on untouched `main` on macOS and are unrelated.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:45:54 -04:00
CaliBrain ddc26f01b6 fix(download): escalating per-host cooldown on HTTP 429 (#1263)
Anna's Archive 429-throttles the source IP after repeated automated
requests.
The bypasser could clear the DDoS-Guard challenge but not the 429, so
each retry
re-solved, re-spawned Chrome, and rotated mirrors that share the same IP
- a
costly loop that never converged.

Add a process-global, per-host cooldown that escalates 2 -> 5 -> 10 ->
15 -> 30
minutes each time a host 429s again after its window elapsed, resetting
after a
long clear gap. Mirror selection skips cooling hosts and the bypasser
refuses to
solve one, so a throttled host fails fast instead of storming the
solver.
2026-08-24 13:08:07 -04:00
CaliBrain 89104ae80f fix(search): let manual search switch media type under forced combined search (#1262)
Manual search browses release sources directly, one media type at a
time,
so the combined (both) flow never applied to it — yet
FORCE_COMBINED_SEARCH
locked the content-type selector onto both, pinning manual search to
ebook
sources with no way to reach audiobook sources (no Audiobay tab).

Treat a manual search target as combined-exempt in the search bar:
present a
plain, switchable Books/Audiobooks selector (unlocked, no combined
toggle),
even when combined search is forced on for metadata targets. Metadata
search
behavior is unchanged.

Fixes #1256
2026-08-24 01:57:42 -04:00
dependabot[bot] 1e45add4d5 build(deps-dev): bump knip from 6.32.1 to 6.32.2 in /src/frontend in the npm-deps group (#1246)
Bumps the npm-deps group in /src/frontend with 1 update:
[knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip).

Updates `knip` from 6.32.1 to 6.32.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.32.2</h2>
<ul>
<li>Support <code>oxfmt.config.mts</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1933">#1933</a>)
(795900191dc75eec8d1e717b866bf57e1e2912cc) - thanks <a
href="https://github.com/joealden"><code>@​joealden</code></a>!</li>
<li>Support <code>oxlint.config.mts</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1934">#1934</a>)
(531e2dc7c1d8bf31babea0068c34391182ec2d50) - thanks <a
href="https://github.com/joealden"><code>@​joealden</code></a>!</li>
<li>Fix Supported <code>lint-staged</code> Configs (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1935">#1935</a>)
(f9c755e414ed10baa4d01af8ddac6d04cb8d5617) - thanks <a
href="https://github.com/joealden"><code>@​joealden</code></a>!</li>
<li>Update dependencies (95f7c529f918dd9e1a84f92c68d064738977b825)</li>
<li>Update sentry snapshot
(ea7929fcbd6b323c8bdd9252ac57017feeb29ecf)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/196a11a4e0cb5208c0dc8382a54341d5630af631"><code>196a11a</code></a>
Release knip@6.32.2</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/95f7c529f918dd9e1a84f92c68d064738977b825"><code>95f7c52</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f9c755e414ed10baa4d01af8ddac6d04cb8d5617"><code>f9c755e</code></a>
Fix Supported <code>lint-staged</code> Configs (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1935">#1935</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/531e2dc7c1d8bf31babea0068c34391182ec2d50"><code>531e2dc</code></a>
Support <code>oxlint.config.mts</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1934">#1934</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/795900191dc75eec8d1e717b866bf57e1e2912cc"><code>7959001</code></a>
Support <code>oxfmt.config.mts</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1933">#1933</a>)</li>
<li>See full diff in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.32.2/packages/knip">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=knip&package-manager=npm_and_yarn&previous-version=6.32.1&new-version=6.32.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 01:57:08 -04:00
dependabot[bot] cb3f6fee82 build(deps): bump astral-sh/uv from 0.11.3 to 0.12.5 in the docker-base-image-digests group (#1247)
Bumps the docker-base-image-digests group with 1 update:
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `astral-sh/uv` from 0.11.3 to 0.12.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.12.5</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-14.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.10.21, 3.11.16, and 3.12.14 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21138">#21138</a>)</li>
<li>Prefer newer versions and standard variants when selecting between
equally prioritized Python interpreters (<a
href="https://redirect.github.com/astral-sh/uv/pull/21134">#21134</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Simplify errors and hints for invalid editable requirements, and
redact credentials in requirement URLs (<a
href="https://redirect.github.com/astral-sh/uv/pull/21130">#21130</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Allow <code>--index</code> and <code>--default-index</code> to
select configured package indexes by name with the
<code>index-by-name</code> preview feature (<a
href="https://redirect.github.com/astral-sh/uv/pull/17455">#17455</a>)</li>
<li>Include distribution artifact URLs and hashes in CycloneDX SBOM
exports by default (<a
href="https://redirect.github.com/astral-sh/uv/pull/21131">#21131</a>)</li>
<li>Fall back to logical file sizes when using
<code>cache-physical-space</code> on filesystems that do not support
physical-space accounting (<a
href="https://redirect.github.com/astral-sh/uv/pull/21133">#21133</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Resolve relative package index paths in PEP 723 scripts against the
script directory (<a
href="https://redirect.github.com/astral-sh/uv/pull/21097">#21097</a>)</li>
</ul>
<h2>Install uv 0.12.5</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-installer.ps1
| iex&quot;
</code></pre>
<h2>Download uv 0.12.5</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-apple-darwin.tar.gz">uv-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-x86_64-apple-darwin.tar.gz">uv-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-pc-windows-msvc.zip">uv-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-i686-pc-windows-msvc.zip">uv-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-x86_64-pc-windows-msvc.zip">uv-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-unknown-linux-gnu.tar.gz">uv-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-i686-unknown-linux-gnu.tar.gz">uv-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-powerpc64le-unknown-linux-gnu.tar.gz">uv-powerpc64le-unknown-linux-gnu.tar.gz</a></td>
<td>PPC64LE Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.5/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.5</h2>
<p>Released on 2026-08-14.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.10.21, 3.11.16, and 3.12.14 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21138">#21138</a>)</li>
<li>Prefer newer versions and standard variants when selecting between
equally prioritized Python interpreters (<a
href="https://redirect.github.com/astral-sh/uv/pull/21134">#21134</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Simplify errors and hints for invalid editable requirements, and
redact credentials in requirement URLs (<a
href="https://redirect.github.com/astral-sh/uv/pull/21130">#21130</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Allow <code>--index</code> and <code>--default-index</code> to
select configured package indexes by name with the
<code>index-by-name</code> preview feature (<a
href="https://redirect.github.com/astral-sh/uv/pull/17455">#17455</a>)</li>
<li>Include distribution artifact URLs and hashes in CycloneDX SBOM
exports by default (<a
href="https://redirect.github.com/astral-sh/uv/pull/21131">#21131</a>)</li>
<li>Fall back to logical file sizes when using
<code>cache-physical-space</code> on filesystems that do not support
physical-space accounting (<a
href="https://redirect.github.com/astral-sh/uv/pull/21133">#21133</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Resolve relative package index paths in PEP 723 scripts against the
script directory (<a
href="https://redirect.github.com/astral-sh/uv/pull/21097">#21097</a>)</li>
</ul>
<h2>0.12.4</h2>
<p>Released on 2026-08-13.</p>
<h3>Enhancements</h3>
<ul>
<li>Prefer post-quantum key exchange and enable opt-in TLS diagnostics
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21054">#21054</a>)</li>
<li>Accept whitespace before versions in noncompliant wildcard
comparisons such as <code>Requires-Python: &gt;= 3.5.*</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21012">#21012</a>)</li>
<li>Report a specific error when a PEP 723 closing tag contains trailing
whitespace or other content (<a
href="https://redirect.github.com/astral-sh/uv/pull/20944">#20944</a>)</li>
<li>Omit source-span carets from diagnostics for empty PEP 508
requirements (<a
href="https://redirect.github.com/astral-sh/uv/pull/21094">#21094</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Add <code>uv check --no-install-project</code> and respect
<code>UV_NO_INSTALL_PROJECT</code> to install dependencies without
building or installing the project (<a
href="https://redirect.github.com/astral-sh/uv/pull/21085">#21085</a>)</li>
<li>Make the ty subprocess invoked by <code>uv check</code> honor uv's
color and progress settings, including quiet mode (<a
href="https://redirect.github.com/astral-sh/uv/pull/21086">#21086</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up resolutions with long runs of unavailable package versions
by coalescing gaps in the resolver's version ranges (<a
href="https://redirect.github.com/astral-sh/uv/pull/20804">#20804</a>)</li>
<li>Speed up Simple API parsing by deserializing PyPI and Pyx file
metadata directly (<a
href="https://redirect.github.com/astral-sh/uv/pull/21041">#21041</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Use windowed <code>pythonw.exe</code> launchers for virtual
environments created from managed Python minor-version links (<a
href="https://redirect.github.com/astral-sh/uv/pull/19235">#19235</a>)</li>
<li>Allow <code>uv lock</code> to proceed when <code>.venv</code> is an
unusable project environment (<a
href="https://redirect.github.com/astral-sh/uv/pull/21068">#21068</a>)</li>
<li>Respect <code>fork-strategy</code> when ordering forks created from
<code>environments</code> or existing lockfile
<code>resolution-markers</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21000">#21000</a>)</li>
<li>Preserve consecutive wildcard Python minor-version exclusions such
as <code>!=3.11.*, !=3.12.*</code> in <code>uv.lock</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21045">#21045</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/210d1f6785e95a8c8c0d53e284408c9be1134700"><code>210d1f6</code></a>
Bump version to 0.12.5 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21140">#21140</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/802a9162a1153ddee799a0080c80a38d96009d91"><code>802a916</code></a>
Sync latest Python releases: 3.10.21, 3.11.16, 3.12.14 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21138">#21138</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/a6904bbdabd3c6ac42b1051896ff597c8bd1895a"><code>a6904bb</code></a>
Order equal-priority Python installations by key (<a
href="https://redirect.github.com/astral-sh/uv/issues/21134">#21134</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/728a70d25c0889d9aaa53776256c3a843eea67a6"><code>728a70d</code></a>
Improve automated fixes for related bug manifestations (<a
href="https://redirect.github.com/astral-sh/uv/issues/21102">#21102</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/b82b0383fc3471227aa864f18d2c1c8efac8b9f1"><code>b82b038</code></a>
Include hashes in cyclonedx exports (<a
href="https://redirect.github.com/astral-sh/uv/issues/21131">#21131</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/8011778d41f2c96fb0b856fb3cbcb4ec8d28cb63"><code>8011778</code></a>
Simplify editable requirement errors and hints (<a
href="https://redirect.github.com/astral-sh/uv/issues/21130">#21130</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/dca33f5e6799f2aefee52729732a839a3b358740"><code>dca33f5</code></a>
Fall back to logical cache accounting on unsupported filesystems (<a
href="https://redirect.github.com/astral-sh/uv/issues/21133">#21133</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/3a76e496e36783371a6d91a8f4834478964d36ca"><code>3a76e49</code></a>
Get rid of <code>Lock::with_manifest</code>, make
<code>Lock::from_resolution</code> take the manif...</li>
<li><a
href="https://github.com/astral-sh/uv/commit/7e6caa45f62a0506fea1b8ecfa0558e5d62d520c"><code>7e6caa4</code></a>
Support referencing indexes by name via <code>--index</code> and
<code>--default-index</code> (<a
href="https://redirect.github.com/astral-sh/uv/issues/17455">#17455</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/298dda41bff49bbd0a2f397e1662ab09b9cd148e"><code>298dda4</code></a>
Fix relative indexes in PEP 723 scripts (<a
href="https://redirect.github.com/astral-sh/uv/issues/21097">#21097</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.11.3...0.12.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=astral-sh/uv&package-manager=docker&previous-version=0.11.3&new-version=0.12.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 01:57:00 -04:00
dependabot[bot] 0dc13c1ca4 build(deps): bump the gh-actions group with 5 updates (#1248)
Bumps the gh-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
|
[docker/setup-buildx-action](https://github.com/docker/setup-buildx-action)
| `4.2.0` | `4.3.0` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `9.0.0`
| `10.0.1` |
| [github/codeql-action/init](https://github.com/github/codeql-action) |
`4.37.6` | `4.37.7` |
|
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
| `4.37.6` | `4.37.7` |
|
[github/codeql-action/analyze](https://github.com/github/codeql-action)
| `4.37.6` | `4.37.7` |

Updates `docker/setup-buildx-action` from 4.2.0 to 4.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/setup-buildx-action/releases">docker/setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<ul>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.92.0 to 0.95.0 in
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/595">docker/setup-buildx-action#595</a></li>
<li>Bump brace-expansion from 1.1.13 to 1.1.18 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/600">docker/setup-buildx-action#600</a></li>
<li>Bump js-yaml from 5.2.0 to 5.3.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/585">docker/setup-buildx-action#585</a></li>
<li>Bump postcss from 8.5.10 to 8.5.25 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/598">docker/setup-buildx-action#598</a></li>
<li>Bump undici from 6.27.0 to 6.28.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/601">docker/setup-buildx-action#601</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/setup-buildx-action/compare/v4.2.0...v4.3.0">https://github.com/docker/setup-buildx-action/compare/v4.2.0...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/37fe631027851001ddb9b187196cc803df7f5f0e"><code>37fe631</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/595">#595</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/b5c4f91922681cc7c58d15ab7838986951f09d19"><code>b5c4f91</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/3e93b637c6430ba8fa896fad44d3aa6821899d63"><code>3e93b63</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.92.0 to
0.95.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/e527031b32c86649307d5d492506855f90470604"><code>e527031</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/600">#600</a>
from docker/dependabot/npm_and_yarn/brace-expansion-1...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/c68814b33cb66f1f7538e546190d410ae557a640"><code>c68814b</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/3f891b01bd5012a434f582800366972569aa1886"><code>3f891b0</code></a>
build(deps): bump brace-expansion from 1.1.13 to 1.1.18</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/787db26fcde8ddcabd49a81472318028f7113962"><code>787db26</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/585">#585</a>
from docker/dependabot/npm_and_yarn/js-yaml-5.2.1</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/f7793687c711790ca336bd4934f1b1bf5f778e17"><code>f779368</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/7d5e60413489a33d28077e11d71c668580cfaf8d"><code>7d5e604</code></a>
build(deps): bump js-yaml from 5.2.0 to 5.3.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/292c2fb3837a12d3ac2d1e47bbc5c00712bad939"><code>292c2fb</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/590">#590</a>
from docker/dependabot/github_actions/actions/setup-n...</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/setup-buildx-action/compare/bb05f3f5519dd87d3ba754cc423b652a5edd6d2c...37fe631027851001ddb9b187196cc803df7f5f0e">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 9.0.0 to 10.0.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v10.0.1 🌈 Tolerate transient manifest timeouts</h2>
<h2>Changes</h2>
<p>Thank you <a
href="https://github.com/arguile"><code>@​arguile</code></a>- for making
this action more resilient.</p>
<h2>🐛 Bug fixes</h2>
<ul>
<li>Tolerate transient manifest timeouts <a
href="https://github.com/arguile"><code>@​arguile</code></a>- (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1016">#1016</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>chore: update known checksums for 0.12.4 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1017">#1017</a>)</li>
</ul>
<h2>📚 Documentation</h2>
<ul>
<li>docs: update version references to v10.0.0 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1014">#1014</a>)</li>
</ul>
<h2>v10.0.0 🌈 Disable automatic caching for sensitive events and new QOL
features</h2>
<h2>Changes</h2>
<p>Another breaking release, directly after v9.0.0 but we think the
added security justifies that.</p>
<h3>Extra security by default</h3>
<p>If you use the default <code>enable-cache: auto</code> this will now
<strong>DISABLE THE CACHE</strong> to protect against cache poisoning
for the following events:</p>
<ul>
<li><code>pull_request_target</code></li>
<li><code>workflow_run</code></li>
<li><code>release</code></li>
</ul>
<p>You can read the full reasoning in <a
href="https://redirect.github.com/astral-sh/setup-uv/issues/984">astral-sh/setup-uv#984</a></p>
<h3><code>version: latest-known</code></h3>
<pre lang="yaml"><code>- name: Install the latest version of uv known to
setup-uv
  uses: astral-sh/setup-uv@v10.0.0
  with:
    version: &quot;latest-known&quot;
</code></pre>
<p>This will now install the latest version with a checksum that is
known by this action. The <a
href="https://github.com/astral-sh/setup-uv/blob/4f6036f71cec78afb113b323f220c9185d983c12/src/download/checksum/known-checksums.ts">known
<code>uv</code> checksums</a> are automatically updated but will take a
release of this action to take effect. You won't be always using the
latest &amp; greatest but you will have an extra level of security.</p>
<h3>Read python version from <code>.tool-versions</code></h3>
<pre lang="yaml"><code>- name: Install uv based on the version defined
in .tool-versions and also set python
  uses: astral-sh/setup-uv@v10.0.0
  with:
    version-file: &quot;pyproject.toml&quot;
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/20cfd1bf945f4377ade1205e4dbc17946fc9a30d"><code>20cfd1b</code></a>
chore: update known checksums for 0.12.4 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1017">#1017</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/d73a0cab66a532d7afa440d9df4a67ea9fe65a30"><code>d73a0ca</code></a>
Tolerate transient manifest timeouts (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1016">#1016</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/ae3b92d1bdb308a10adfe7b8f408e5cc8c30f3f6"><code>ae3b92d</code></a>
docs: update version references to v10.0.0 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1014">#1014</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d"><code>ae62891</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1013">#1013</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f9cdb47d487aee2be8925d1e57290177ad9e1ac2"><code>f9cdb47</code></a>
Reject paths in .tool-versions (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1007">#1007</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/4f6036f71cec78afb113b323f220c9185d983c12"><code>4f6036f</code></a>
Require pull requests for Dependabot rollups (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1005">#1005</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/8d6402c9b71205b2d8d0b82de531d8fed8430182"><code>8d6402c</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/1004">#1004</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/46f427bd47c794e99536b75ffaa9f27602425027"><code>46f427b</code></a>
Read Python version from .tool-versions (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/996">#996</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/8ed89c51143f65ea13eaba62db51dbb8ea52d0a3"><code>8ed89c5</code></a>
ci: pin Alpine container image (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/995">#995</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/8473c7fea42cdfd540f4b01317a17ac5f54126ae"><code>8473c7f</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/994">#994</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/c771a70e6277c0a99b617c7a806ffedaca235ff9...20cfd1bf945f4377ade1205e4dbc17946fc9a30d">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/init` from 4.37.6 to 4.37.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.7</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd"><code>ff2f1c6</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4093">#4093</a>
from github/update-v4.37.7-be7a3dbb8</li>
<li><a
href="https://github.com/github/codeql-action/commit/951a133f96aa2114dd747e9e437305335d0bde16"><code>951a133</code></a>
Update changelog for v4.37.7</li>
<li><a
href="https://github.com/github/codeql-action/commit/be7a3dbb8147b82cd6d27e0707105b36aa190fc1"><code>be7a3db</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4087">#4087</a>
from github/dependabot/npm_and_yarn/npm-minor-0aa561...</li>
<li><a
href="https://github.com/github/codeql-action/commit/9310334b11405b305d9444edfa56cd86e2f1e4fe"><code>9310334</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4086">#4086</a>
from github/mbg/thread-action-state-to-codeql</li>
<li><a
href="https://github.com/github/codeql-action/commit/b4d8a54218a8792de9af2f6f32e33af899ca5212"><code>b4d8a54</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/ab5db2519c3344f2fa61c711fa2d6ad135829200"><code>ab5db25</code></a>
Bump the npm-minor group across 1 directory with 8 updates</li>
<li><a
href="https://github.com/github/codeql-action/commit/38055a3c3cf3979323eaf70fc6c73a8690250bde"><code>38055a3</code></a>
Drop <code>logger</code> from <code>databaseInitCluster</code> in
interface</li>
<li><a
href="https://github.com/github/codeql-action/commit/1f87aed5e66849f0c43ae147377cc77f2d98ac99"><code>1f87aed</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4085">#4085</a>
from github/update-bundle/codeql-bundle-v2.26.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/dc1b98ad1c2f13ccf9fc33fb82f32fc76f944253"><code>dc1b98a</code></a>
Make <code>logger</code> available to <code>getCodeQLForCmd</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/6f0220ee37121218af472efbde25f06907a4da4f"><code>6f0220e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4084">#4084</a>
from github/navntoft/bump-undici</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.6 to 4.37.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.7</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd"><code>ff2f1c6</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4093">#4093</a>
from github/update-v4.37.7-be7a3dbb8</li>
<li><a
href="https://github.com/github/codeql-action/commit/951a133f96aa2114dd747e9e437305335d0bde16"><code>951a133</code></a>
Update changelog for v4.37.7</li>
<li><a
href="https://github.com/github/codeql-action/commit/be7a3dbb8147b82cd6d27e0707105b36aa190fc1"><code>be7a3db</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4087">#4087</a>
from github/dependabot/npm_and_yarn/npm-minor-0aa561...</li>
<li><a
href="https://github.com/github/codeql-action/commit/9310334b11405b305d9444edfa56cd86e2f1e4fe"><code>9310334</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4086">#4086</a>
from github/mbg/thread-action-state-to-codeql</li>
<li><a
href="https://github.com/github/codeql-action/commit/b4d8a54218a8792de9af2f6f32e33af899ca5212"><code>b4d8a54</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/ab5db2519c3344f2fa61c711fa2d6ad135829200"><code>ab5db25</code></a>
Bump the npm-minor group across 1 directory with 8 updates</li>
<li><a
href="https://github.com/github/codeql-action/commit/38055a3c3cf3979323eaf70fc6c73a8690250bde"><code>38055a3</code></a>
Drop <code>logger</code> from <code>databaseInitCluster</code> in
interface</li>
<li><a
href="https://github.com/github/codeql-action/commit/1f87aed5e66849f0c43ae147377cc77f2d98ac99"><code>1f87aed</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4085">#4085</a>
from github/update-bundle/codeql-bundle-v2.26.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/dc1b98ad1c2f13ccf9fc33fb82f32fc76f944253"><code>dc1b98a</code></a>
Make <code>logger</code> available to <code>getCodeQLForCmd</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/6f0220ee37121218af472efbde25f06907a4da4f"><code>6f0220e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4084">#4084</a>
from github/navntoft/bump-undici</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.6 to 4.37.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.7</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.7 - 13 Aug 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3">2.26.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4085">#4085</a></li>
</ul>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd"><code>ff2f1c6</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4093">#4093</a>
from github/update-v4.37.7-be7a3dbb8</li>
<li><a
href="https://github.com/github/codeql-action/commit/951a133f96aa2114dd747e9e437305335d0bde16"><code>951a133</code></a>
Update changelog for v4.37.7</li>
<li><a
href="https://github.com/github/codeql-action/commit/be7a3dbb8147b82cd6d27e0707105b36aa190fc1"><code>be7a3db</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4087">#4087</a>
from github/dependabot/npm_and_yarn/npm-minor-0aa561...</li>
<li><a
href="https://github.com/github/codeql-action/commit/9310334b11405b305d9444edfa56cd86e2f1e4fe"><code>9310334</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4086">#4086</a>
from github/mbg/thread-action-state-to-codeql</li>
<li><a
href="https://github.com/github/codeql-action/commit/b4d8a54218a8792de9af2f6f32e33af899ca5212"><code>b4d8a54</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/ab5db2519c3344f2fa61c711fa2d6ad135829200"><code>ab5db25</code></a>
Bump the npm-minor group across 1 directory with 8 updates</li>
<li><a
href="https://github.com/github/codeql-action/commit/38055a3c3cf3979323eaf70fc6c73a8690250bde"><code>38055a3</code></a>
Drop <code>logger</code> from <code>databaseInitCluster</code> in
interface</li>
<li><a
href="https://github.com/github/codeql-action/commit/1f87aed5e66849f0c43ae147377cc77f2d98ac99"><code>1f87aed</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4085">#4085</a>
from github/update-bundle/codeql-bundle-v2.26.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/dc1b98ad1c2f13ccf9fc33fb82f32fc76f944253"><code>dc1b98a</code></a>
Make <code>logger</code> available to <code>getCodeQLForCmd</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/6f0220ee37121218af472efbde25f06907a4da4f"><code>6f0220e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4084">#4084</a>
from github/navntoft/bump-undici</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 01:56:52 -04:00
dependabot[bot] d1f8527089 build(deps): bump the python-deps group across 1 directory with 5 updates (#1260)
Bumps the python-deps group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [gunicorn](https://github.com/benoitc/gunicorn) | `26.0.0` | `26.1.0`
|
| [apprise](https://github.com/caronc/apprise) | `1.12.0` | `1.13.0` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.51.12` | `4.52.1` |
| [prek](https://github.com/j178/prek) | `0.4.13` | `0.4.14` |
| [ruff](https://github.com/astral-sh/ruff) | `0.16.3` | `0.16.4` |


Updates `gunicorn` from 26.0.0 to 26.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/benoitc/gunicorn/releases">gunicorn's
releases</a>.</em></p>
<blockquote>
<h2>gunicorn 26.1.0</h2>
<h3>New Features</h3>
<ul>
<li><strong>Glob patterns in <code>reload_extra_files</code></strong>:
entries containing <code>*</code>, <code>?</code> or <code>[</code>
are treated as patterns, so <code>ui/*/config.json</code> watches every
view's config
without listing them one by one. Patterns are re-expanded on every
reload
check rather than once at startup, so a file created later starts being
watched without restarting gunicorn, and <code>**</code> recurses. A
pattern matching
nothing warns instead of failing, since with live expansion it may match
later
(<a
href="https://redirect.github.com/benoitc/gunicorn/issues/1643">#1643</a>,
<a
href="https://redirect.github.com/benoitc/gunicorn/pull/3662">#3662</a>).</li>
</ul>
<h3>Security</h3>
<ul>
<li><strong>Dependency floors raised past known advisories</strong>:
every declared floor was
checked against the advisory database. <code>tornado</code>,
<code>h2</code>, <code>setuptools</code> and
<code>pymdown-extensions</code> permitted vulnerable versions and now
require the first
clean release; <code>pytest</code> and <code>httpx</code> were unpinned
and now carry floors. The
<code>tornado</code> example pinned <code>tornado&lt;6</code>, which was
both the source of several
advisories and older than the <code>&gt;=6.5.0</code> the tornado worker
needs, so the
example could not run as pinned.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>
<p><strong>SIGHUP did not reload the logger configuration</strong>:
<code>Arbiter.reload()</code>
re-read the configuration file but kept using the logger built at
startup,
calling only <code>reopen_files()</code> on its existing handlers.
Changes to
<code>logconfig</code>, <code>logconfig_dict</code>,
<code>logconfig_json</code> and <code>loglevel</code> were ignored
until a full restart, which in containers meant replacing the pod. The
existing logger now re-runs its setup on reload, so new handlers,
formats
and levels take effect while the process identity and its listeners are
preserved, and re-running the setup no longer stacks duplicate syslog
handlers. An invalid log configuration on reload is not fatal either:
the
error is reported on stderr, the previous working configuration is
restored
and the master keeps running with it
(<a
href="https://redirect.github.com/benoitc/gunicorn/issues/3353">#3353</a>).</p>
</li>
<li>
<p><strong>Truncated chunked bodies accepted</strong>: RFC 9112 section
7.1.2 ends a chunked
body with <code>0 CRLF CRLF</code>, the second CRLF being the mandatory
empty trailer
section. <code>ChunkedReader.parse_chunk_size()</code> swallowed the
<code>NoMoreData</code> raised
while scanning for it, so a body cut short right after the last chunk
line was
treated as complete instead of rejected. It now raises
<code>ChunkMissingTerminator</code>
(<a
href="https://redirect.github.com/benoitc/gunicorn/issues/3382">#3382</a>,
<a
href="https://redirect.github.com/benoitc/gunicorn/pull/3685">#3685</a>).</p>
</li>
<li>
<p><strong><code>--spew</code> crashed on dynamically generated
code</strong>: the trace hook indexed the
2-tuple returned by <code>inspect.getsourcelines()</code> by line number
rather than
indexing the list of lines, so a frame with no <code>__file__</code>
raised
<code>AttributeError: 'int' object has no attribute 'rstrip'</code> on
line 1 and</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/benoitc/gunicorn/commit/71b59a75820dd4a762dc42a3280124168b4e44a8"><code>71b59a7</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3698">#3698</a>
from benoitc/fix/docker-health-check-readerror</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/48287de8d8360825c85ac981ddfe9c80dba3b418"><code>48287de</code></a>
test: catch every transport error in the docker health check</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/3110e8c37f716ca0ed63ca7f80c7c9ea0fbbdd50"><code>3110e8c</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3696">#3696</a>
from benoitc/docs/roadmap</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/cc56c410b7103c1f2b877279f81cb3a14705315a"><code>cc56c41</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3693">#3693</a>
from benoitc/release/26.1.0</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/5cf1f1651a40fa36afe13fde623e3437ca872463"><code>5cf1f16</code></a>
docs: surface the roadmap on the site home page</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/7e35f72d135056c37da321becf22b19aeec06937"><code>7e35f72</code></a>
docs: add FastCGI to the roadmap and point items at Ideas</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/18ddc586c9b9513b25e92c6ed6f818f66ff3abcd"><code>18ddc58</code></a>
docs: drop the framework and reverse-proxy non-goals from the
roadmap</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/1ecae56ebd096ee4f94d12c59a36f240ce348572"><code>1ecae56</code></a>
docs: add a roadmap and make the chat easy to find</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/ca412e3f7134bd9f0e91851778ae6d8dd222cf41"><code>ca412e3</code></a>
docs: sync the Latest changelog page with 26.1.0</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/640936fb29f7bdf5665d5b7f919783bb73e2f981"><code>640936f</code></a>
docs: note the dependency security work in 26.1.0</li>
<li>Additional commits viewable in <a
href="https://github.com/benoitc/gunicorn/compare/26.0.0...26.1.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `apprise` from 1.12.0 to 1.13.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/caronc/apprise/releases">apprise's
releases</a>.</em></p>
<blockquote>
<h2>Release v1.13.0</h2>
<h2>What's Changed</h2>
<p>This update clears out our backlog of resolved bugs and introduces a
few new services. While it’s a standard maintenance release, we want to
give a massive shoutout to our community. The level of support we've
received for this update is truly incredible; there were more
commits/PRs from you than there were from me and that has never happend
before 🙂 . Your contributions are deeply
appreciated! Seriously!</p>
<p><strong>Note:</strong> ⚠️ <strong>This will be the last version of
Apprise v1.x</strong>. Future releases will be under Apprise v2.x. This
means: Developers, <em>please</em> make sure you pin your
<code>projects.toml</code> or <code>requirements.txt</code> to
<code>apprise &gt;=1.0.0, &lt;2.0.0</code>. v2.x will be awesome, but it
will introduce breaking changes your software may need to adapt to. I
will still continue supporting the v1.x branch should security issues
arise for at year or two, but eventually v2.x would be the way to
go.</p>
<h3>📣 New Notification Services:</h3>
<ul>
<li>Added Pinglet Support by <a
href="https://github.com/TheGlenn88"><code>@​TheGlenn88</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1680">caronc/apprise#1680</a></li>
<li>Add Trigv notification support by <a
href="https://github.com/hchouhan"><code>@​hchouhan</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1671">caronc/apprise#1671</a></li>
<li>Added Pingram (formerly NotificationApi) by <a
href="https://github.com/lipusal"><code>@​lipusal</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1665">caronc/apprise#1665</a></li>
</ul>
<h3>🐞  Bugfixes</h3>
<ul>
<li>Preserve x/y coordinate of 0 in dbus/glib url() (round-trip crash on
x=0) by <a href="https://github.com/gaoflow"><code>@​gaoflow</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1663">caronc/apprise#1663</a></li>
<li>Allow RFC 3986 path characters that are safe to leave unencoded by
<a href="https://github.com/Sanjays2402"><code>@​Sanjays2402</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1673">caronc/apprise#1673</a></li>
<li>small bugfix in splunk entity_id handling on url in <a
href="https://redirect.github.com/caronc/apprise/pull/1688">caronc/apprise#1688</a></li>
<li>Fix Microsoft Workflows CU-routed webhooks by <a
href="https://github.com/Sanjays2402"><code>@​Sanjays2402</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1676">caronc/apprise#1676</a></li>
<li>Return None from parse_url() on malformed authority content (<a
href="https://redirect.github.com/caronc/apprise/issues/1693">#1693</a>)
by <a href="https://github.com/youdie006"><code>@​youdie006</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1694">caronc/apprise#1694</a></li>
<li>fix issue causing in memory email attachments to fail by <a
href="https://github.com/kevinfeyrer"><code>@​kevinfeyrer</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1696">caronc/apprise#1696</a></li>
</ul>
<h3>💡 Features</h3>
<ul>
<li>Improved handling matrix message splitting in <a
href="https://redirect.github.com/caronc/apprise/pull/1687">caronc/apprise#1687</a></li>
<li>feat(bark): add AES-GCM encryption by <a
href="https://github.com/IceCodeNew"><code>@​IceCodeNew</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1684">caronc/apprise#1684</a></li>
<li>fix(docs): CLI file attachments feature by <a
href="https://github.com/egvimo"><code>@​egvimo</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1678">caronc/apprise#1678</a></li>
<li>Support for Telegram rich message support in <a
href="https://redirect.github.com/caronc/apprise/pull/1690">caronc/apprise#1690</a></li>
</ul>
<h3>❤️ Life-Cycle Support</h3>
<ul>
<li>Fix grammar and tiny errors in README.md by <a
href="https://github.com/notrudyyy"><code>@​notrudyyy</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1674">caronc/apprise#1674</a></li>
<li>docs: quote pip extras install examples by <a
href="https://github.com/nyxst4ck"><code>@​nyxst4ck</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1679">caronc/apprise#1679</a></li>
<li>Decomissioned legacy service NotificationApi by <a
href="https://github.com/lipusal"><code>@​lipusal</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1665">caronc/apprise#1665</a></li>
<li>Fixed warnings emitted while running test suite in <a
href="https://redirect.github.com/caronc/apprise/pull/1689">caronc/apprise#1689</a></li>
<li>Proxy documentation added to man page in <a
href="https://redirect.github.com/caronc/apprise/pull/1691">caronc/apprise#1691</a></li>
<li>Updated github-action references to latest in <a
href="https://redirect.github.com/caronc/apprise/pull/1692">caronc/apprise#1692</a></li>
<li>Add Italian translation by <a
href="https://github.com/albanobattistella"><code>@​albanobattistella</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1670">caronc/apprise#1670</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/gaoflow"><code>@​gaoflow</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1663">caronc/apprise#1663</a></li>
<li><a
href="https://github.com/TheGlenn88"><code>@​TheGlenn88</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1680">caronc/apprise#1680</a></li>
<li><a href="https://github.com/egvimo"><code>@​egvimo</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1678">caronc/apprise#1678</a></li>
<li><a href="https://github.com/nyxst4ck"><code>@​nyxst4ck</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1679">caronc/apprise#1679</a></li>
<li><a href="https://github.com/notrudyyy"><code>@​notrudyyy</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1674">caronc/apprise#1674</a></li>
<li><a href="https://github.com/hchouhan"><code>@​hchouhan</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1671">caronc/apprise#1671</a></li>
<li><a
href="https://github.com/IceCodeNew"><code>@​IceCodeNew</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1684">caronc/apprise#1684</a></li>
<li><a
href="https://github.com/Sanjays2402"><code>@​Sanjays2402</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1673">caronc/apprise#1673</a></li>
<li><a href="https://github.com/lipusal"><code>@​lipusal</code></a> made
their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1665">caronc/apprise#1665</a></li>
<li><a
href="https://github.com/albanobattistella"><code>@​albanobattistella</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1670">caronc/apprise#1670</a></li>
<li><a href="https://github.com/youdie006"><code>@​youdie006</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1694">caronc/apprise#1694</a></li>
<li><a
href="https://github.com/kevinfeyrer"><code>@​kevinfeyrer</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1696">caronc/apprise#1696</a></li>
</ul>
<h2>Installation</h2>
<p>Apprise is available <a href="https://pypi.org/project/apprise/">on
PyPI</a> through <em>pip</em>:</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/caronc/apprise/commit/cf17bc9ecd2686c62b548b4577b6e06839331a60"><code>cf17bc9</code></a>
bumped version to v1.13.0</li>
<li><a
href="https://github.com/caronc/apprise/commit/c41f802190ff07a71edb98683c2094f04b5b9fc2"><code>c41f802</code></a>
in-memory email attachments no longer fail (<a
href="https://redirect.github.com/caronc/apprise/issues/1696">#1696</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/6ebddd3a19a9076d1c0feca410f5e61bf9c927f5"><code>6ebddd3</code></a>
Return None from parse_url() on malformed authority content (<a
href="https://redirect.github.com/caronc/apprise/issues/1694">#1694</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/6b8cb1364360c9af61190faa248d0ef4187daaa0"><code>6b8cb13</code></a>
Add Italian translation (<a
href="https://redirect.github.com/caronc/apprise/issues/1670">#1670</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/468d26f3b49c4de8dd21a44f1db99288c79247f6"><code>468d26f</code></a>
Updated github-action plugins to latest supported versions (<a
href="https://redirect.github.com/caronc/apprise/issues/1692">#1692</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/73c8512a5c518e4c601d6a32c53feabbc2a9e0fa"><code>73c8512</code></a>
Support for Telegram rich message support (<a
href="https://redirect.github.com/caronc/apprise/issues/1690">#1690</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/fac5056b8cb50d725f83744ff26636ded60f9f46"><code>fac5056</code></a>
fixed issue causing time based xmpp tests to randomly fail</li>
<li><a
href="https://github.com/caronc/apprise/commit/2c48a87d1bfb5f5afa6a40775f6d3fb8fef2d2e4"><code>2c48a87</code></a>
Proxy documentation added to man page (<a
href="https://redirect.github.com/caronc/apprise/issues/1691">#1691</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/094073af543726a52f29672f31ca060f2f8e31b0"><code>094073a</code></a>
relaxed and improved on unit-tests time restrictions</li>
<li><a
href="https://github.com/caronc/apprise/commit/cc2dffb3ccc6a6ee4cf0a6979c9881fe06b43b78"><code>cc2dffb</code></a>
Fixed warnings emitted while running test suite (<a
href="https://redirect.github.com/caronc/apprise/issues/1689">#1689</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/caronc/apprise/compare/v1.12.0...v1.13.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.12 to 4.52.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.52.1 - Fix timeout issue with executing scripts</h2>
<h2>Fix timeout issue with executing scripts</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e55bcc7a9f544cbb2ea9ad0c9d4fc358d36c055f">Fix
timeout issue with executing scripts in Selenium Mode</a>
--&gt; (See the next commit where the fix was moved to a
<code>finally</code> block)</li>
<li><strong><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a5e37fd41813e92ed60cb7554781d5ba3aae6ef4">Improve
the earlier commit that fixes the script timeout issue</a></strong>
--&gt; (A method that changed the default timeout wasn't resetting it
back afterward)
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4467">seleniumbase/SeleniumBase#4467</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/37ace079c94bb9e08d4604387fbce13876ac00fb">Update
examples</a>
--&gt; (Updates some examples after changes were made on the site being
tested)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Fix timeout issue with executing scripts by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4468">seleniumbase/SeleniumBase#4468</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.52.0...v4.52.1">https://github.com/seleniumbase/SeleniumBase/compare/v4.52.0...v4.52.1</a></p>
<h2>4.52.0 - CDP Mode: Patch 129</h2>
<h2>CDP Mode: Patch 129</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/814c21ed7d0e94d459778b32db8be1fe7eb85ba5">Update
CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a3f0b5715fdb2d42e8ca53a043c173555f0ce097">Improve
output from driver downloads</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/17d723fb302ca7eb8a5604c05306a57688494499">Drop
support for Python 3.9</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0b7cc37597bfdc1e008b6176a8cb793760da534a">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/99327cc58df60a9cce7cd0e50588e806d65e90c3">Add
scraping examples</a></li>
</ul>
<h3>Resolutions:</h3>
<ul>
<li>This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4461">seleniumbase/SeleniumBase#4461</a></li>
<li>This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4462">seleniumbase/SeleniumBase#4462</a></li>
<li>This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4463">seleniumbase/SeleniumBase#4463</a></li>
<li>This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4464">seleniumbase/SeleniumBase#4464</a></li>
<li>This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4465">seleniumbase/SeleniumBase#4465</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 129 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4466">seleniumbase/SeleniumBase#4466</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.12...v4.52.0">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.12...v4.52.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c71edd581a72bfe46a21c1099a39f2ef8af5aa04"><code>c71edd5</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4468">#4468</a>
from seleniumbase/fix-timeout-issue-with-executing-s...</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a5e37fd41813e92ed60cb7554781d5ba3aae6ef4"><code>a5e37fd</code></a>
Improve the earlier commit that fixes the script timeout issue</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cd7b8945ca0298be0f7a8f6578ad4313107ed7c9"><code>cd7b894</code></a>
Version 4.52.1</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/37ace079c94bb9e08d4604387fbce13876ac00fb"><code>37ace07</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e55bcc7a9f544cbb2ea9ad0c9d4fc358d36c055f"><code>e55bcc7</code></a>
Fix timeout issue with executing scripts in Selenium mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b2207cb2ff3f0849de5ece7b9e81402983f857d5"><code>b2207cb</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4466">#4466</a>
from seleniumbase/cdp-mode-patch-129</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0be0f562c918bef4c27ab19c5b3068a28aff8835"><code>0be0f56</code></a>
Version 4.52.0</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/44e9d8564ce6afd764941219916e464174badac3"><code>44e9d85</code></a>
Update the ReadMe</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/99327cc58df60a9cce7cd0e50588e806d65e90c3"><code>99327cc</code></a>
Add scraping examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0b7cc37597bfdc1e008b6176a8cb793760da534a"><code>0b7cc37</code></a>
Refresh Python dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.12...v4.52.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.13 to 0.4.14
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.14</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-17.</p>
<h3>Enhancements</h3>
<ul>
<li>Support check-yaml unsafe mode (<a
href="https://redirect.github.com/j178/prek/pull/2546">#2546</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reuse allocations in common filters (<a
href="https://redirect.github.com/j178/prek/pull/2548">#2548</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Accept non-finite floats in check-yaml (<a
href="https://redirect.github.com/j178/prek/pull/2545">#2545</a>)</li>
<li>Allow comment-heavy YAML in check-yaml (<a
href="https://redirect.github.com/j178/prek/pull/2554">#2554</a>)</li>
<li>Sanitize captured terminal output before replay (<a
href="https://redirect.github.com/j178/prek/pull/2552">#2552</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.14</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.14/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.14/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.4.14</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-x86_64-apple-darwin.tar.gz">prek-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-aarch64-pc-windows-msvc.zip">prek-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.14/prek-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.14</h2>
<p>Released on 2026-08-17.</p>
<h3>Enhancements</h3>
<ul>
<li>Support check-yaml unsafe mode (<a
href="https://redirect.github.com/j178/prek/pull/2546">#2546</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reuse allocations in common filters (<a
href="https://redirect.github.com/j178/prek/pull/2548">#2548</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Accept non-finite floats in check-yaml (<a
href="https://redirect.github.com/j178/prek/pull/2545">#2545</a>)</li>
<li>Allow comment-heavy YAML in check-yaml (<a
href="https://redirect.github.com/j178/prek/pull/2554">#2554</a>)</li>
<li>Sanitize captured terminal output before replay (<a
href="https://redirect.github.com/j178/prek/pull/2552">#2552</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/432eeb08a4d9fe760817ce8d3d75ed3ebf7d3943"><code>432eeb0</code></a>
Bump version to 0.4.14 (<a
href="https://redirect.github.com/j178/prek/issues/2571">#2571</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6b6d429319dabac1911b26ce6cb6f04bb814951a"><code>6b6d429</code></a>
Update Rust crate ignore to v0.4.33 (<a
href="https://redirect.github.com/j178/prek/issues/2564">#2564</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/27d0cf8cb309f7b889d2b355254dc96957bbd60c"><code>27d0cf8</code></a>
Update prek hooks (<a
href="https://redirect.github.com/j178/prek/issues/2555">#2555</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/aaf407bb098b624620eac3855e6818b3fa2c4ab0"><code>aaf407b</code></a>
Update Rust crate aws-lc-rs to v1.18.0 (<a
href="https://redirect.github.com/j178/prek/issues/2569">#2569</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3ddddfd494b87dc0ddee4e7694d1ead3ac4277b7"><code>3ddddfd</code></a>
Update Rust crate xml to v1.4.0 (<a
href="https://redirect.github.com/j178/prek/issues/2570">#2570</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/fc90ec6c8a7b1519691b221bae5224064248a37d"><code>fc90ec6</code></a>
Update Rust crate similar to v3.1.2 (<a
href="https://redirect.github.com/j178/prek/issues/2567">#2567</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/50e60d412350fcef8bc9e50755bd4ea357a45328"><code>50e60d4</code></a>
Update Rust crate thiserror to v2.0.20 (<a
href="https://redirect.github.com/j178/prek/issues/2568">#2568</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/70a4c0635352987f55b995ecd768f1e8a2f9c9db"><code>70a4c06</code></a>
Update Rust crate liblzma to v0.4.8 (<a
href="https://redirect.github.com/j178/prek/issues/2565">#2565</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/7b8dcaa4579449a9a656889398e7d380bd117b08"><code>7b8dcaa</code></a>
Update Rust crate globset to v0.4.20 (<a
href="https://redirect.github.com/j178/prek/issues/2563">#2563</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3e075d33a5584a8b0f467c39eac3833a8efd4da2"><code>3e075d3</code></a>
Update Rust crate clap_complete to v4.6.9 (<a
href="https://redirect.github.com/j178/prek/issues/2562">#2562</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.13...v0.4.14">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.3 to 0.16.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.4</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-20.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-use-pathlib</code>] Add autofix for
<code>PTH116</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26460">#26460</a>)</li>
<li>[<code>refurb</code>] Restrict <code>delete-full-slice</code> to
lists (<code>FURB131</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27711">#27711</a>)</li>
<li>[<code>refurb</code>] Skip <code>FURB101</code> and
<code>FURB103</code> when the <code>open</code> argument is a file
descriptor (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27643">#27643</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix <code>InvalidInstruction</code> on Windows CPUs that do not
support <code>POPCNT</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27803">#27803</a>)</li>
<li>[<code>pyflakes</code>] Emit semantic syntax errors in string type
definitions as <code>F722</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27835">#27835</a>)</li>
<li>[<code>pylint</code>] Allow <code>os._exit</code> imports in
<code>import-private-name</code> (<code>PLC2701</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27738">#27738</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[syntax-errors] Align mixed t-string/bytes error message with
CPython 3.14 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27766">#27766</a>)</li>
<li>[<code>ruff</code>] Add <code>ctypes.LittleEndianStructure</code>
and related types to existing exception (<code>RUF012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27753">#27753</a>)</li>
<li>[syntax-errors] Detect duplicate keyword arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/17804">#17804</a>)</li>
<li>[syntax-errors] Detect parameters declared <code>nonlocal</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27628">#27628</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Offer display-only fixes and mark safe fixes preferred (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27807">#27807</a>)</li>
<li>Support pull diagnostics for notebook cells (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27779">#27779</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add default indicator to rules table (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27724">#27724</a>)</li>
<li>Fix broken link to Python docs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27757">#27757</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Fix s390x stacker assembly in release builds (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27776">#27776</a>)</li>
<li>Guarantee minimum stack size when parsing a module, standalone
expression, and suites (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25464">#25464</a>)</li>
<li>Reduce configuration deserialization code size (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27924">#27924</a>)</li>
<li>Check packed AST index bounds (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27849">#27849</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/AbhinavMir"><code>@​AbhinavMir</code></a></li>
<li><a
href="https://github.com/eduardorittner"><code>@​eduardorittner</code></a></li>
<li><a href="https://github.com/royb3"><code>@​royb3</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/carljm"><code>@​carljm</code></a></li>
<li><a
href="https://github.com/rosstitmarsh"><code>@​rosstitmarsh</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.4</h2>
<p>Released on 2026-08-20.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-use-pathlib</code>] Add autofix for
<code>PTH116</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26460">#26460</a>)</li>
<li>[<code>refurb</code>] Restrict <code>delete-full-slice</code> to
lists (<code>FURB131</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27711">#27711</a>)</li>
<li>[<code>refurb</code>] Skip <code>FURB101</code> and
<code>FURB103</code> when the <code>open</code> argument is a file
descriptor (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27643">#27643</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix <code>InvalidInstruction</code> on Windows CPUs that do not
support <code>POPCNT</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27803">#27803</a>)</li>
<li>[<code>pyflakes</code>] Emit semantic syntax errors in string type
definitions as <code>F722</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27835">#27835</a>)</li>
<li>[<code>pylint</code>] Allow <code>os._exit</code> imports in
<code>import-private-name</code> (<code>PLC2701</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27738">#27738</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[syntax-errors] Align mixed t-string/bytes error message with
CPython 3.14 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27766">#27766</a>)</li>
<li>[<code>ruff</code>] Add <code>ctypes.LittleEndianStructure</code>
and related types to existing exception (<code>RUF012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27753">#27753</a>)</li>
<li>[syntax-errors] Detect duplicate keyword arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/17804">#17804</a>)</li>
<li>[syntax-errors] Detect parameters declared <code>nonlocal</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27628">#27628</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Offer display-only fixes and mark safe fixes preferred (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27807">#27807</a>)</li>
<li>Support pull diagnostics for notebook cells (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27779">#27779</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add default indicator to rules table (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27724">#27724</a>)</li>
<li>Fix broken link to Python docs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27757">#27757</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Fix s390x stacker assembly in release builds (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27776">#27776</a>)</li>
<li>Guarantee minimum stack size when parsing a module, standalone
expression, and suites (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25464">#25464</a>)</li>
<li>Reduce configuration deserialization code size (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27924">#27924</a>)</li>
<li>Check packed AST index bounds (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27849">#27849</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/AbhinavMir"><code>@​AbhinavMir</code></a></li>
<li><a
href="https://github.com/eduardorittner"><code>@​eduardorittner</code></a></li>
<li><a href="https://github.com/royb3"><code>@​royb3</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/carljm"><code>@​carljm</code></a></li>
<li><a
href="https://github.com/rosstitmarsh"><code>@​rosstitmarsh</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/11c76bf48fdac06b2f240cba502eda96da4dce77"><code>11c76bf</code></a>
Bump 0.16.4 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27937">#27937</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d53c8c58662ca0576ddd502aa1a2979acf03832f"><code>d53c8c5</code></a>
Isolate playground builds from deployment credentials (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27839">#27839</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/cab001e5dec22f55653021f1f7be449e47c7d81e"><code>cab001e</code></a>
Disable uv preview for releases and pre-commit hooks (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27939">#27939</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f8d575fedc97e75ea62c679d77afb14246afa88e"><code>f8d575f</code></a>
[ty] Clarify writing guidance for human readers (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27912">#27912</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ca45faebb1750a213df19ed7f686ee5cf9277f93"><code>ca45fae</code></a>
Set <code>--preview</code> and <code>--default-index</code> for the
<code>uv-lock</code> hook (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27935">#27935</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/4827bf7cb449055e46fbfaf4b26e5125883a0569"><code>4827bf7</code></a>
Export <code>UV_DEFAULT_INDEX</code> in <code>release.sh</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27934">#27934</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d1087a4b9e03d253a88703f34e0869ee4b805456"><code>d1087a4</code></a>
[ty] Handle assignment expressions in string annotations (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27921">#27921</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/680cce48b6d89ab5b1566e4b797bd4847d861815"><code>680cce4</code></a>
[ty] Optimize inherited recursive protocol comparisons (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27922">#27922</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/974d3cbc04520c112843d6b92577844587402e04"><code>974d3cb</code></a>
Upgrade ecosystem-analyzer and mypy_primer to the latest upstream pins
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/27932">#27932</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b169b402356d0676451f4a7bc6903da2644b31eb"><code>b169b40</code></a>
Install cargo tools locked (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27929">#27929</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.3...0.16.4">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 01:56:46 -04:00
CaliBrain 95e34670f7 fix/group archive extracted audiobooks (#1261)
- fix: group multi-file audiobooks that arrive as an archive
- Surface the concrete reason when a direct-download fetch fails
2026-08-24 01:25:00 -04:00
CaliBrain 7d56624ab6 fix: group multi-file audiobooks that arrive as an archive (#1254)
Follow-up to #1237. \`rename_and_group\` only grouped when the source
root was a directory, so a multi-file audiobook delivered as a single
archive fell through to the flat path: a \`Book.zip\` of twelve chapters
landed loose in the destination root with its original chapter names —
the layout #1181 is about.

The \`is_dir()\` guard was there to keep \`Book.zip/\` from becoming the
folder name, but skipping the file case gives up the grouping instead of
naming it. A non-directory source can only produce several book files by
having been extracted (\`collect_staged_files\` returns a single-element
list for every other file shape), so the archive stem is the release
name and the suffix is packaging: group under \`Book/\`.

Also regenerates the env docs for the new option and gives it the same
\"do not use with ingest folders\" caveat Rename and Organize carries,
since both now create directories in the destination.

Tested: reverting only the source fix makes both new tests fail and the
\`rename\` control case pass, so grouping stays opt-in. Full non-e2e
suite green (2653 passed).
2026-08-21 10:43:06 -04:00
f4421ff189 fix: preserve multi-file audiobook folders (#1237)
Pass the effective source root from `process_folder_output` into
`transfer_book_files`, and have the transfer layer select a sanitized
child directory named after that source root when an audiobook has
multiple files and its organization mode is `none` or `rename`. Create
that grouping directory before applying the existing hardlink/copy/move
logic so operation accounting, torrent seeding preservation, collision
handling, cleanup, and custom-script final paths continue to use the
established production path. Completed multi-file audiobook torrents
arrive as a directory whose chapter filenames may not identify the book,
but folder output currently sends every discovered chapter directly to
the configured destination in `none` and `rename` modes. This flattens
chapters from unrelated books together and causes directory-oriented
consumers such as Audiobookshelf to interpret individual chapters as
separate books.

A multi-file audiobook torrent in the default `rename` mode copies or
hardlinks all supported chapter files beneath `<destination>/<original
torrent directory>/` with their original chapter filenames, and places
no chapters directly in the destination root; A multi-file audiobook in
`none` mode receives the same source-folder grouping without renaming
its chapter files.

Fixes #1181

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-08-21 09:44:08 -04:00
CaliBrain e7007865a4 fix(prowlarr): stop turning indexer failures into empty results and 404s (#1251)
Two independent bugs, both from an indexer that Prowlarr proxies rather
than answers for itself: the search never reported that it had failed,
and the grab never resolved what it was handed.

Search. A Torznab search is Prowlarr proxying a live request out to the
tracker, so for a Cloudflare-fronted indexer it waits on FlareSolverr.
The client gave it the 30s budget sized for Prowlarr's own JSON
endpoints, then swallowed every failure -- the timeout, the 429 Prowlarr
returns once it has disabled an indexer, a parse error -- into the same
empty list that means "this indexer has nothing". A cold challenge
routinely runs past a minute, so the UI said "No releases found for this
book" while FlareSolverr was still solving. That empty list also drove
the auto-expand retry, which fires on "no results with the category
filter". A timeout satisfies it, so Shelfmark sent a second search to an
indexer still busy with the first -- two Chromes at once, enough to take
FlareSolverr's down on a small host.

torznab_search now raises ProwlarrSearchError, and an empty list
strictly
means the indexer answered with no matches. The source records which
indexer searches failed: one dead indexer no longer sinks the others,
auto-expand runs only when every indexer genuinely answered, and zero
results with at least one failure raises SourceUnavailableError, which
the releases endpoint already turns into a 503 carrying a real message.
Prowlarr being unreachable was the same lie by another route -- the
indexer list came back empty, leaving nothing to query -- and now says
so.

Indexer searches also get their own timeout, PROWLARR_INDEXER_TIMEOUT,
defaulting to 90s and clamped to 5-300. Prowlarr's status and indexer
list keep 30s so Test Connection stays responsive, and the connect
timeout is split out at 10s so an unreachable Prowlarr fails fast rather
than hanging for the whole read budget. The overall per-request search
budget now scales to twice the indexer timeout, capped at 240s, so
raising the setting is not undone by the cap one level up while staying
under the 300s gunicorn worker timeout.

Grab. Prowlarr hands out a proxy download URL, with no magnetUrl and no
infoHash, for any indexer that only publishes torrent files. The native
Real-Debrid client built its magnet as "if not
url.startswith('magnet:') and expected_hash", so with no hash to work
from it left the URL alone and POSTed it to /torrents/addMagnet as the
magnet field. Real-Debrid answered 404 and the grab died on a raw HTTP
error. AllDebrid carried the same line and the same bug.

Both now resolve the URL first, through the extract_torrent_info path
the
torrent clients have used since #1108: pass a magnet through untouched,
follow a redirect or a response body that turns out to be a magnet,
otherwise upload the fetched .torrent, and fall back to a magnet built
from the infoHash only when the fetch failed. The file is preferred over
a synthesized urn:btih: magnet because it carries the tracker list; a
bare hash leaves the service to find the swarm on DHT alone. Fetches are
shared with the rest of the add path through the torrent fetch cache, so
resolving costs at most one request. Real-Debrid takes the file on PUT
/torrents/addTorrent with the raw bytes as the request body, AllDebrid
on
POST /magnet/upload/file as multipart files[]. A URL that resolves to
neither form now raises before any request reaches the service, so the
user reads why instead of a 404. Neither debrid client had any test
coverage; both have some now.

Fixes #1249
Fixes #1250
2026-08-21 09:07:03 -04:00
CaliBrain 5b3df2a463 docs(hardcover): list the API key scopes Shelfmark needs (#1243)
Hardcover's August 2026 token system replaced blanket access with
per-token scopes, and nothing in the docs said which ones Shelfmark
actually uses. A key missing write:library or write:lists still passes
Test Connection -- the reading-status and auto-remove-on-download calls
just fail silently afterwards.

Verified against a live hc_pat_ key: every scope in the table backs a
query or mutation the provider really issues, and the omitted ones
(journal, goals, reviews, prompts, notifications, account) are absent
from the provider entirely.

Refs #1240
2026-08-20 19:29:55 -04:00
CaliBrain 5247ec6124 fix(bypass): close the gaps a helper that outlives its request opened (#1244)
assumptions the code around it still made were written for a helper that
was killed after every request.

A bypass that hits the child's deadline is cancelled from the calling
thread, which returns the moment the cancellation is scheduled - so the
helper went on to serve the next request while the abandoned one was
still closing its browser, on the same loop, sharing the DISPLAY globals
and one process group. The deadline now lives inside the loop, where
asyncio.wait_for() waits for the unwind before it raises, with the
calling thread keeping a bounded backstop in case the cleanup wedges
too. Both budgets are set so the child still answers before the parent
gives up on it.

The helper's cookie store survived the request as well, and the whole of
it is exported back to the parent on every answer - so clearance the
parent had purged for one host came back the next time some other host
was solved, the dead-cookie resurrection _redirect_loop_handoff purges
to avoid. The child starts each request from an empty store again; the
parent already runs the cached-cookie check against a superset of it.

DNS config is compared against what the helper is actually resolving
through rather than skipped whenever the parent reports "auto", so a
user flipping CUSTOM_DNS back to auto - which applies live - reaches a
warm helper instead of leaving it on an abandoned DoH resolver.

The 15s exit grace is now asked only of a helper that can still read its
stdin. One dropped mid-bypass never returns to that read, so the grace
could only end in the kill - while a user cancelling a download, and
every bypass queued behind them on LOCKED, waited it out.

Result files are cleaned on the timeout and cancellation paths too,
staging file included, rather than only when the answer was read.
2026-08-20 19:29:33 -04:00
CaliBrain bd21ec1257 fix(audiobookbay): search the ASCII punctuation ABB actually stores (#1242)
WordPress texturizes punctuation on output only, so a post stored as
"The
Stranger's Wife" renders as "The Stranger’s Wife". ABB's search matches
the
stored value and ANDs its terms, so one typographic character in the
query
empties the entire result set rather than merely ranking worse. Book
metadata
and mobile keyboards both hand us those characters.

Map curly quotes, dashes and ellipses to ASCII before a query goes out,
and on
both sides of the relevance comparison, since scraped titles carry the
rendered
forms. Release titles are still stored and displayed exactly as ABB
renders
them; only matching normalizes.

Also percent-encode the search query properly. The hand-rolled encoder
only
escaped double quotes and spaces, so a bare "&" started a new query
parameter
and silently truncated the search: "detective dan riley books 1 & 2
weatherley"
reached ABB as "detective dan riley books 1" and returned six
confident-looking
results without the requested book among them. "%" and "+" were mangled
too.
2026-08-20 19:00:27 -04:00
helgehelge123andhelgehelge123 7b9c416df8 perf(bypass): keep the helper subprocess alive between bypasses (#1222)
Every protected request spawns a fresh helper subprocess, paying
interpreter start and imports before any work begins. Measured inside
the container, five consecutive runs of `python -c "import
shelfmark.bypass.internal_bypasser"`:

```
3.53s  3.45s  3.55s  3.54s  3.46s
```

A single search issues several protected requests, so that is paid
several times over per search.

## What changed

The helper now serves one JSON request per line of stdin until the
parent closes the pipe, and an idle timer
(`BYPASS_BROWSER_IDLE_TIMEOUT`, default 180s) shuts it down once
searching stops.

Answers still travel by result file, but the file is now written to a
`.part` path and renamed into place — the parent treats the file's
existence as the answer, so it must never observe a half-written one.
stdout and stderr stay attached to the parent's, so helper logs keep
appearing in `docker logs` exactly as before.

Failure handling, since a warm helper is exposed to more of it than a
per-request one ever was:

| Situation | Handling |
| --- | --- |
| Helper died between requests | Detected via `poll()`, respawned |
| Pipe broken at write time (`poll()` can miss this) | One retry on a
fresh process; a fresh one failing there is a real failure |
| Helper exits without writing a result | `RuntimeError` naming the exit
code |
| Wedged past the timeout, or cancelled mid-bypass | Helper killed, then
`_cleanup_orphan_processes` because a killed helper never got to close
Chrome |
| Idle reaper racing an arriving request | Re-checks the deadline under
the lock and re-arms instead of killing a helper that just did work |

The DNS config now travels with every request rather than only at spawn:
a warm helper outlives changes the parent makes to its provider.

## `BYPASS_REUSE_BROWSER`, off by default

This parks the CDP driver between bypasses. A driver's websockets are
bound to the loop that opened them and cannot outlive their process, so
the persistent helper is what makes this possible at all — and the warm
path runs on `_CDP_WORKER`'s long-lived loop rather than `asyncio.run`
for the same reason.

The mechanism works. With it on, the browser start disappears from the
second request onward: 0.7s from `Reusing warm Chrome browser` to the
first bypass attempt, against roughly 16s cold.

**It still ships off, because a matched-pair test shows it is a net loss
against DDoS-Guard.** Each round primed with one cold bypass, waited
10s, then measured a second — identical timing in both arms, only the
browser strategy differing, order balanced (fresh, warm, warm, fresh) so
drift over the session cannot masquerade as an effect:

| Arm | Measured request |
| --- | --- |
| fresh browser | 42.8s, 40.6s |
| warm browser | 57.1s, 59.6s |

Spread within each arm is 2.2s and 2.5s, against 16.7s between them.
Reuse removes the ~15s browser start and then gives back roughly twice
that in solving: a returning browser draws a harder challenge. Where the
cold browser is through on the second bypass method, the warm one fails
the first three and only `_bypass_method_humanlike` gets it, at ~30s for
that method alone.

Worth separating from a second effect I ran into while measuring: five
back-to-back searches slow from ~32s to 51–98s with reuse **disabled**
as well, so DDoS-Guard escalates on request rate independently of any of
this. That is why the pairs above are timed identically rather than
simply run in sequence. It is the larger of the two effects, but not
something this project can patch around.

Reuse is left available rather than dropped because Cloudflare sites may
not respond the same way, and because the two concerns are independent:
the helper start is pure overhead and always worth removing, the browser
is not.

## Verification

- 2559 unit tests pass (2542 before, 17 added in
`tests/bypass/test_warm_browser.py`)
- `ruff check`, `ruff format`, `basedpyright` over backend and tests,
and `vulture` all clean
- `docs/environment-variables.md` regenerated via
`scripts/generate_env_docs.py`
- Live against Anna's Archive on a warm helper: searches return their
usual ~760KB and 667 results, the app's own search warm-up completes
with 50 results, and the container is left with no orphan
chrome/Xvfb/ffmpeg processes

Happy to drop the `BYPASS_REUSE_BROWSER` half entirely if you would
rather not carry a default-off path — the helper persistence stands on
its own.

Co-authored-by: helgehelge123 <helge.neumann@zollsoft.de>
2026-08-20 19:00:06 -04:00
CaliBrain 646b531669 fix(hardcover): accept the short hc_pat_ keys Hardcover issues now (#1241)
Hardcover replaced its ~500 char JWTs with short opaque personal access
tokens ("hc_pat_..."), and the connection test rejected anything under
100 chars before a request ever left Shelfmark, so every newly created
key failed with "API key seems too short".

The length floor now applies only to keys without the hc_pat_ prefix; a
prefixed key goes straight to Hardcover, which is the authority on
whether it is valid. Also strip a pasted "bearer " prefix regardless of
casing -- Hardcover's docs tell users to paste the token into an
"authorization" header, so the prefix rides along on the copy, and the
old case-sensitive removeprefix() sent it through as part of the token.
The API key field now names the expected shape.

Note that Hardcover's PAT path currently answers every hc_pat_ token
with a 500, a fabricated one included, while non-PAT tokens still get a
clean 401. So a new key cannot connect yet regardless of this change --
that failure is server-side and not something this code can reach.

Refs #1240
2026-08-20 14:42:45 -04:00
dependabot[bot] eafb965662 build(deps): bump qbittorrent-api from 2026.8.0 to 2026.8.1 in the python-deps group (#1236)
Bumps the python-deps group with 1 update:
[qbittorrent-api](https://github.com/rmartin16/qbittorrent-api).

Updates `qbittorrent-api` from 2026.8.0 to 2026.8.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/releases">qbittorrent-api's
releases</a>.</em></p>
<blockquote>
<h2>release-2026.8.1</h2>
<h2>What's Changed</h2>
<h3>Features</h3>
<ul>
<li>feat: add missing <code>torrents/add</code> and
<code>torrents/reannounce</code> parameters by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/656">rmartin16/qbittorrent-api#656</a></li>
<li>feat: add endpoints shipped in qBittorrent v5.2.x by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/658">rmartin16/qbittorrent-api#658</a></li>
</ul>
<h3>Fixes</h3>
<ul>
<li>fix: accept and forward <code>**kwargs</code> on all API methods by
<a href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in
<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/655">rmartin16/qbittorrent-api#655</a></li>
<li>fix: send <code>seedMode</code> for <code>is_skip_checking</code> on
Web API v2.16.0 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/654">rmartin16/qbittorrent-api#654</a></li>
<li>docs: correct version annotations by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/657">rmartin16/qbittorrent-api#657</a></li>
</ul>
<h3>Chores</h3>
<ul>
<li>Bump cryptography from 48.0.1 to 50.0.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/652">rmartin16/qbittorrent-api#652</a></li>
<li>retire codeql by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/660">rmartin16/qbittorrent-api#660</a></li>
<li>remove xfail for previous python 3.15 issue by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/638">rmartin16/qbittorrent-api#638</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.8.0...v2026.8.1">https://github.com/rmartin16/qbittorrent-api/compare/v2026.8.0...v2026.8.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md">qbittorrent-api's
changelog</a>.</em></p>
<blockquote>
<h3>v2026.8.1 (16 aug 2026)</h3>
<ul>
<li>Add support for <code>app/rotateAPIKey</code> and
<code>app/deleteAPIKey</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li>Add support for <code>torrents/SSLParameters</code> and
<code>torrents/setSSLParameters</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li>Add support for <code>torrents/fetchMetadata</code>,
<code>torrents/parseMetadata</code>, and
<code>torrents/saveMetadata</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li>Add support for <code>torrents/pieceAvailability</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li>Add support for <code>clientdata/load</code> and
<code>clientdata/store</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li>Add <code>file_priorities</code> and <code>downloader</code> for
<code>torrents/add</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/656">#656</a>)</li>
<li>Add <code>urls</code> for <code>torrents/reannounce</code> (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/656">#656</a>)</li>
<li>Fix <code>is_skip_checking</code> for <code>torrents/add</code>
being ignored by qBittorrent v5.3.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/654">#654</a>)</li>
<li>Fix missing <code>**kwargs</code> for several endpoints (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/655">#655</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/97e5f577df0bcfd4a7986c79e8d21e88ae8e64d0"><code>97e5f57</code></a>
bump to v2026.8.1 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/661">#661</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/39e05d109dbb427b1e75a33fc96903ee22e3abd3"><code>39e05d1</code></a>
remove xfail for previous python 3.15 issue (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/638">#638</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/0c067fdd356b3c2da0cdfbc1501c3badeb697e22"><code>0c067fd</code></a>
feat: add endpoints shipped in qBittorrent v5.2.x (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/658">#658</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/64f65eacb62d33b54449ef413047779f6d766022"><code>64f65ea</code></a>
fix: send seedMode for is_skip_checking on Web API v2.16.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/654">#654</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/f302ac473a66d3943878bf8491080f3ab800264e"><code>f302ac4</code></a>
docs: correct version annotations (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/657">#657</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/cd9650277f572d26b1c2c09ff8e86a9917cfe435"><code>cd96502</code></a>
feat: add missing torrents/add and torrents/reannounce parameters (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/656">#656</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/7ed08865b11e6f57c7ef0395e8d929c8842de340"><code>7ed0886</code></a>
fix: accept and forward **kwargs on all API methods (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/655">#655</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/0b293e28356e74b3aead64ac3fd1e02e85d5de87"><code>0b293e2</code></a>
retire codeql (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/660">#660</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/fd276e2d918c31d78528acc280fbbd36b354cf88"><code>fd276e2</code></a>
Bump cryptography from 48.0.1 to 50.0.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/652">#652</a>)</li>
<li>See full diff in <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.8.0...v2026.8.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qbittorrent-api&package-manager=uv&previous-version=2026.8.0&new-version=2026.8.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-20 10:49:39 -04:00
CaliBrain 7193036626 fix(rtorrent): apply the audiobook label to audiobook downloads (#1239)
add_download() picks self._audiobook_label from a content_type kwarg,
but the only call site never passed one, so is_audiobook was always
False and every download got RTORRENT_LABEL. category does not fill
the gap: _get_category_for_task() returns None for rTorrent, which has
no category concept, leaving content_type as its only audiobook signal.

Pass task.content_type through from base_handler, and match it with the
shared is_audiobook() helper instead of == "audiobook".
normalize_content_type()
treats "book (audiobook)" as an audiobook, so the exact-string check
would have mislabeled that value even once it arrived.

The existing rTorrent tests passed content_type straight to the client,
which is why nothing caught the missing wiring; the new handler test
covers the call site itself.

Post-processing was never affected: destination.py reads
task.content_type directly, so files already landed in
DESTINATION_AUDIOBOOK correctly.

Fixes #1235
2026-08-20 10:39:50 -04:00
CaliBrain 12d554a92f fix(download): hand a 503 carrying a challenge to the bypasser (#1238)
503 is in RETRYABLE_CODES, and the bypasser is only ever reached from
the 403
branch and the AA redirect-loop rescues. Once Z-Library re-serves its
DDoS-Guard
interstitial with the same cookie the #1188 handshake already echoed
back, the
request has nothing left to try and spends every attempt on the same
wall.

Gate the handoff on the response body rather than the status, so a
genuine
overloaded-origin 503 keeps its retry path, and on
allow_bypasser_fallback, so
best-effort fetches still fail fast. The challenge indicators move out
of
internal_bypasser into shelfmark/bypass/challenge.py so http.py can use
them
without importing SeleniumBase, which is lazily imported precisely
because it
is optional.

Refs #1233
2026-08-20 10:29:52 -04:00
CaliBrain fae6140c6a fix(bypass): scope browser cleanup to the calling session (#1232)
The orphan sweep ran a container-wide 'pkill -9 -f
chrome|chromium|Xvfb|ffmpeg', so it also matched browsers another bypass
was still driving. Scope it by process group: kill only our own group
and groups whose leader has died. Spawn the helper with
start_new_session so its browser tree is identifiable, tear the whole
group down after every run (a timed-out helper used to leak its Chrome
and Xvfb), and have an orphaned helper take its browser down with it.
Fixes #1231.
2026-08-18 23:24:43 -04:00
dependabot[bot] 63133097e4 build(deps): update httpx[http2] requirement from >=0.27 to >=0.28.1 (#1227)
Updates the requirements on
[httpx[http2]](https://github.com/encode/httpx) to permit the latest
version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/encode/httpx/releases">httpx[http2]'s
releases</a>.</em></p>
<blockquote>
<h2>Version 0.28.1</h2>
<h2>0.28.1 (6th December, 2024)</h2>
<ul>
<li>Fix SSL case where <code>verify=False</code> together with client
side certificates.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/encode/httpx/blob/master/CHANGELOG.md">httpx[http2]'s
changelog</a>.</em></p>
<blockquote>
<h2>0.28.1 (6th December, 2024)</h2>
<ul>
<li>Fix SSL case where <code>verify=False</code> together with client
side certificates.</li>
</ul>
<h2>0.28.0 (28th November, 2024)</h2>
<p>Be aware that the default <em>JSON request bodies now use a more
compact representation</em>. This is generally considered a prefered
style, tho may require updates to test suites.</p>
<p>The 0.28 release includes a limited set of deprecations...</p>
<p><strong>Deprecations</strong>:</p>
<p>We are working towards a simplified SSL configuration API.</p>
<p><em>For users of the standard <code>verify=True</code> or
<code>verify=False</code> cases, or
<code>verify=&lt;ssl_context&gt;</code> case this should require no
changes. The following cases have been deprecated...</em></p>
<ul>
<li>The <code>verify</code> argument as a string argument is now
deprecated and will raise warnings.</li>
<li>The <code>cert</code> argument is now deprecated and will raise
warnings.</li>
</ul>
<p>Our revised <a
href="https://github.com/encode/httpx/blob/master/docs/advanced/ssl.md">SSL
documentation</a> covers how to implement the same behaviour with a more
constrained API.</p>
<p><strong>The following changes are also included</strong>:</p>
<ul>
<li>The deprecated <code>proxies</code> argument has now been
removed.</li>
<li>The deprecated <code>app</code> argument has now been removed.</li>
<li>JSON request bodies use a compact representation. (<a
href="https://redirect.github.com/encode/httpx/issues/3363">#3363</a>)</li>
<li>Review URL percent escape sets, based on WHATWG spec. (<a
href="https://redirect.github.com/encode/httpx/issues/3371">#3371</a>,
<a
href="https://redirect.github.com/encode/httpx/issues/3373">#3373</a>)</li>
<li>Ensure <code>certifi</code> and <code>httpcore</code> are only
imported if required. (<a
href="https://redirect.github.com/encode/httpx/issues/3377">#3377</a>)</li>
<li>Treat <code>socks5h</code> as a valid proxy scheme. (<a
href="https://redirect.github.com/encode/httpx/issues/3178">#3178</a>)</li>
<li>Cleanup <code>Request()</code> method signature in line with
<code>client.request()</code> and <code>httpx.request()</code>. (<a
href="https://redirect.github.com/encode/httpx/issues/3378">#3378</a>)</li>
<li>Bugfix: When passing <code>params={}</code>, always strictly update
rather than merge with an existing querystring. (<a
href="https://redirect.github.com/encode/httpx/issues/3364">#3364</a>)</li>
</ul>
<h2>0.27.2 (27th August, 2024)</h2>
<h3>Fixed</h3>
<ul>
<li>Reintroduced supposedly-private <code>URLTypes</code> shortcut. (<a
href="https://redirect.github.com/encode/httpx/issues/2673">#2673</a>)</li>
</ul>
<h2>0.27.1 (27th August, 2024)</h2>
<h3>Added</h3>
<ul>
<li>Support for <code>zstd</code> content decoding using the python
<code>zstandard</code> package is added. Installable using
<code>httpx[zstd]</code>. (<a
href="https://redirect.github.com/encode/httpx/issues/3139">#3139</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Improved error messaging for <code>InvalidURL</code> exceptions. (<a
href="https://redirect.github.com/encode/httpx/issues/3250">#3250</a>)</li>
<li>Fix <code>app</code> type signature in <code>ASGITransport</code>.
(<a
href="https://redirect.github.com/encode/httpx/issues/3109">#3109</a>)</li>
</ul>
<h2>0.27.0 (21st February, 2024)</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/encode/httpx/commit/26d48e0634e6ee9cdc0533996db289ce4b430177"><code>26d48e0</code></a>
Version 0.28.1 (<a
href="https://redirect.github.com/encode/httpx/issues/3445">#3445</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/89599a9541af14bcf906fc4ed58ccbdf403802ba"><code>89599a9</code></a>
Fix <code>verify=False</code>, <code>cert=...</code> case. (<a
href="https://redirect.github.com/encode/httpx/issues/3442">#3442</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/8ecb86f0d74ffc52d4663214fae9526bee89358d"><code>8ecb86f</code></a>
Add test for request params behavior changes (<a
href="https://redirect.github.com/encode/httpx/issues/3364">#3364</a>)
(<a
href="https://redirect.github.com/encode/httpx/issues/3440">#3440</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/0cb7e5a2e736628e2f506d259fcf0d48cd2bde82"><code>0cb7e5a</code></a>
Bump the python-packages group with 11 updates (<a
href="https://redirect.github.com/encode/httpx/issues/3434">#3434</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/15e21e9ea3cad4f06e22a7e704aabefdf43d2e29"><code>15e21e9</code></a>
Updating deprecated docstring Client() class (<a
href="https://redirect.github.com/encode/httpx/issues/3426">#3426</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/80960fa31918d7663c3f4c3ad61661cf0e80628f"><code>80960fa</code></a>
Version 0.28.0. (<a
href="https://redirect.github.com/encode/httpx/issues/3419">#3419</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/a33c87852b8a0dddc65e5f739af1e0a6fca4b91f"><code>a33c878</code></a>
Fix <code>extensions</code> type annotation. (<a
href="https://redirect.github.com/encode/httpx/issues/3380">#3380</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/ce7e14da27abba6574be9b3ea7cd5990556a9343"><code>ce7e14d</code></a>
Error on verify as str. (<a
href="https://redirect.github.com/encode/httpx/issues/3418">#3418</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/47f4a96ffaaaa07dca1614409549b5d7a6e7af49"><code>47f4a96</code></a>
Handle empty zstd responses (<a
href="https://redirect.github.com/encode/httpx/issues/3412">#3412</a>)</li>
<li><a
href="https://github.com/encode/httpx/commit/189fc4bcbe5f314128775dec66a616ac9a31ad48"><code>189fc4b</code></a>
Update CHANGELOG.md, fix typo(s) (<a
href="https://redirect.github.com/encode/httpx/issues/3406">#3406</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/encode/httpx/compare/0.27.0...0.28.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 22:22:06 -04:00
dependabot[bot] 82aeee387e build(deps-dev): bump the python-deps group with 2 updates (#1226)
Bumps the python-deps group with 2 updates:
[basedpyright](https://github.com/detachhead/basedpyright) and
[ruff](https://github.com/astral-sh/ruff).

Updates `basedpyright` from 1.39.9 to 1.39.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/detachhead/basedpyright/releases">basedpyright's
releases</a>.</em></p>
<blockquote>
<h2>v1.39.10 (pyright 1.1.412)</h2>
<h2>What's Changed</h2>
<ul>
<li>add <code>allowedUntypedLibraries</code> and
<code>failOnWarnings</code> to <code>pyrightconfig.schema.json</code> by
<a href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in
<a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1851">DetachHead/basedpyright#1851</a></li>
<li>Update pycharm setup instructions by <a
href="https://github.com/charliecloudberry"><code>@​charliecloudberry</code></a>
in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1862">DetachHead/basedpyright#1862</a></li>
<li>Merge 1.1.412 by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1869">DetachHead/basedpyright#1869</a></li>
<li>fix redundant <code>workspace/configuration</code> request by <a
href="https://github.com/DetachHead"><code>@​DetachHead</code></a> in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1847">DetachHead/basedpyright#1847</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/vmphase"><code>@​vmphase</code></a> made
their first contribution in <a
href="https://redirect.github.com/DetachHead/basedpyright/pull/1866">DetachHead/basedpyright#1866</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/DetachHead/basedpyright/compare/v1.39.9...v1.39.10">https://github.com/DetachHead/basedpyright/compare/v1.39.9...v1.39.10</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/6d830bac284253dc6587d35eb026a9a30aee7771"><code>6d830ba</code></a>
1.39.10</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/a34496c27eb0805e4ac39976361526c92d6b3f59"><code>a34496c</code></a>
fix redundant <code>workspace/configuration</code> request</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/b3074fe4dfa981a1928aebc4d9694ae4e5c03fc9"><code>b3074fe</code></a>
fix links in tsp docs</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/979a3fc4d9a86c018a11aeebf17822c468b71ab2"><code>979a3fc</code></a>
add <code>nodejs-wheel</code> back as a dev dependency</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/285225059bae1e3d41b7ff198d8f1d3e07b7141a"><code>2852250</code></a>
ignore <code>mypy_primer/build</code> in bpr</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/5c4427f639c26a4917747ebd5d133ca425e807cc"><code>5c4427f</code></a>
baseline type errors from new upstream python file</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/ae420b5e0cbcad508d93f603282c5e2614d58182"><code>ae420b5</code></a>
try to fix primer</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/0e5c88e47a8ee57ab73b37702a72997976706405"><code>0e5c88e</code></a>
fixes from merge</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/78adf4f989315b4821d30c3b79f0a0aa3732bb07"><code>78adf4f</code></a>
don't support TSP</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/eff463de301edaf268c816a2be618de4c40b6b62"><code>eff463d</code></a>
Merge tag '1.1.412' into merge-1.1.412</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.9...v1.39.10">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.2 to 0.16.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.3</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-13.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pylint</code>] Fix false negatives on negative numbers
(<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27251">#27251</a>)</li>
<li>[<code>pyupgrade</code>] Add rule to replace <code>while 1</code>
with <code>while True</code> (<code>UP048</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27190">#27190</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bandit</code>] Also check keyword arguments
(<code>S602</code>, <code>S603</code>, <code>S607</code>,
<code>S609</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27687">#27687</a>)</li>
<li>[<code>pylint</code>] Allow <code>continue</code> in
<code>finally</code> on Python 3.8 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27626">#27626</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLE1307</code> false positive with
bools (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27651">#27651</a>)</li>
<li>[<code>pylint</code>] Fix false positives and negatives with
<code>%b</code> format character (<code>PLE1300</code>,
<code>PLE1307</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27560">#27560</a>)</li>
<li>[<code>pylint</code>] Improve handling of concatenated strings
(<code>PLE1300</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27659">#27659</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>numpy</code>] Make <code>np.chararray</code> autofix
backwards-compatible (<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27527">#27527</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Enable PGO for Linux x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27570">#27570</a>)</li>
<li>Enable PGO for Linux ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27574">#27574</a>)</li>
<li>Enable PGO for Windows x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27573">#27573</a>)</li>
<li>Enable PGO for macOS ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27572">#27572</a>)</li>
<li>Reduce <code>Expr</code> size to 64 bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27591">#27591</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Hyperlink rule codes in <code>ruff check --statistics</code> output
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27646">#27646</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>ruff</code>] Also suggest <code>asyncio.TaskGroup</code>
(<code>RUF006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27461">#27461</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Use mimalloc v3 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27586">#27586</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Andrej730"><code>@​Andrej730</code></a></li>
<li><a
href="https://github.com/alonfaraj"><code>@​alonfaraj</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.3</h2>
<p>Released on 2026-08-13.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pylint</code>] Fix false negatives on negative numbers
(<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27251">#27251</a>)</li>
<li>[<code>pyupgrade</code>] Add rule to replace <code>while 1</code>
with <code>while True</code> (<code>UP048</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27190">#27190</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bandit</code>] Also check keyword arguments
(<code>S602</code>, <code>S603</code>, <code>S607</code>,
<code>S609</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27687">#27687</a>)</li>
<li>[<code>pylint</code>] Allow <code>continue</code> in
<code>finally</code> on Python 3.8 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27626">#27626</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLE1307</code> false positive with
bools (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27651">#27651</a>)</li>
<li>[<code>pylint</code>] Fix false positives and negatives with
<code>%b</code> format character (<code>PLE1300</code>,
<code>PLE1307</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27560">#27560</a>)</li>
<li>[<code>pylint</code>] Improve handling of concatenated strings
(<code>PLE1300</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27659">#27659</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>numpy</code>] Make <code>np.chararray</code> autofix
backwards-compatible (<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27527">#27527</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Enable PGO for Linux x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27570">#27570</a>)</li>
<li>Enable PGO for Linux ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27574">#27574</a>)</li>
<li>Enable PGO for Windows x86-64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27573">#27573</a>)</li>
<li>Enable PGO for macOS ARM64 Ruff releases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27572">#27572</a>)</li>
<li>Reduce <code>Expr</code> size to 64 bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27591">#27591</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Hyperlink rule codes in <code>ruff check --statistics</code> output
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27646">#27646</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>ruff</code>] Also suggest <code>asyncio.TaskGroup</code>
(<code>RUF006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27461">#27461</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Use mimalloc v3 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27586">#27586</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Andrej730"><code>@​Andrej730</code></a></li>
<li><a
href="https://github.com/alonfaraj"><code>@​alonfaraj</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/tjkuson"><code>@​tjkuson</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/chirizxc"><code>@​chirizxc</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/b0e47022cfce4f3594aa26d15ea792681430b6f6"><code>b0e4702</code></a>
Bump 0.16.3 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27723">#27723</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ecdd401fdbc5b0b22e18759c8bd25cda452e8b32"><code>ecdd401</code></a>
[ty] Separate script and uv modules from project metadata (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27720">#27720</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/126352467217bebfa4cb86fd3c4d20820322d9e3"><code>1263524</code></a>
[ty] Simplify display implementations with std::fmt::from_fn (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27718">#27718</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/59196baedf23c9876d1fcf1fa2ae78f80d306f94"><code>59196ba</code></a>
[ty] Unify polarity-aware relation construction (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27707">#27707</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b8c5e73abe5b15a74fb066e474d30397d1421cfe"><code>b8c5e73</code></a>
[ty] Disable CodSpeed cycle estimation for instrumented benchmarks (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27706">#27706</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/2b0d21094e2a55491bff60c07fd6f8803876cae5"><code>2b0d210</code></a>
[ty] Centralize matched argument relations (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27705">#27705</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/a9130f3381fe137626d22288c0d45f996541ca7e"><code>a9130f3</code></a>
[<code>pyupgrade</code>] Add rule to replace <code>while 1</code> with
<code>while True</code> (<code>while-one</code>, `...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c64c7d6dad1e0a4966ce578b2c03af1e8e7673e1"><code>c64c7d6</code></a>
[ty] Model try exception flow with operation checkpoints (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27471">#27471</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/9dea5ef180b3de748b5fe45787056716f235d11a"><code>9dea5ef</code></a>
[ty] Avoid deriving sequents for typevars with concrete bounds (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27587">#27587</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/9798e88de673ec73051980ebd9aeb681161f3c27"><code>9798e88</code></a>
[ty] Preserve enum exhaustiveness with custom <em>missing</em> methods
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/27700">#27700</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.2...0.16.3">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 22:21:52 -04:00
CaliBrain 4cd1091d16 fix(hardcover): send the field count Hardcover's Book search requires (#1224)
Advanced title search, advanced title+author search, and the title
typeahead returned zero results every time, and the sort fallback added
in #1183 blamed the sort value for it.

Hardcover turns the `fields` search parameter into Typesense's
`query_by`
but keeps `num_typos` and `query_by_weights` as fixed-length presets per
query_type. For query_type=Book the preset expects exactly five fields,
so a shorter list is not searched loosely - the whole search is rejected
with a null results body. Confirmed against the live API: 1, 2, 3, 4 and
6 fields are all rejected, only 5 works, and weights must match
one-for-one when sent. Every Book-type list we sent was the wrong length
- the title typeahead and advanced title search sent 2, title+author
sent 3.

- Send BOOK_SEARCH_FIELDS (the full five) for every narrowed Book search
  and express the intent through weights instead. Weights only bias
  ranking - a field weighted 0 still matches - so a title search now
  ranks titles first rather than restricting to them. That is the
  closest behaviour Hardcover still allows, and there is no client-side
  filter to restore the old precision.
- Pin the field and weight counts in tests, since the failure mode is a
  silent zero results rather than an error.

The sort fallback from #1183 also misread these rejections:

- Select the `error` field on every search and log Hardcover's own
  explanation. The reason is only ever in that sibling field, so a
  rejection surfaced as "returned no result body" with nothing to act
  on. Reading it is what made the field-count rule findable.
- Drop `sort` entirely on the retry instead of sending an empty string.
  An empty sort is a value like any other and can be rejected too.
- Arm the 900s sticky window only after the sortless retry succeeds. It
  was armed before the retry and never rolled back, so one rejected
  typeahead disabled sorting process-wide for 15 minutes whatever the
  actual cause.

Verified against the live Hardcover API: advanced title search 0 -> 84
results, title+author 0 -> 139, title typeahead 0 -> 84 with the exact
title top. 2566 unit tests pass; ruff, basedpyright and vulture clean.

Refs #1183. The sort_by regression #1183 was written for is gone from
Hardcover's side - every sort value it rejected, including the one in
the report, is accepted again today. Two plain-search rejections in that
report (fields=None) remain unexplained: they could not be reproduced
under any per_page, page depth, sort value or query shape, and are most
likely transient upstream. They now self-report the reason if they
recur.
2026-08-16 20:55:08 -04:00
CaliBrain 651096ed7b fix(bypass): reuse external bypasser clearance instead of re-solving (#1223)
Direct download was unusable behind an external bypasser (FlareSolverr /
Byparr): every request paid a 403 plus a full solve, and a search that
never ran was reported to the user as "No books found".

Clearance was discarded on the external path. get_cf_cookies_for_domain
and get_cf_user_agent_for_domain returned {} / None whenever
USING_EXTERNAL_BYPASSER was set, and _fetch_via_bypasser read only
solution.response - dropping solution.cookies and solution.userAgent,
which FlareSolverr-compatible services do return. A solve therefore
cleared the one request that paid for it and nothing else, and a file
download - which the solver cannot proxy, being binary - presented no
clearance at all. Diagnosed from a v1.3.9 debug bundle: ~35s in the
bypasser per search, on every search.

- Move the cookie jar out of internal_bypasser into bypass/cookie_store.
  internal_bypasser imports seleniumbase at module scope, which is the
  dependency an external-bypasser deployment is entitled not to have, so
  it cannot host a store the external path depends on.
- Harvest solution.cookies and solution.userAgent after a successful
  solve. The existing filtering applies unchanged, so the per-check
  __ddg8_/__ddg9_/__ddg10_ trio is still dropped and the external path
  cannot reintroduce the ?check=1 loop fixed in ebb833a. The UA matters
  as much as the cookies: Cloudflare ties cf_clearance to the UA that
  solved the challenge.
- Read cookie fields from either shape - CDP objects or JSON mappings.
  Both use the same field names, expires included.
- Point http.py's getters and _purge_clearance at the shared store, so
  either bypasser fills and drains the same jar.
- Give the Docker helper-subprocess handoff explicit export_store /
  import_store rather than reaching into module globals.

An unsolved challenge was also indistinguishable from an empty result.
_looks_like_aa_page() counted the challenge markers as "recognisably
AA", so _fetch_search_table handed a DDoS-Guard interstitial back as a
legitimate no-table response and the user was told their query found
nothing when the search never ran. Split challenge detection out and
raise SearchUnavailableError with the reason instead. The mirror is
still not quarantined - every mirror shares the same protection, so it
is not the mirror's fault.

Verified: 2531 unit tests pass; ruff, basedpyright and vulture clean;
e2e bypasser-external profile passes (5). Its mock FlareSolverr already
returned cookies and userAgent from /v1 - the contract was there,
shelfmark was not reading it.

Refs #1220. Deliberately not "Fixes": this removes the re-solve and
makes a failed solve legible, but if Byparr genuinely cannot clear AA's
current DDoS-Guard, the reporter now gets that as an error rather than a
silent "no books found". The download path may swallow interstitials the
same way; not audited here.
2026-08-16 12:08:45 -04:00
CaliBrain ebb833a82c fix(bypass): discard rejected DDoS-Guard cookies instead of replaying them (#1221)
A cookie that has been rejected was kept and presented again on every
later
request, so a single bad clearance could re-arm the challenge
indefinitely.

Cookie storage:
- Enforce expiry for every stored cookie, not just cf_clearance.
DDoS-Guard
domains have no cf_clearance, so the existing check never fired for them
and
  expired cookies were replayed forever.
- Stop storing the per-check cookies __ddg8_/__ddg9_/__ddg10_ and
ddg_last_challenge. Captured live from Anna's Archive, these carry the
client
IP and the timestamp the check was issued (~40 min), versus ~1 year for
the
  __ddg1_/__ddg2_/__ddgid_ clearance. Replaying an IP-bound token stops
describing the caller as soon as the egress IP changes, which is routine
  behind a VPN.

Failure handling — every path that is rejected while carrying cookies
now
purges them, not just the redirect loop:
- 403 returned while presenting cookies.
- Cached-cookie attempt rejected, whether by status or by redirect loop.
- Factored the purge into _purge_clearance, guarded on a non-empty
hostname
since clear_cf_cookies("") means "every host" and would wipe clearance
for
  sites that are working fine.

Also fix the search warm-up switches shipped inert in v1.3.8:
SEARCH_WARMUP_ENABLED and SEARCH_WARMUP_QUERY are not in the settings
registry, and config.get only consults the environment for keys it
knows, so
both always returned their defaults — the warm-up could not be turned
off or
retargeted. Read os.environ first.

Refs #1220. Deliberately not "Fixes": the reported failure could not be
reproduced on v1.3.8 from a stable IP (the reporter's own queries all
returned
200 on both the pre- and post-change builds), and the new purge paths
did not
fire in live testing because the failures arrive as redirect loops,
which were
already purged. These are correctness fixes with no measured effect on
that
issue. The underlying problem remains that Chrome-obtained cookies never
satisfy DDoS-Guard when replayed by requests, so every search still
re-solves.

Verified: 2542 unit tests pass; ruff, basedpyright and vulture clean;
e2e
platform baseline (10), full (6) and bypasser-external (5) all pass;
five
sequential live searches against Anna's Archive all returned 200 with
zero
"Exceeded 30 redirects".
2026-08-15 17:08:11 -04:00
CaliBrain b7093f4594 Fix log to debug DNS (#1219) 2026-08-15 15:30:29 -04:00
CaliBrain b656f019be feat(download): add DoH wireformat support, mirror quarantine, and search warmup (#1218)
- Add RFC 8484 DNS wireformat codec and HTTP/2 support (httpx) for
Quad9/OpenDNS DoH providers.
- Quarantine dead, parked, or seized mirrors for the session on hard
failure (DNS errors, connection refused, 410/451, parked pages) while
preserving bypass clearance on live mirrors.
- Add background startup search warmup to prime DNS, elect mirrors, and
pre-solve protection challenges to eliminate cold-start search latency.
- Add comprehensive test suites for DoH wireformat, mirror quarantine,
parked domain detection, and search warmup.
2026-08-15 14:17:44 -04:00
CaliBrain 6e96ead519 Fix frontend timeout search (#1217) 2026-08-15 13:44:09 -04:00
CaliBrain 7345f6be1a Fix README and hints for audiobooks (#1215) 2026-08-15 12:19:58 -04:00
CaliBrain 2b8b35bb52 fix(newznab): make indexer book categories configurable (#1214)
Newznab searches hardcoded category 7000 for ebooks and 3030 for
audiobooks,
so indexers using custom IDs returned no results or the wrong ones. Add
NEWZNAB_EBOOK_CATEGORIES and NEWZNAB_AUDIOBOOK_CATEGORIES (tag lists,
defaulting to 7000 and 3030) and resolve the search categories from
config.

Values are parsed leniently — list or comma/whitespace separated,
non-numeric
entries skipped, duplicates dropped — and fall back to the standard IDs
when
empty, so a cleared field can't silently widen the search to every
category.
NEWZNAB_AUTO_EXPAND remains the way to do that on purpose.

Results carrying a custom ID outside the standard 7000-7999 / 3030
ranges were
typed as "other", which routed custom-category audiobooks as ebooks.
Trust the
searched content type when a result carries a category we explicitly
asked for.

Also drop the unused NEWZNAB_BOOKS / NEWZNAB_AUDIOBOOKS constants from
api.py —
a third copy of the same hardcoding.

Closes #1208
2026-08-15 11:48:10 -04:00
FlozeandCaliBrain 58a5b5ed27 fix: sync renamed CWA usernames safely (#1203)
## Summary

- sync an existing CWA-backed user's username when CWA renames it
- keep username collisions safe by assigning a stable `__cwa` alias
instead of overwriting a local account
- allow username updates through `UserDB` and cover
rename/collision/repeat-sync behavior

Fixes #1197.

## Testing

- `uv run ruff check shelfmark tests`
- `uv run ruff format --check shelfmark tests`
- `uv run vulture shelfmark`
- `uv run pytest tests/core/test_cwa_user_sync.py
tests/core/test_user_db.py tests/core/test_admin_users_api.py
tests/core/test_auth_api.py -k "cwa or update_user"` (36 passed)
- `uv run pytest tests/ -x --tb=short -m "not integration and not e2e"
--ignore=tests/config/test_entrypoint_permissions.py -q` (2445 passed, 5
skipped)

The entrypoint permission tests were excluded locally because macOS
ships Bash 3.2, which does not support the `${1,,}` expansion used by
`entrypoint.sh`; the same failure reproduces on an unchanged checkout.
`make python-typecheck` also currently reports the existing
`settings.py:147` callback return-type mismatch on the unchanged base.

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-08-15 11:40:32 -04:00
Sujeito OperatorandCaliBrain 52c1702419 docker: mount uv at build time instead of copying it into every image (#1200)
### What this PR does

`uv` stops being copied into the image and starts being mounted into the
three `RUN`s that
actually use it. The digest pin stays in exactly one place — it moves
from the `COPY` to a
stage declaration:

```dockerfile
FROM ghcr.io/astral-sh/uv:0.11.3@sha256:90bbb3c... AS uv
```
```dockerfile
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=from=uv,source=/uv,target=/usr/local/bin/uv \
    uv sync --locked --no-default-groups
```

A stage consumed only through `--mount=from=` contributes no layer to
anything published, so
`uv` never lands in `base`. The two `RUN rm -f /usr/bin/uv /usr/bin/uvx`
lines then have nothing
left to delete and go with it.

### Why

The `base` stage copies uv in, and both final stages try to take it back
out:

```dockerfile
# uv is only needed while building the image.
RUN rm -f /usr/bin/uv /usr/bin/uvx
```

That intent is exactly right. **The mechanism can't carry it out**: a
`RUN` adds a layer, it
does not rewrite the layer underneath. The `COPY` layer is still pushed
and still pulled by
everyone. What the `rm` produces is a whiteout on top of it.

### Measured, not assumed

Read off the published images over the registry API — `linux/amd64`,
both built
`2026-08-13T17:53Z`, pinned by digest so these numbers stay reproducible
after tonight's
scheduled rebuild:

```
ghcr.io/calibrain/shelfmark@sha256:9b6041f797cbcc1e5c50ab42bd010a8f747dfaac926080cb6269ddfae99cf820
  layer  COPY /uv /uvx /bin/                        24.3 MB   of 585 MB total   4.1% of the pull
  layer  RUN rm -f /usr/bin/uv /usr/bin/uvx              159 B

ghcr.io/calibrain/shelfmark-lite@sha256:2eae503d791cef685e10135aaaff77077cfb4a31d6911e31216704988ce28b02
  layer  COPY /uv /uvx /bin/                        24.3 MB   of 221 MB total  11.0% of the pull
```

The `rm` layer unpacks to exactly four tar entries:

```
usr/
usr/bin/
usr/bin/.wh.uv       0 bytes
usr/bin/.wh.uvx      0 bytes
```

Two zero-length overlayfs whiteouts. That is the deletion behaving
exactly as specified — and
removing nothing at all from what anyone downloads.

Same thing without the registry API:

```
$ docker manifest inspect ghcr.io/calibrain/shelfmark-lite:latest
```

and look for the ~24 MB layer; or `docker history` on a local build.

### To be clear about what the `rm` does and doesn't do

**It is not useless and I'm not claiming it is.** It removes `uv` from
the flattened filesystem,
which is what the container sees at runtime and what Trivy/Grype scan by
default — so the
"don't ship a stale installer" half of the intent is already working
today, the same way the
`pip` removal above it does. This PR is about the other half: the bytes.
After it, `uv` is
absent from the filesystem *and* absent from the layers, so nothing
regresses.

This is image size, not a vulnerability, and I would not have opened it
as anything else.

### Why this is safe

- **Nothing at runtime can depend on `uv` or `uvx` today**, and that is
read off your own
artifact rather than argued: both are already whiteouted out of both
published images. `uvx`
is never invoked anywhere in the repo — `entrypoint.sh` has no `uv` in
it, and the Makefile's
  `uv run` lines are the host-side dev workflow, outside the image.
- `/usr/local/bin` is already on `PATH` in `python:3.14.7-slim`, and
your `ENV PATH=/app/.venv/bin:$PATH`
prepends rather than replaces, so `uv` resolves the same way it does
now.
- The pin does not move. Same image, same `sha256`, same resolution per
target platform as
`COPY --from=<image>` does today, so the `linux/amd64` and `linux/arm64`
builds each keep
  getting their own `uv`.
- `RUN --mount=` is already used three times in this file, so the
frontend in use supports
  mounts; `from=` is part of the same feature.
- Your `docker-build-check` job builds `shelfmark-lite` on every PR, so
a build is the cheapest
possible review of this change. As a first-time contributor my workflow
runs sit at
`action_required` until someone approves them — approving is enough to
check the whole claim.

### Notes for reviewers

- I have **not** built these images locally. There is no Docker daemon
on the machine I run on.
Every figure above is read from the published images over the registry
API, and my own
  selftest re-reads them live on each run rather than trusting a note.
- I left the `pip` removal in `base` alone. It has the same shape, but
its stated goal — keeping
a stale installer out of what scanners see — is genuinely achieved by
the flattened
filesystem, and `pip` arrives in the `python:slim` base layer where a
Dockerfile change can't
  reach it anyway.
- Written by an automated agent; saying so plainly seemed better than
not.

Signed-off-by: Sujeito Operator <operator@sujeito.org>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-08-15 11:32:37 -04:00
3e2a7a48d5 fix: clear the DDoS-Guard cookie probe on AA search (#1209)
## Summary

Two failure modes on the same code path, both reported this week: Anna's
Archive `/search` is gated behind a DDoS-Guard cookie probe that the
manual redirect follower can never satisfy.

**#1202 — the cookie is dropped on every hop.** AA URLs set
`allow_redirects = False`, so `html_get_page` follows redirects by hand.
The 302 to `?check=1` carries a `Set-Cookie` (`__ddg*`) that has to come
back on the next request. Because cookies are passed per call and
`requests` keeps no jar across manual hops, it was discarded each time
and the server just re-issued the same redirect until `_MAX_REDIRECTS`
raised `TooManyRedirects`. The file already had the right helper —
`_new_cookies()` — but only the 503 Z-Library handshake branch called
it.

**#1204 — the loop never reaches the bypasser.** `TooManyRedirects`
isn't in `_is_retryable_error` and carries no status code, so the 403
rescue path (`status == _HTTP_STATUS_FORBIDDEN`) never fired and all
attempts repeated the identical failure — ~2.5 min, surfacing as the
misleading "Network restricted or mirrors are blocked".

These interact, which is why #1202's fix alone isn't enough. Requests
merge as `cookies={**handshake_cookies, **cookies}`, so **stale bypasser
cookies override the fresh handshake ones** — once `_cf_cookies` holds
an expired `__ddg*`, the probe can never clear no matter how faithfully
we echo. Hence one search per restart, exactly as #1204 describes.

## Changes

1. Harvest cookies in the same-host redirect branch, the way the 503
branch already does. `_new_cookies()` returns only *new* values, so a
server re-sending an identical cookie yields an empty dict and a genuine
redirect loop still terminates at `_MAX_REDIRECTS`.
2. Treat a redirect loop as a detected challenge: purge the stored
cookies for that host and switch to the bypasser, instead of burning the
retry budget. Gated on `allow_bypasser_fallback` and
`_is_cf_bypass_enabled()`, and skipped when already bypassing, so
AudiobookBay (`allow_bypasser_fallback=False`) and external-bypasser
setups are unaffected.

The broader point in #1204 stands — the fallback would be better gated
on "challenge detected" than on specific status codes, since DDoS-Guard
presents at least three faces (403 js-challenge, 429, and this redirect
loop). This PR fixes the two live exits without that refactor.

## Tests

Two regression tests, both failing before and passing after:

- `test_html_get_page_echoes_cookies_across_same_host_redirects` — the
fake server only returns results if `__ddg2_` comes back on the
`?check=1` hop.
- `test_html_get_page_redirect_loop_purges_cookies_and_bypasses` —
asserts the stored cookies are cleared, the bypasser runs, and the loop
is cut short rather than repeated per attempt.

`ruff check` and `ruff format` clean. `tests/download/` passes except
`test_download_url_ignores_zlib_cookie_refresh_failure`, which fails
identically on unmodified `main` in my environment (no `seleniumbase` —
the `browser` extra isn't installed).

## Verification

Applied on a live v1.3.7 install (Debian LXC, internal CDP bypasser).
Before: every search timed out through 10 retries with
`TooManyRedirects`, zero results. After:

```
http.py:455 - Redirect loop detected; switching to bypasser
internal_bypasser.py:756 - Bypass successful using _bypass_method_cdp_gui_click
internal_bypasser.py:322 - Extracted 9 protection cookies for annas-archive.pk
direct_download.py:1865 - Found 24 releases via ISBN
```

~25 s per search, results render. Note the second search still re-solves
the challenge, since the freshly stored cookies go stale immediately —
the design issue #1204 raises, left for the broader fix.

Fixes #1202
Fixes #1204

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_012Ln3yVj3sWHG2c6T78W1we

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-08-15 11:27:03 -04:00
dependabot[bot] a178541561 Bump the python-deps group with 3 updates (#1205)
Bumps the python-deps group with 3 updates:
[gevent](https://github.com/gevent/gevent),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[prek](https://github.com/j178/prek).

Updates `gevent` from 26.7.0 to 26.8.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/gevent/gevent/commit/4f684105f537eeceb9988adbfe81420a1f28d9a0"><code>4f68410</code></a>
Preparing release 26.8.0</li>
<li><a
href="https://github.com/gevent/gevent/commit/10489c56d3b03caae5be00bc46996a0180ab3d8c"><code>10489c5</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2199">#2199</a>
from florentinl/florentin.labelle/fix/hubless-thread...</li>
<li><a
href="https://github.com/gevent/gevent/commit/d4f5f098c5d6655e9700336ed6f15e924a7fd142"><code>d4f5f09</code></a>
Document the args[0] cross-thread wakeup mechanism</li>
<li><a
href="https://github.com/gevent/gevent/commit/9b049915e8e308e4286f922fd51baf9d92187a88"><code>9b04991</code></a>
Run test_cross_thread_callback_can_run_before_scheduling_returns on all
backends</li>
<li><a
href="https://github.com/gevent/gevent/commit/ce7996d7048d3555be2869cc6172d47e332efb58"><code>ce7996d</code></a>
Address review comments: document cross-thread race, drop unneeded
cpdef</li>
<li><a
href="https://github.com/gevent/gevent/commit/5288a6eec90ca63f9658b44d67f14fbdfe07259d"><code>5288a6e</code></a>
Add missing <a
href="https://github.com/ignores"><code>@​ignores</code></a>_leakcheck
to new cross-thread test</li>
<li><a
href="https://github.com/gevent/gevent/commit/c72eda095d99e82ca0c767afe56baecbc4c131a2"><code>c72eda0</code></a>
Fix cross-thread notifier scheduling race</li>
<li><a
href="https://github.com/gevent/gevent/commit/908b93730ffef5cee0594e4482b3a43b476c43a4"><code>908b937</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2195">#2195</a>
from ddorian/fix-popen-exit-reentrant-close</li>
<li><a
href="https://github.com/gevent/gevent/commit/b58795f8a659e767b0317cd199d68f273b742167"><code>b58795f</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2191">#2191</a>
from ddorian/fix-1865-global-shutdown-lock</li>
<li><a
href="https://github.com/gevent/gevent/commit/ede2e71a859198b96a22f4c683fa210e750406e6"><code>ede2e71</code></a>
Always use 'versionchanged:: NEXT' to let the release machinery fill in
the c...</li>
<li>Additional commits viewable in <a
href="https://github.com/gevent/gevent/compare/26.7.0...26.8.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.11 to 4.51.12
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.12 - CDP Mode: Patch 128</h2>
<h2>CDP Mode: Patch 128</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2322c11a532a43a00f7224bb02aba30f677457f5">Perform
no-op on duplicate quit() calls to avoid coroutine warnings</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4458">seleniumbase/SeleniumBase#4458</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/117c9994dce50e134746580f3f73f62ed22449b2">Refresh
Python dependencies</a>
--&gt; <code>setuptools</code> and <code>platformdirs</code></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 128 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4459">seleniumbase/SeleniumBase#4459</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.11...v4.51.12">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.11...v4.51.12</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2b54219498fdda1a6c689be543f7777ed6c125a4"><code>2b54219</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4459">#4459</a>
from seleniumbase/cdp-mode-patch-128</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6774cef0999b82c3b22dcd5a5a896a6299e8a69b"><code>6774cef</code></a>
Version 4.51.12</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/117c9994dce50e134746580f3f73f62ed22449b2"><code>117c999</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2322c11a532a43a00f7224bb02aba30f677457f5"><code>2322c11</code></a>
Perform no-op on duplicate quit() calls to avoid coroutine warnings</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.11...v4.51.12">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.12 to 0.4.13
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.13</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-10.</p>
<h3>Highlights</h3>
<h4>Manage hook tools with mise</h4>
<p>The new <code>language: mise</code> support lets hooks install tools
using
<a href="https://mise.jdx.dev/"><code>mise</code></a> in an isolated
environment:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: golangci-lint
        name: golangci-lint
        language: mise
additional_dependencies: [&quot;aqua:golangci/golangci-lint@2&quot;]
        entry: golangci-lint run --fast-only ./...
        pass_filenames: false
</code></pre>
<h4>Run commands in hook environments</h4>
<p>The new <code>prek exec</code> subcommand can run an explicit command
in a configured
hook's prepared environment. For example, the hook above makes its
managed
binary available to this command:</p>
<pre lang="console"><code>$ prek exec golangci-lint -- golangci-lint
--version
</code></pre>
<h3>Enhancements</h3>
<ul>
<li>Add <code>mise</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2540">#2540</a>)</li>
<li>Add <code>deny-filename-pattern</code> and
<code>require-filename-pattern</code> hooks (<a
href="https://redirect.github.com/j178/prek/pull/2488">#2488</a>)</li>
<li>Add <code>prek exec</code> for running commands in a hook
environment (<a
href="https://redirect.github.com/j178/prek/pull/2478">#2478</a>)</li>
<li>Add <code>yaml-language-server:</code> comment to YAML sample config
(<a
href="https://redirect.github.com/j178/prek/pull/2486">#2486</a>)</li>
<li>Make <code>prek cache size</code> output terminal-aware (<a
href="https://redirect.github.com/j178/prek/pull/2508">#2508</a>)</li>
<li>Match file regexes against path bytes (<a
href="https://redirect.github.com/j178/prek/pull/2541">#2541</a>)</li>
<li>Show hook aliases in run output (<a
href="https://redirect.github.com/j178/prek/pull/2497">#2497</a>)</li>
<li>Show hook descriptions in run output (<a
href="https://redirect.github.com/j178/prek/pull/2490">#2490</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid env cache scans for skipped hooks (<a
href="https://redirect.github.com/j178/prek/pull/2502">#2502</a>)</li>
<li>Cache Node version queries (<a
href="https://redirect.github.com/j178/prek/pull/2500">#2500</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.13</h2>
<p>Released on 2026-08-10.</p>
<h3>Highlights</h3>
<h4>Manage hook tools with mise</h4>
<p>The new <code>language: mise</code> support lets hooks install tools
using
<a href="https://mise.jdx.dev/"><code>mise</code></a> in an isolated
environment:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: golangci-lint
        name: golangci-lint
        language: mise
additional_dependencies: [&quot;aqua:golangci/golangci-lint@2&quot;]
        entry: golangci-lint run --fast-only ./...
        pass_filenames: false
</code></pre>
<h4>Run commands in hook environments</h4>
<p>The new <code>prek exec</code> subcommand can run an explicit command
in a configured
hook's prepared environment. For example, the hook above makes its
managed
binary available to this command:</p>
<pre lang="console"><code>$ prek exec golangci-lint -- golangci-lint
--version
</code></pre>
<h3>Enhancements</h3>
<ul>
<li>Add <code>mise</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2540">#2540</a>)</li>
<li>Add <code>deny-filename-pattern</code> and
<code>require-filename-pattern</code> hooks (<a
href="https://redirect.github.com/j178/prek/pull/2488">#2488</a>)</li>
<li>Add <code>prek exec</code> for running commands in a hook
environment (<a
href="https://redirect.github.com/j178/prek/pull/2478">#2478</a>)</li>
<li>Add <code>yaml-language-server:</code> comment to YAML sample config
(<a
href="https://redirect.github.com/j178/prek/pull/2486">#2486</a>)</li>
<li>Make <code>prek cache size</code> output terminal-aware (<a
href="https://redirect.github.com/j178/prek/pull/2508">#2508</a>)</li>
<li>Match file regexes against path bytes (<a
href="https://redirect.github.com/j178/prek/pull/2541">#2541</a>)</li>
<li>Show hook aliases in run output (<a
href="https://redirect.github.com/j178/prek/pull/2497">#2497</a>)</li>
<li>Show hook descriptions in run output (<a
href="https://redirect.github.com/j178/prek/pull/2490">#2490</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid env cache scans for skipped hooks (<a
href="https://redirect.github.com/j178/prek/pull/2502">#2502</a>)</li>
<li>Cache Node version queries (<a
href="https://redirect.github.com/j178/prek/pull/2500">#2500</a>)</li>
</ul>
<h3>Bug fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/6204a68bc591773d8a796e1b6c9898cd35aa520d"><code>6204a68</code></a>
Bump version to 0.4.13 (<a
href="https://redirect.github.com/j178/prek/issues/2543">#2543</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f1c73c5f1780b1d3931d372016c2f9b244be1126"><code>f1c73c5</code></a>
Add mise language support (<a
href="https://redirect.github.com/j178/prek/issues/2540">#2540</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3f08ed41fb440af8cc9430cda729f6f41a497c2d"><code>3f08ed4</code></a>
Match file regexes against path bytes (<a
href="https://redirect.github.com/j178/prek/issues/2541">#2541</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6bc5f06f1f090ecf034109ce5b8cc5c773b096d2"><code>6bc5f06</code></a>
Update Rust crate serde-saphyr to v1 (<a
href="https://redirect.github.com/j178/prek/issues/2539">#2539</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/b8c5c69ea3452a77ebc2711ed3b2b8ad011f4791"><code>b8c5c69</code></a>
Update Rust crate fancy-regex to 0.19.0 (<a
href="https://redirect.github.com/j178/prek/issues/2537">#2537</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/2557af921bf5ed6a919385dc18e0177c05530c71"><code>2557af9</code></a>
Update prek hooks (<a
href="https://redirect.github.com/j178/prek/issues/2528">#2528</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/a9587311bc8aa8bf13de7d5d612b93e00f248500"><code>a958731</code></a>
Update Rust crate http to v1.5.0 (<a
href="https://redirect.github.com/j178/prek/issues/2538">#2538</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/fc8b9a45288e005291e1945792543da7a44a2f3a"><code>fc8b9a4</code></a>
Update Rust crate clap to v4.6.5 (<a
href="https://redirect.github.com/j178/prek/issues/2531">#2531</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3bacaa18ad0b0ea67b15e7ea35d4175ad213bd86"><code>3bacaa1</code></a>
Update dependency uv to v0.12.1 (<a
href="https://redirect.github.com/j178/prek/issues/2536">#2536</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/222fc00edd3fb3b3b4443ea54bacc1e868e6e6a7"><code>222fc00</code></a>
Update Rust crate toml to v1.1.4 (<a
href="https://redirect.github.com/j178/prek/issues/2535">#2535</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.12...v0.4.13">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-15 11:16:22 -04:00
dependabot[bot] 78e1f4daba Bump python from 83c1ceb to ce40764 (#1206)
Bumps python from `83c1ceb` to `ce40764`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.7-slim&new-version=3.14.7-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-15 11:16:14 -04:00
dependabot[bot] eeea92280c Bump the npm-deps group in /src/frontend with 3 updates (#1207)
Bumps the npm-deps group in /src/frontend with 3 updates:
[knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip),
[oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) and
[oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint).

Updates `knip` from 6.32.0 to 6.32.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.32.1</h2>
<ul>
<li>Handle referenced config files in their own plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1931">#1931</a>,
close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1932">#1932</a>)
(982c1d8e28cc62d3cba5ecde6dd8df2740c7c329)</li>
<li>Fix type-check against typescript@5.0.4
(2febefe44a8b39f74158916a2bc73933b4c281ae)</li>
<li>Update sentry snapshot
(0397bddbf809e2b24fe59a4bea8c0258526bb565)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/437b608ebc1e098506deb60842c6ce079ff6164e"><code>437b608</code></a>
Release knip@6.32.1</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/2febefe44a8b39f74158916a2bc73933b4c281ae"><code>2febefe</code></a>
Fix type-check against typescript@5.0.4</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/982c1d8e28cc62d3cba5ecde6dd8df2740c7c329"><code>982c1d8</code></a>
Handle referenced config files in their own plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1931">#1931</a>,
close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1932">#1932</a>)</li>
<li>See full diff in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.32.1/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.62.0 to 0.63.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this package will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0">Keep a Changelog</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/c42d6397eab5b2d5bb2bd6746c57bc2a9cad21bd"><code>c42d639</code></a>
release(apps): oxlint v1.78.0 &amp;&amp; oxfmt v0.63.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25473">#25473</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/00f490d7f72d43ec88b1afe28de153e376caf8ed"><code>00f490d</code></a>
refactor(oxfmt,formatter): split <code>sortImports</code> validation and
use type enum (...</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.63.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.77.0 to 1.78.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.78.0] - 2026-08-10</h2>
<h3>🚀 Features</h3>
<ul>
<li>ccb8fe8 linter/jsdoc: Implement <code>no-blank-blocks</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25207">#25207</a>)
(Mikhail Baev)</li>
<li>d4a897c linter/eslint: Implement <code>one-var</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24470">#24470</a>)
(Cole Ellison)</li>
<li>5ab9340 linter/jsx-a11y/anchor-has-content: Add options to match
eslint (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24571">#24571</a>)
(Cole Ellison)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>9573937 linter/typescript: Validate <code>ban-ts-comment</code>
description_format (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25320">#25320</a>)
(Mikhail Baev)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/c42d6397eab5b2d5bb2bd6746c57bc2a9cad21bd"><code>c42d639</code></a>
release(apps): oxlint v1.78.0 &amp;&amp; oxfmt v0.63.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25473">#25473</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/ccb8fe89db08123ff2b86d7fb2f39d0dd6c33df7"><code>ccb8fe8</code></a>
feat(linter/jsdoc): implement <code>no-blank-blocks</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25207">#25207</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/9573937df3cc01f29e1c65bc018ce378ec947e0e"><code>9573937</code></a>
fix(linter/typescript): validate <code>ban-ts-comment</code>
description_format (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25320">#25320</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d4a897ce2290bf853720b4fbf371304bfea2c980"><code>d4a897c</code></a>
feat(linter/eslint): implement <code>one-var</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24470">#24470</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/5ab9340637eff80539bca89a494e162e94569358"><code>5ab9340</code></a>
feat(linter/jsx-a11y/anchor-has-content): add options to match eslint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24571">#24571</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.78.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-15 11:16:09 -04:00
CaliBrain 0a5256ecbb fix(download): reconcile the two AA redirect-loop rescues (#1213)
#1210 and #1212 both added a DDoS-Guard `?check=1` rescue, and #1212 was
branched before #1210 landed, so the merged result had two of them with
identical guards. #1212's inline handoff returns before the raise that
#1210's exception handler keys on, so the handler was shadowed and its
stale-cookie purge — the substance of #1210 — never ran. Its regression
test has been failing on main since the merge.

Fold both into one path:

- `_redirect_loop_handoff()` purges the host's stale clearance cookies,
  then bypasses, so the inline AA handoff and the exception handler
  cannot drift apart again.
- The exception handler keeps its own reason to exist: non-AA hosts run
with allow_redirects=True, so `requests` raises the loop itself and the
  manual AA follower never sees it. It now invokes the bypasser directly
  rather than setting a flag and continuing, which was a no-op at
  MAX_RETRY=1 for the same reason the 403 handoff was.
- An unrescuable loop returns empty instead of raising TooManyRedirects
into the retry path. That error is not retryable and carries no status,
  so `/dyn/md5/summary` (allow_bypasser_fallback=False) re-ran the full
  6-redirect loop on all 10 attempts: 60 requests to AA and ~30s of
  backoff, measured. Every AA mirror shares the challenge, so there is
  nothing to rotate to.
- `allow_bypasser_fallback` docs now describe what the flag actually
  gates; the old text predated #1198 and named the wrong callers.
2026-08-15 11:14:13 -04:00
David YoungandD 6d2af0ac28 fix(download): hand AA challenges to the bypasser immediately (#1212)
## Problem

Two defects in `html_get_page`, either of which is enough to make an
Anna's Archive search fail *without the bypasser ever running*. Found
while chasing why AA search returned nothing on v1.3.7 even with
`USE_CF_BYPASS` on and a working bypasser.

### 1. An AA redirect loop is treated as a network fault

AA serves its DDoS-Guard handshake as a same-host redirect loop:
`/search?…` redirects to `/search?…&check=1`, which redirects back,
indefinitely. The manual redirect follower counts those against
`_MAX_REDIRECTS` and raises `TooManyRedirects`:

```python
redirects_followed += 1
if redirects_followed > _MAX_REDIRECTS:
    _raise_too_many_redirects(f"Too many redirects for {current_url}")
```

That lands in the retry path, so every one of the `MAX_RETRY` attempts
re-runs the same 6-redirect loop and the URL is never offered to the
bypasser — which is the only thing that can clear the challenge. With
the default `MAX_RETRY=10` that's ~60 requests to AA per search, all of
which can only fail:

```
Retry 5/10 for https://annas-archive.pk/search?…&check=1: TooManyRedirects
Retry 6/10 for https://annas-archive.pk/search?…&check=1: TooManyRedirects
…
Giving up after 10 attempts: https://annas-archive.pk/search?…&check=1
```

Surfaced to the user as `Unable to reach download source. Network
restricted or mirrors are blocked.`

### 2. Both bypasser handoffs are a no-op at `MAX_RETRY=1`

The existing 403 handoff — and the new redirect one — set a flag and
`continue`:

```python
logger.info("403 detected; switching to bypasser: %s", current_url)
use_bypasser_now = True
continue
```

The branch that acts on `use_bypasser_now` sits at the top of the
**next** retry attempt. With `MAX_RETRY=1` there is no next attempt, so
a 403 simply ends the search and the bypasser never runs. `MAX_RETRY` is
user-configurable down to 1, so this is reachable in normal use.

The redirect handoff had an additional problem: it sits inside the inner
redirect `while`, so a `continue` there re-enters *that* loop rather
than reaching the retry branch at all.

## Change

Both handoffs now invoke the bypasser directly, through a shared
`_run_bypasser()` closure extracted from the existing branch body. No
behaviour change to the bypass itself — same grace handling, same error
reporting, same `finally`.

The redirect handoff also honours `allow_bypasser_fallback`, for the
same reason the 403 path does: callers such as the `/dyn/md5/summary/…`
fetch behind the details modal pass `False` precisely so a best-effort
request fails fast instead of holding the UI open for a minutes-long
browser solve.

## Result

Measured against `/api/releases` for the same book, internal bypasser,
default `MAX_RETRY`:

| | searches returning results |
|---|---|
| before | 4 / 9 |
| after | 3 / 3, then 7 / 7 |

Zero `TooManyRedirects` give-ups after, and the new path is visible in
the logs:

```
redirect loop on https://annas-archive.gl/search?…&check=1; switching to bypasser
Bypass successful using _bypass_method_cdp_gui_click
```

The request volume drop is the other half of the win — a failing search
no longer emits ~60 requests to AA before giving up.

## Notes

- Only `shelfmark/download/http.py` changes; no config or API surface.
- `use_bypasser_now` is still set before each direct call, so the guard
against double-invocation is unchanged.
- Tested with the internal bypasser (seleniumbase). The
external-bypasser path goes through the same `get_bypassed_page()` call
and is unaffected by the control-flow change, though I have not measured
it against DDoS-Guard specifically — in my testing
FlareSolverr-compatible solvers do not clear that challenge regardless.

Co-authored-by: D <d@e>
2026-08-15 11:01:10 -04:00
Zoltán SzabóandKukkerem 056ddd372a Send DDoS-Guard's ?check=1 redirect loop to the bypasser (#1210)
Fixes #1204.

## Problem

#1198 sends a gated AA `/search` to the bypasser when the origin answers
403.
DDoS-Guard has a second response: when the clearance cookies from an
earlier
solve go stale, it serves an endless `?check=1` redirect instead.

`requests` follows that until `_raise_too_many_redirects`, and
`TooManyRedirects` carries no status code, so `status ==
_HTTP_STATUS_FORBIDDEN`
is false and the rescue never runs. All 10 retries re-send the same dead
cookies, then the search fails as `Unable to reach download source.
Network
restricted or mirrors are blocked.`

Direct-download search therefore works once per container start, and
stays dead
after the stored cookie ages out.

v1.3.7 (`sha256:520715f3…`), internal bypasser, mirrors `.gl/.pk/.gd`:

```
17:04:36 internal_bypasser.py:756 - Bypass successful using _bypass_method_cdp_gui_click
...
17:11:39 http.py:483 - Retry 1/10 for https://annas-archive.gl/search?...&check=1:
    TooManyRedirects: Too many redirects
17:12:12 http.py:493 - Giving up after 10 attempts
17:12:12 main.py:2870 - Release search failed for source direct_download:
    Unable to reach download source. Network restricted or mirrors are blocked.
```

The token is short-lived, which is what makes this reachable in normal
use:

```
$ curl -sD - 'https://annas-archive.gl/search?...&check=1'
HTTP/2 403
server: ddos-guard
set-cookie: __ddg8_=…; Expires=Fri, 14-Aug-2026 15:39:38 GMT   # issued 15:19:38, 20 min
```

## Fix

Handle the loop like the 403: drop the domain's stored cookies, then
retry
through the bypasser. The branch sits above the `status ==` ladder
because
`_get_status_code()` returns `None` for this exception.

Cookies are purged only for the internal bypasser; with an external one
`get_cf_cookies_for_domain()` already returns `{}`.

Related but not changed here: `get_cf_cookies_for_domain()` enforces
expiry for
`cf_clearance` only, so `__ddg*` cookies are never evicted on age, which
is why
they go stale. This patch makes the rescue fire whatever the reason the
cookies
stopped working.

## Verification

The regression test drives a real redirect loop through `html_get_page`
(302 to `&check=1`, exception raised by the production path rather than
faked)
and asserts the cookies are purged and the bypasser runs once.

- `pytest tests/download/test_http_bypasser_fallbacks.py`: 8 passed.
`test_download_url_ignores_zlib_cookie_refresh_failure` fails in my
checkout
  on a missing `seleniumbase`, unrelated to this change.
- `ruff check`, `ruff format --check`: clean.
- Running in production since 2026-08-14 on v1.3.7 with only this file
replaced:
six direct-download searches, five served, three books downloaded end to
end,
against one search per container start before. The rescue mid-download:

```
19:12:14 http.py:449 - Redirect loop detected; switching to bypasser:
    https://annas-archive.gl/md5/cb8fba7abae800ddbae1adfb8d7699d9?&check=1
19:12:38 internal_bypasser.py:756 - Bypass successful using _bypass_method_cdp_gui_click
19:14:36 direct_download.py:1142 - Resolved download URL [aa-slow-nowait]: …
19:14:47 orchestrator.py:735 - download finished; starting post-processing
```

## Separate issue this exposes

DDoS-Guard does not accept a solved cookie from plain `requests`
traffic, so
after this patch the rescue runs for nearly every AA URL.
`internal_bypasser.get()`
serializes all solves on one module-wide lock and builds a fresh Chrome
each
time: 11-16 s uncontended, 43-52 s under concurrent load, measured on
the host
above. Correctness is cheap here, latency is not. Happy to open a
separate PR
for a warm browser session if that direction is welcome.

Co-authored-by: Kukkerem <Kukkerem@users.noreply.github.com>
2026-08-15 10:59:41 -04:00
CaliBrain d0e008adde Stop dropping audiobook releases that are not m4b or mp3 (#1199)
An IRC audiobook search returned nothing while OpenBooks, reading the
same @search answer from the same channel, listed results. Three
separate defects were discarding them.

The audiobook format list was maintained by hand in four places and had
drifted. The settings UI offered only m4b/mp3/m4a/zip/rar, and that list
is the only one a user's config can be built from, so flac, opus, ogg,
aac, wav and wma were unreachable everywhere — even though the IRC
parser recognized them, the IRC sorter ranked them (dead code that could
never fire), archive extraction knew them and Prowlarr searched for
them. A FLAC audiobook was invisible in search and, if it arrived
anyway, rejected after download as "format not supported".
AUDIOBOOK_FORMATS and ARCHIVE_FORMATS now live once in core.utils and
every layer derives from them, which also restored the missing .opus in
the post-download scan's trackable extensions.

Widening the default alone would not have reached anyone already
affected: initialize_default_configs() writes field defaults only when a
tab has no config file yet, so an existing install keeps its persisted
m4b/mp3 list forever. migrate_audiobook_formats rewrites a list that
still matches the old default exactly and leaves every other value
alone — re-enabling formats someone had deliberately turned off would be
worse than leaving them narrow.

The IRC parser filtered by file extension alone. Multi-file audiobooks
ship as a .rar or .zip of MP3s, which matched neither SUPPORTED_FORMATS
nor SUPPORTED_AUDIOBOOK_FORMATS, so they fell out of the ebook bucket
and the audiobook bucket both. Results are now classified before the
format filter is applied: an audio extension means audiobook, an ebook
extension means ebook, and for a container — where the extension says
nothing about the contents — the release name decides. An ebook archive
stays out of audiobook results.

RESULT_LINE_REGEX matched \w+ after any dot, so a line carrying no file
extension parsed as format "5mb" out of "::INFO:: 620.5MB", taking the
title and the size down with it and guaranteeing every downstream filter
dropped it. Any decimal size did this. The extension is now matched
against the known formats, so such a line falls through to the simple
pattern and comes back as "unknown", which the rest of the parser
already handles. ALL_RECOGNIZED_FORMATS became an ordered tuple in the
process: it was a set, so which extension won for a line naming two of
them depended on set iteration order and could vary between restarts.

Refs #1129
2026-08-13 13:51:40 -04:00
CaliBrain 03e219eb43 Let the bypasser solve bot challenges on Anna's Archive search (#1198)
Anna's Archive put a DDoS-Guard JS challenge in front of /search: the
homepage still returns 200, but /search and /md5/<id> answer 403 on
every mirror (.gl, .pk, .gd all confirmed). Search fetched both with
allow_bypasser_fallback=False, which rotates mirrors on a 403 instead of
invoking the bypasser, so it walked the whole mirror list, exhausted it,
and surfaced "Unable to reach download source. Network restricted or
mirrors are blocked." as a 503 on every query. Adding mirrors could not
help — they sit behind the same gate — and neither could USE_CF_BYPASS,
since search never reached that branch.
Fetch search and the detail page with allow_bypasser_fallback=True so a
403 hands over to the bypasser, which already detects this challenge
(DDOS_GUARD_INDICATORS matches the live page). Echoing the __ddg cookies
back does not clear it; it needs real JS execution. The download-count
fetch keeps allow_bypasser_fallback=False: it is decoration on the
details modal and not worth holding the modal open for a browser solve.
Fixes #1196
2026-08-13 13:06:11 -04:00
dependabot[bot] 0e8608c427 Bump transmission-rpc from 7.0.11 to 7.0.12 in the python-deps group (#1195)
Bumps the python-deps group with 1 update:
[transmission-rpc](https://github.com/Trim21/transmission-rpc).

Updates `transmission-rpc` from 7.0.11 to 7.0.12
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Trim21/transmission-rpc/releases">transmission-rpc's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.12</h2>
<h3> New Features</h3>
<ul>
<li><a
href="https://github.com/trim21/transmission-rpc/commit/849cc3b9a357f903242915301fcd190d5ae932a3"><code>849cc3b</code></a>
- add v8 migration deprecations <em>(commit by <a
href="https://github.com/trim21"><code>@​trim21</code></a>)</em></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/trim21/transmission-rpc/commit/d05e9c6c2953d7f334b46df600af4b47d9ea65f5"><code>d05e9c6</code></a>
bump: 7.0.12</li>
<li><a
href="https://github.com/trim21/transmission-rpc/commit/2800e6f0a0a64c31f44935e5122cb7ad3d581dfd"><code>2800e6f</code></a>
ci: pin pyproject schema validation</li>
<li><a
href="https://github.com/trim21/transmission-rpc/commit/1bc5f0d51888f526ada2026409b00228287d2fc8"><code>1bc5f0d</code></a>
ci: run workflows on 7.x</li>
<li><a
href="https://github.com/trim21/transmission-rpc/commit/849cc3b9a357f903242915301fcd190d5ae932a3"><code>849cc3b</code></a>
feat: add v8 migration deprecations</li>
<li>See full diff in <a
href="https://github.com/Trim21/transmission-rpc/compare/v7.0.11...v7.0.12">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=transmission-rpc&package-manager=uv&previous-version=7.0.11&new-version=7.0.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-13 00:30:47 -04:00
dependabot[bot] 7f770f54fa Bump python from 3.14.6-slim to 3.14.7-slim (#1190)
Bumps python from 3.14.6-slim to 3.14.7-slim.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.6-slim&new-version=3.14.7-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 00:21:24 -04:00
dependabot[bot] 0eb8b78dc7 Bump the npm-deps group in /src/frontend with 3 updates (#1191)
Bumps the npm-deps group in /src/frontend with 3 updates:
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node),
[knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) and
[vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).

Updates `@types/node` from 26.1.2 to 26.2.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.31.0 to 6.32.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.32.0</h2>
<ul>
<li>fix: attribute wildcard subpath-import aliases as dependency usage
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1918">#1918</a>)
(4890a2ad5317b9e3f0ab844631ad0f0592802c3e) - thanks <a
href="https://github.com/jsmecham"><code>@​jsmecham</code></a>!</li>
<li>Add Borp plugin (5eb9ad4cfb2ccb7770eac49f6109459d30590211)</li>
<li>Add tsd plugin (bd4ae7041f3fc6aef27b027644f80daefc432aca)</li>
<li>Resolve Rollup --config argument as plugin configuration
(8111f97981406f4327d5e6a655c13308a9dc4426)</li>
<li>Resolve babel-jest configFile from Jest transform options
(24794ccecb80fdaecfe4d46a26faff46c30d9015)</li>
<li>Add pre-commit plugin
(ac726b0918cb931a6d538797e342484812a6752e)</li>
<li>Thread script words through resolvers to preserve quoting
(89f9ada6ca81229bf8f7293439998acc5f87d457)</li>
<li>Resolve entries from Mocha script arguments
(353f860f8e32f05f7c87dc5501071befc0e5a293)</li>
<li>Detect Node test runner through c8
(fa44be722aa35c6e8b441cd8cd0f4cf644027c22)</li>
<li>Update dependencies (non-major) (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1922">#1922</a>)
(6b1e6f3cbb1749776e3798f46eb2b99cd95ed56a) - thanks <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot]!</li>
<li>fix(playwright): match config files with .cjs, .cts and .mts
extensions (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1919">#1919</a>)
(1c1073a1817fdb3bcd3dc00eda2b1d858e444156) - thanks <a
href="https://github.com/davidpavlovschi"><code>@​davidpavlovschi</code></a>!</li>
<li>Restart VS Code language server process (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1923">#1923</a>)
(d48eac5a2447567a33e835ce3e1648bf3f4ffb2b)</li>
<li>Classify built-ins from module specifiers (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1925">#1925</a>)
(3528c5d0f808b7b2155f69a1f98493ee0e3e06c1)</li>
<li>Don't turn absolute-path script tokens into entries (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1928">#1928</a>)
(e5608e77b434145c8dd5c2c2872bfb90ae622ce7)</li>
<li>Update sponsors data (025884bb53eede041732723197ac0415a1a50f71)</li>
<li>Update dependencies (d2c0a07c09cea70ab2cae5f97d12da272a6e43e6)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/f21bcbb653377682dd690fb99b0f02977ac524d2"><code>f21bcbb</code></a>
Release knip@6.32.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/d2c0a07c09cea70ab2cae5f97d12da272a6e43e6"><code>d2c0a07</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e5608e77b434145c8dd5c2c2872bfb90ae622ce7"><code>e5608e7</code></a>
Don't turn absolute-path script tokens into entries (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1928">#1928</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/3528c5d0f808b7b2155f69a1f98493ee0e3e06c1"><code>3528c5d</code></a>
Classify built-ins from module specifiers (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1925">#1925</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/1c1073a1817fdb3bcd3dc00eda2b1d858e444156"><code>1c1073a</code></a>
fix(playwright): match config files with .cjs, .cts and .mts extensions
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1919">#1919</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/fa44be722aa35c6e8b441cd8cd0f4cf644027c22"><code>fa44be7</code></a>
Detect Node test runner through c8</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/353f860f8e32f05f7c87dc5501071befc0e5a293"><code>353f860</code></a>
Resolve entries from Mocha script arguments</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/89f9ada6ca81229bf8f7293439998acc5f87d457"><code>89f9ada</code></a>
Thread script words through resolvers to preserve quoting</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/ac726b0918cb931a6d538797e342484812a6752e"><code>ac726b0</code></a>
Add pre-commit plugin</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/24794ccecb80fdaecfe4d46a26faff46c30d9015"><code>24794cc</code></a>
Resolve babel-jest configFile from Jest transform options</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.32.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.2.0 to 8.2.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>plugin-legacy@8.2.1</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/plugin-legacy@8.2.1/packages/plugin-legacy/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.2.1</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.2.1/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.2.0...v8.2.1">8.2.1</a>
(2026-08-06)<!-- raw HTML omitted --></h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>build:</strong> make client chunkImportMap work with
<code>sharedPlugins: true</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/23184">#23184</a>)
(<a
href="https://github.com/vitejs/vite/commit/15f03073c915d6ffb9a1fda447ef66b02bf5cde8">15f0307</a>)</li>
<li><strong>bundled-dev:</strong> inject client script tag before chunk
scripts (<a
href="https://redirect.github.com/vitejs/vite/issues/23161">#23161</a>)
(<a
href="https://github.com/vitejs/vite/commit/eac0cc84aa2472a85a19ee84561c1ba71e381a55">eac0cc8</a>)</li>
<li><strong>css:</strong> don't re-run lightningcss visitor during
minify (fix <a
href="https://redirect.github.com/vitejs/vite/issues/23146">#23146</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/23147">#23147</a>)
(<a
href="https://github.com/vitejs/vite/commit/de041a79b05a0be965c874592fe2c1505bcd48df">de041a7</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/23136">#23136</a>)
(<a
href="https://github.com/vitejs/vite/commit/14454fd8c9a399bc3fdc193e28465b6fcf001e4d">14454fd</a>)</li>
<li><strong>deps:</strong> update rolldown-related dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/23070">#23070</a>)
(<a
href="https://github.com/vitejs/vite/commit/7ac6f7f590747bbdab9958e2c016e3dd04f10542">7ac6f7f</a>)</li>
<li>don't mutate the user config when resolving the lib entry from the
top-level <code>input</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/23135">#23135</a>)
(<a
href="https://github.com/vitejs/vite/commit/b4bf59686a7ac238929e91a6e1708c739b843a2f">b4bf596</a>)</li>
<li>handle shebang ending with uncommon line terminators (<a
href="https://redirect.github.com/vitejs/vite/issues/23038">#23038</a>)
(<a
href="https://github.com/vitejs/vite/commit/17f7b2f193a110d0b47742ad296d182cb4666ce7">17f7b2f</a>)</li>
<li><strong>server:</strong> use a random port when port is 0 (<a
href="https://redirect.github.com/vitejs/vite/issues/23158">#23158</a>)
(<a
href="https://github.com/vitejs/vite/commit/fddf4ea41de5f7889037a2f957438857ac12a260">fddf4ea</a>)</li>
</ul>
<h3>Performance Improvements</h3>
<ul>
<li><strong>css:</strong> look up pure CSS chunks through a Set (<a
href="https://redirect.github.com/vitejs/vite/issues/23114">#23114</a>)
(<a
href="https://github.com/vitejs/vite/commit/1331b0b438b1e7193effb7d2341660bccb9c3155">1331b0b</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>build:</strong> fix incomplete <code>@default</code> for
build.minify (<a
href="https://redirect.github.com/vitejs/vite/issues/23177">#23177</a>)
(<a
href="https://github.com/vitejs/vite/commit/ef02435114c57d0422028f0e6987f3df8db72969">ef02435</a>)</li>
</ul>
<h3>Miscellaneous Chores</h3>
<ul>
<li><strong>deps:</strong> update dependency rolldown-plugin-dts to
^0.28.0 (<a
href="https://redirect.github.com/vitejs/vite/issues/23137">#23137</a>)
(<a
href="https://github.com/vitejs/vite/commit/4adc1e7931d4beceb4e236d9a271d057c858a06f">4adc1e7</a>)</li>
<li><strong>deps:</strong> update dependency strip-literal to v4 (<a
href="https://redirect.github.com/vitejs/vite/issues/23140">#23140</a>)
(<a
href="https://github.com/vitejs/vite/commit/9db65ce63488ea8f08a3c98dcdc4282b17bd33ff">9db65ce</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li><strong>bundled-dev:</strong> avoid injecting server values in the
bundle (<a
href="https://redirect.github.com/vitejs/vite/issues/22967">#22967</a>)
(<a
href="https://github.com/vitejs/vite/commit/23b8a088dec9dcc3f1c1353f2074f8644b3cc21f">23b8a08</a>)</li>
<li><strong>bundled-dev:</strong> remove rolldown lazy stub module
workaround (<a
href="https://redirect.github.com/vitejs/vite/issues/23129">#23129</a>)
(<a
href="https://github.com/vitejs/vite/commit/e72036eed2e28936ed824971b18aeaa3900857f6">e72036e</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li><strong>bundled-dev:</strong> enable sourcemap playgrounds (<a
href="https://redirect.github.com/vitejs/vite/issues/23080">#23080</a>)
(<a
href="https://github.com/vitejs/vite/commit/c2155fe4d5c8d25fba3a7366d367e3296ae669fa">c2155fe</a>)</li>
<li>reduce logs (<a
href="https://redirect.github.com/vitejs/vite/issues/23138">#23138</a>)
(<a
href="https://github.com/vitejs/vite/commit/7673c02e53343ae9356c1f496c1c1da2eb732ac1">7673c02</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/421615865dad3ed39137d17281814fc78a41246c"><code>4216158</code></a>
release: v8.2.1</li>
<li><a
href="https://github.com/vitejs/vite/commit/fddf4ea41de5f7889037a2f957438857ac12a260"><code>fddf4ea</code></a>
fix(server): use a random port when port is 0 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23158">#23158</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/de041a79b05a0be965c874592fe2c1505bcd48df"><code>de041a7</code></a>
fix(css): don't re-run lightningcss visitor during minify (fix <a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23146">#23146</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23147">#23147</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/15f03073c915d6ffb9a1fda447ef66b02bf5cde8"><code>15f0307</code></a>
fix(build): make client chunkImportMap work with <code>sharedPlugins:
true</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23184">#23184</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/c2155fe4d5c8d25fba3a7366d367e3296ae669fa"><code>c2155fe</code></a>
test(bundled-dev): enable sourcemap playgrounds (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23080">#23080</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/ef02435114c57d0422028f0e6987f3df8db72969"><code>ef02435</code></a>
docs(build): fix incomplete <code>@default</code> for build.minify (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23177">#23177</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/eac0cc84aa2472a85a19ee84561c1ba71e381a55"><code>eac0cc8</code></a>
fix(bundled-dev): inject client script tag before chunk scripts (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23161">#23161</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/23b8a088dec9dcc3f1c1353f2074f8644b3cc21f"><code>23b8a08</code></a>
refactor(bundled-dev): avoid injecting server values in the bundle (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22967">#22967</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/e72036eed2e28936ed824971b18aeaa3900857f6"><code>e72036e</code></a>
refactor(bundled-dev): remove rolldown lazy stub module workaround (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23129">#23129</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/14454fd8c9a399bc3fdc193e28465b6fcf001e4d"><code>14454fd</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/23136">#23136</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v8.2.1/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 00:14:04 -04:00
dependabot[bot] eb98b6a816 Bump the gh-actions group with 2 updates (#1192)
Bumps the gh-actions group with 2 updates:
[actions/attest-build-provenance](https://github.com/actions/attest-build-provenance)
and [dorny/paths-filter](https://github.com/dorny/paths-filter).

Updates `actions/attest-build-provenance` from 4.1.1 to 4.2.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/attest-build-provenance/releases">actions/attest-build-provenance's
releases</a>.</em></p>
<blockquote>
<h2>v4.2.2</h2>
<blockquote>
<p>[!NOTE]
As of version 4, <code>actions/attest-build-provenance</code> is simply
a wrapper on top of <a
href="https://github.com/actions/attest"><code>actions/attest</code></a>.</p>
<p>Existing applications may continue to use the
<code>attest-build-provenance</code> action, but new implementations
should use <code>actions/attest</code> instead.</p>
</blockquote>
<h2>What's Changed</h2>
<ul>
<li>Bump actions/attest from 4.2.0 to 4.2.1 in the actions-minor group
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/attest-build-provenance/pull/862">actions/attest-build-provenance#862</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/attest-build-provenance/compare/v4.1.1...v4.2.2">https://github.com/actions/attest-build-provenance/compare/v4.1.1...v4.2.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/4d101475d8b20a2381f78447822ac1eab6504dd8"><code>4d10147</code></a>
Bump actions/attest from 4.2.0 to 4.2.1 in the actions-minor group (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/862">#862</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/e3fe62ef559997059fe8380e7d2b4c909e2d65f4"><code>e3fe62e</code></a>
Bump the actions-minor group with 2 updates (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/860">#860</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/attest-build-provenance/compare/0f67c3f4856b2e3261c31976d6725780e5e4c373...4d101475d8b20a2381f78447822ac1eab6504dd8">compare
view</a></li>
</ul>
</details>
<br />

Updates `dorny/paths-filter` from 4.0.2 to 4.0.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/releases">dorny/paths-filter's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update Outputs in readme to account for the 'every'
predicate-quantifier by <a
href="https://github.com/hintron"><code>@​hintron</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/247">dorny/paths-filter#247</a></li>
<li>fix: scope base-ignored warning to API path by <a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/319">dorny/paths-filter#319</a></li>
<li>docs: add contents permission to PR example by <a
href="https://github.com/134130"><code>@​134130</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/248">dorny/paths-filter#248</a></li>
<li>feat: add 'some-with-excludes' predicate quantifier by <a
href="https://github.com/arxeiss"><code>@​arxeiss</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/322">dorny/paths-filter#322</a></li>
<li>Document safe handling of file list outputs in workflows by <a
href="https://github.com/dorny"><code>@​dorny</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/326">dorny/paths-filter#326</a></li>
</ul>
<h2>Security</h2>
<ul>
<li>Escape multi-line filenames in list-files shell and csv output] by
<a href="https://github.com/ken-matsui"><code>@​ken-matsui</code></a>
and <a href="https://github.com/tjswlsgg"><code>@​tjswlsgg</code></a> in
<a
href="https://github.com/advisories/GHSA-7hc6-8hq5-9q2m">https://github.com/advisories/GHSA-7hc6-8hq5-9q2m</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/hintron"><code>@​hintron</code></a> made
their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/247">dorny/paths-filter#247</a></li>
<li><a href="https://github.com/134130"><code>@​134130</code></a> made
their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/248">dorny/paths-filter#248</a></li>
<li><a href="https://github.com/arxeiss"><code>@​arxeiss</code></a> made
their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/322">dorny/paths-filter#322</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v4...v4.0.3">https://github.com/dorny/paths-filter/compare/v4...v4.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md">dorny/paths-filter's
changelog</a>.</em></p>
<blockquote>
<h2>v4.0.3</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/326">Document
safe handling of file list outputs in workflows</a></li>
<li><a href="https://github.com/advisories/GHSA-7hc6-8hq5-9q2m">Escape
multi-line filenames in list-files shell and csv output</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/322">Add
'some-with-excludes' predicate quantifier</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/248">Add
contents permission to PR example</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/319">Scope
base-ignored warning to API path</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/247">Update
outputs in readme to account for the 'every'
predicate-quantifier</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/dorny/paths-filter/commit/ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d"><code>ceb8a2b</code></a>
Update CHANGELOG.md for v4.0.3 and v3.0.4 (<a
href="https://redirect.github.com/dorny/paths-filter/issues/327">#327</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/ef09b88f3eacdbec6ce135a7c9a193a6849545c1"><code>ef09b88</code></a>
Document safe handling of file list outputs in workflows (<a
href="https://redirect.github.com/dorny/paths-filter/issues/326">#326</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/44adc5b06dc135dba334efce9bf3cf0624512d2d"><code>44adc5b</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/4711b7a31b4aa89103d8c6ffab2e3b8e7b6381c7"><code>4711b7a</code></a>
feat: add 'some-with-excludes' predicate quantifier (<a
href="https://redirect.github.com/dorny/paths-filter/issues/322">#322</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/93c889f9e58fca66f35a0c83d8673ac7e88bb70a"><code>93c889f</code></a>
fix: escape multi-line filenames in list-files shell and csv output</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/b41dfa943b1939b9b646f67753bfe35cf6e4de03"><code>b41dfa9</code></a>
docs: add contents permission to PR example (<a
href="https://redirect.github.com/dorny/paths-filter/issues/248">#248</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/9af6e5a9d010d1ae8ec570390b3d793e2b70a402"><code>9af6e5a</code></a>
fix: scope base-ignored warning to API path (<a
href="https://redirect.github.com/dorny/paths-filter/issues/319">#319</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/cae9006b65a1a53044b518c68e13e835c54948a7"><code>cae9006</code></a>
docs: update outputs in readme to account for the 'every'
predicate-quantifie...</li>
<li>See full diff in <a
href="https://github.com/dorny/paths-filter/compare/v4.0.2...v4.0.3">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 00:13:45 -04:00
CaliBrain 29ce83e274 Stop dependabot proposing Python pre-releases, bound the e2e health wait (#1189)
PR #1169 (python:3.14.6-slim -> python:3.15.0b3-slim) ran for 6h before
GitHub's max job limit killed it, then did it again on re-run. Two
independent defects.

Dependabot proposed a beta at all: the config already excluded python
from the docker digest group for dependabot-core#9496, but the comment
claimed ungrouped python updates get their pre-release filtered. They
don't. dependabot-core#13815 rewrote the Docker pre-release heuristic to
catch PEP 440 tags (its tests cover 3.15.0a2 and 3.5.0b3), yet the
suffixed real tag still got through seven months later. CPython spells
pre-releases without a separator, so 3.15.0b3 parses as an ordinary
version sorting above 3.14.6. Ignore python semver-minor/major instead
of trusting the heuristic; patch and digest updates still flow.

The run took hours rather than failing: the health wait looked bounded
at 60 iterations x 2s, but bare `curl` has no timeout. The 3.15 image
booted a container that bound 8084 without ever serving (greenlet has no
3.15 wheel, so the gevent gunicorn worker was wedged), so curl blocked
on
read forever and the loop never reached iteration 2. Every job's orphan
process at cancellation was that curl. Bound each probe and switch to a
wall-clock deadline, and add timeout-minutes so a hang can never reach
6h
again.

Verified against a socket that accepts and never responds: the old loop
was still hung at 30s, the new one exits at 120s with HEALTHY=0 into the
existing log-dump path, and a responsive endpoint is still detected
immediately.
2026-08-11 23:58:37 -04:00
CaliBrain e320b7623d Fix LOG_LEVEL being ignored and Z-Library 503 cookie gate (#1188)
LOG_LEVEL never reached the app logger: env.py hardcoded the level to
DEBUG or INFO, so INFO lines kept appearing under LOG_LEVEL=error. Read
it from the env var and advanced settings, normalize unknown values to
INFO, and expose it as a setting. entrypoint.sh now normalizes
gunicorn's level too, so a typo falls back to info instead of stopping
the container from booting.

Z-Library gates the first hit on /md5/<hash> with a 503 whose only
payload is a Set-Cookie; echoing that cookie back returns the 302 to the
real page. html_get_page dropped it and re-ran the same rejected request
on every retry, ending in "No download URL resolved". Retry once with
the
cookies the 503 issued.

Fixes #1185
Fixes #1187
2026-08-11 23:27:44 -04:00
CaliBrain bb848f05bc fix/bypass stall watchdog (#1186)
- Fix protection bypass cancelled by stall detection at exactly 300s
- make fixes
- Try to fix Synology DELETE issues
2026-08-11 12:23:34 -04:00
CaliBrain cc1a95f965 Fix protection bypass cancelled by stall detection at exactly 300s (#1184)
A download that hits Cloudflare hung on "Bypassing protection..." for
five
minutes and then died, regardless of which bypasser was configured.

html_get_page() started a BypassHeartbeat thread to keep the download
marked
alive during a bypass, but the thread had no loop: it fired one status
event
and returned. Even with the loop restored it could not have worked,
because
update_download_status() dedupes identical (status, message) tuples and
returns before refreshing _last_activity, and the heartbeat re-sent the
byte-identical payload already emitted just above it.

So _last_activity was frozen for the whole bypass, while both bypassers
are
allowed to run longer than STALL_TIMEOUT (external FlareSolverr ~394s at
default settings, internal 420s per get() call). The watchdog always
won.
From a reporter's log: 403 at 07:04:33.390, cancelled at 07:09:33.987 -
exactly 300.000s, and 41s before the bypasser would have finished and
reported the real error, an HTTP 500 from FlareSolverr the user never
saw.

The regression is not one commit. 1f093de (#536) added the heartbeat and
the
dedup together and refreshed activity before the dedup return, so it
worked.
ff094be (#832) moved the refresh below that return while tightening
stall
detection for #823. 3a3a3ce (#845) then deleted the heartbeat's while
loop
to silence a B023 lint, removing the last evidence of intent.

The dedup itself is correct and stays: a keep-alive that ticks on a
timer
proves nothing about whether an operation is progressing, so letting it
refresh the stall clock would make a wedged download immortal. Split the
two
concerns instead.

Add shelfmark/download/activity.py. A long single-shot operation
declares its
own upper bound once, over a sentinel status carried on the existing
status_callback channel - so no new parameter has to be threaded through
every
handler, post-processor and output module. The orchestrator intercepts
the
sentinel in its per-task closure and records an absolute deadline in
_activity_grace, which stall detection honours alongside STALL_TIMEOUT.
The
grace never extends itself and is clamped to
_MAX_ACTIVITY_GRACE_SECONDS, so
an operation that overruns its own declared budget is still cancelled.

Each bypasser now reports max_duration_seconds() derived from its own
retry
and timeout settings, and http.py asks whichever is active, plus 30s of
slack
so the bypasser's own deadline expires first and the user sees its real
failure. On that path html_get_page() also emits
status_callback("error", ...)
rather than silently returning an empty page.

Three further fixes on the same code path:

- Extract the watchdog into _find_stalled_tasks() and
_cancel_stalled_task().
It was the only place holding _progress_lock across a call into
book_queue,
whose terminal-status hooks reach a sqlite write that gevent does not
patch,
blocking the hub and every download worker. It now holds the lock for
dict
  reads only.
- Bound _CDP_WORKER.run(), which waited with timeout=None while holding
the
module-wide LOCKED, so a single wedged in-process CDP session blocked
every
  subsequent bypass forever on non-Docker installs.
- Broaden the coordinator loop's except clause back to Exception, with
  escalating backoff. 8d98e12 (#868) narrowed it to a six-type tuple to
silence BLE001, which let gevent's LoopExit and similar kill the only
thread
driving the download queue - undoing #832's fix for #823 and resurfacing
it
  as #1166. GreenletExit and gevent.Timeout still propagate.

Fixes #1001
Refs #1166, #823
2026-08-11 02:25:28 -04:00
CaliBrain dfcd7c9b00 Fix silent Hardcover search failures on rejected sort values (#1183)
Hardcover forwards the `sort` argument to Typesense's `sort_by` and
rejects
the entire search if it dislikes the value -- an unknown field, a bare
field
name with no direction, or more than three sort keys. A rejected search
is
not a GraphQL error: it comes back as HTTP 200, no `errors` key, and a
null
`results` body.

_extract_typesense_hits() reads that null as `hits=[], found=0`, so a
failed
search was indistinguishable from one that matched nothing. Users saw
zero
results with a healthy container and no log line explaining why.

Add _execute_search_query(), used by the three sort-bearing call sites
(book
search, field typeahead, series resolution):

- Detect the rejection via the null `results` body. A search that
genuinely
matched nothing still returns a results object with `found: 0`, so empty
    result sets are not mistaken for failures.
- Retry once with an empty sort, which Hardcover always accepts, so
searches
    return results instead of nothing.
- Keep that fallback sticky for 15 minutes so every subsequent search
does
not pay for a request known to fail, and let it expire so sort order
comes
    back on its own if the index is fixed upstream.
- Log rejections that no sort can explain, and retries that also fail,
at
    ERROR instead of discarding them.

While the fallback is active, results fall back to Typesense's default
ordering regardless of the selected sort. Degraded ordering beats no
results,
and it is now logged rather than silent.

SORT_MAPPING itself is unchanged: all five of its values were verified
against
the live API and return results. The `sort: "relevance"` reported in
#1179 was
the raw SortOrder value sent by v1.3.5; the mapping already fixed that.
What
remained unfixed, and is fixed here, is that the failure was invisible.

Fixes #1179
2026-08-11 01:35:41 -04:00
dependabot[bot] bd9a22bd6c Bump node from a0b9bf0 to d32cdf6 in the docker-base-image-digests group (#1168)
Bumps the docker-base-image-digests group with 1 update: node.

Updates `node` from `a0b9bf0` to `d32cdf6`


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=node&package-manager=docker&previous-version=24-alpine&new-version=24-alpine)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-11 01:06:51 -04:00
dependabot[bot] ba4f7fb5e6 Bump the npm-deps group in /src/frontend with 8 updates (#1170)
Bumps the npm-deps group in /src/frontend with 8 updates:

| Package | From | To |
| --- | --- | --- |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.18.1` | `7.18.2` |
|
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)
| `19.2.17` | `19.2.18` |
|
[@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom)
| `19.2.3` | `19.2.4` |
|
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
| `6.0.4` | `6.0.5` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.29.0` | `6.31.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.61.0` | `0.62.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.76.0` | `1.77.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.1.5` | `8.2.0` |

Updates `react-router-dom` from 7.18.1 to 7.18.2
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/react-router-dom@7.18.2/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.18.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.18.2"><code>react-router@7.18.2</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/69a653ee6ab1ac95b13c917ec56c5f3dc17ca9c1"><code>69a653e</code></a>
Release v7.18.2 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15354">#15354</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.18.2/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react` from 19.2.17 to 19.2.18
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react-dom` from 19.2.3 to 19.2.4
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.0.4 to 6.0.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/releases">@​vitejs/plugin-react's
releases</a>.</em></p>
<blockquote>
<h2>plugin-react@6.0.5</h2>
<h3>Fixed the react compiler preset filter to be linear (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1353">#1353</a>)</h3>
<p>The improved filter in v6.0.3 was non-linear and caused a performance
regression (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/issues/1349">#1349</a>).
The filter was changed to be linear to avoid that.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.0.5 (2026-07-30)</h2>
<h3>Fixed the react compiler preset filter to be linear (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1353">#1353</a>)</h3>
<p>The improved filter in v6.0.3 was non-linear and caused a performance
regression (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/issues/1349">#1349</a>).
The filter was changed to be linear to avoid that.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/68c0cb8796ce18bd049c3d05c5210eaf0617eac0"><code>68c0cb8</code></a>
release: plugin-react@6.0.5 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1362">#1362</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/555cdbc126506317b05404481374406771a41e70"><code>555cdbc</code></a>
fix(react): make the react compiler preset filter linear (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1353">#1353</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/a00a9f8240d5a7bb4062ee2a5bac68ea4f0defa6"><code>a00a9f8</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1327">#1327</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.5/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.29.0 to 6.31.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.31.0</h2>
<ul>
<li>feat: Add basic support for Marko 6 and 5 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1914">#1914</a>)
(c6b151642701f9b4864ddb5ea8e40580623f59d1) - thanks <a
href="https://github.com/caseycarroll"><code>@​caseycarroll</code></a>!</li>
<li>Use Array.from in Marko compiler
(5aadf47a22bdfd43bb8ad4082768e07fe37fc5ca)</li>
<li>Update release-it and fix release script flags
(6fa9c269c65c0923965924226a5ccf0778842967)</li>
<li>Downgrade <code>@​types/vscode</code> to match extension engines
range (6d8e9bf5200cf982d0bc801469c4e2be5627e5b8)</li>
</ul>
<h2>Release 6.30.0</h2>
<ul>
<li>docs: migrate to Starlight Blog plugin (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1854">#1854</a>)
(c89e3e3c9) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>Include workspace dependencies in scoped runs (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1901">#1901</a>)
(a75309eda)</li>
<li>Simplify workspace assembly (b3ac16411)</li>
<li>Document export declaration safety (ef98a7682)</li>
<li>Read object jsPlugin specifiers from Vite+ config (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1879">#1879</a>)
(3ea6a92d4) - thanks <a
href="https://github.com/matchai"><code>@​matchai</code></a>!</li>
<li>Compile gitignore negations once (6884cdb20)</li>
<li>Cache Node test script detection (d970f67d8)</li>
<li>Track only enabled workspace plugins (67d48268a)</li>
<li>Skip unsupported Vite config command (545bb2d36)</li>
<li>Add SARIF reporter (ce11cf5d4)</li>
<li>Track catalog refs in pnpm dlx scripts (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1885">#1885</a>,
close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1886">#1886</a>)
(102189a1a)</li>
<li>Report unresolved catalog references (b2b86c3e5)</li>
<li>Track catalog references across scoped runs (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1905">#1905</a>)
(f0365bae0)</li>
<li>Track script catalog references across scoped runs (9b3ab3778)</li>
<li>Remove tsc from ignoreBinaries (a0a283040)</li>
<li>fix: detect dynamic imports in Svelte component templates (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1908">#1908</a>)
(aa303fb04) - thanks <a
href="https://github.com/firatciftci"><code>@​firatciftci</code></a>!</li>
<li>fix(remark): support all types of dependency names (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1911">#1911</a>)
(3441bea3a) - thanks <a
href="https://github.com/voxpelli"><code>@​voxpelli</code></a>!</li>
<li>Update sanity snapshot (d04aa04e5)</li>
<li>feat(stryker): add ts extensions (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1910">#1910</a>)
(cfc50886e) - thanks <a
href="https://github.com/christopher-buss"><code>@​christopher-buss</code></a>!</li>
<li>Adopt <code>@​e18e/eslint-plugin</code> (adf2511ab)</li>
<li>Remove Workleap from sponsors (d4f6af9ff)</li>
<li>Update dependencies (3f61542f6)</li>
<li>Add ES2023 array types to TypeScript 5 CI (360a47157)</li>
<li>Update sentry snapshot (7defc1853)</li>
<li>Analyze published type dependencies (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1909">#1909</a>)
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1912">#1912</a>)
(87d713e52)</li>
<li>Update TanStack and Code Forge logos (39ed8c82b)</li>
<li>Track assets referenced from SCSS URLs (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1916">#1916</a>)
(cbe13bf87)</li>
<li>Consume only the default export of inline dynamic import loaders
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1915">#1915</a>)
(b90a299e2)</li>
<li>Update ecosystem snapshots (3f6cdee15)</li>
<li>Update dependencies (6cdb3a6ac)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/69c6006ee5938d7e2a6157222a24799eb639ec5c"><code>69c6006</code></a>
Release knip@6.31.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/5aadf47a22bdfd43bb8ad4082768e07fe37fc5ca"><code>5aadf47</code></a>
Use Array.from in Marko compiler</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c6b151642701f9b4864ddb5ea8e40580623f59d1"><code>c6b1516</code></a>
feat: Add basic support for Marko 6 and 5 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1914">#1914</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/837e52ca8601813b6bbbae13f6e7a614449de58a"><code>837e52c</code></a>
Release knip@6.30.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/6cdb3a6ac1f221d594fb4e71da00e80e6c2a90e6"><code>6cdb3a6</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b90a299e2461f618f065cf3cfcededb1b4a4abc0"><code>b90a299</code></a>
Consume only the default export of inline dynamic import loaders
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1915">#1915</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/cbe13bf87d80f1d458453b913e5408c22413c11f"><code>cbe13bf</code></a>
Track assets referenced from SCSS URLs (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1916">#1916</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/87d713e5288820096bb675a283d873fb3af486e8"><code>87d713e</code></a>
Analyze published type dependencies (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1909">#1909</a>)
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1912">#1912</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/360a47157ec850064da0f946ff233d00e07f87c7"><code>360a471</code></a>
Add ES2023 array types to TypeScript 5 CI</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/3f61542f6eaf07b526d76e5f4f0293ae059ad32f"><code>3f61542</code></a>
Update dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.31.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.61.0 to 0.62.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.62.0] - 2026-08-03</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>e6e584b oxfmt: Type jsdoc. enum options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25008">#25008</a>)
(leaysgur)</li>
</ul>
<h2>[0.59.0] - 2026-07-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>415fe1e oxfmt: Error on ignorePatterns that cannot match files
outside the config directory (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24286">#24286</a>)
(leaysgur)</li>
</ul>
<h2>[0.55.0] - 2026-06-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>9a2788b linter/unicorn: Implement <code>prefer-export-from</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22935">#22935</a>)
(AliceLanniste)</li>
</ul>
<h2>[0.54.0] - 2026-06-08</h2>
<h3>📚 Documentation</h3>
<ul>
<li>dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22965">#22965</a>)
(Boshen)</li>
<li>f88961a oxfmt: Annotate each config option with supported languages
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22953">#22953</a>)
(leaysgur)</li>
</ul>
<h2>[0.52.0] - 2026-05-26</h2>
<h3>🚀 Features</h3>
<ul>
<li>16b8058 oxfmt: Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22454">#22454</a>)
(leaysgur)</li>
</ul>
<h2>[0.50.0] - 2026-05-15</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>43b9978 formatter/sort_imports: Treat subpath imports as internal
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22440">#22440</a>)
(leaysgur)</li>
</ul>
<h2>[0.49.0] - 2026-05-11</h2>
<h3>🚀 Features</h3>
<ul>
<li>6e8e818 oxfmt: Experimental .svelte support (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21700">#21700</a>)
(leaysgur)</li>
</ul>
<h2>[0.45.0] - 2026-04-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>50c389b oxfmt: Support <code>.editorconfig</code>
<code>quote_type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20989">#20989</a>)
(leaysgur)</li>
</ul>
<h2>[0.44.0] - 2026-04-06</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/9a423f2f485b79c2353c49442c0c7f60f900261d"><code>9a423f2</code></a>
release(apps): oxlint v1.77.0 &amp;&amp; oxfmt v0.62.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25251">#25251</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/e6e584b9bee0f85f45874854c79dbf23ae6e527a"><code>e6e584b</code></a>
fix(oxfmt): type jsdoc. enum options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/25008">#25008</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.62.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.76.0 to 1.77.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.77.0] - 2026-08-03</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>5c0fa61 linter/eslint/no-warning-comments: Unify config structs and
remove manual options docs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25151">#25151</a>)
(Mikhail Baev)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>9dc7756 linter/typescript/no-unnecessary-condition: Clarify options
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25110">#25110</a>)
(camc314)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/9a423f2f485b79c2353c49442c0c7f60f900261d"><code>9a423f2</code></a>
release(apps): oxlint v1.77.0 &amp;&amp; oxfmt v0.62.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25251">#25251</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/5c0fa61ddbd098fea5101dff356dc9b67adbee95"><code>5c0fa61</code></a>
fix(linter/eslint/no-warning-comments): unify config structs and remove
manua...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/9dc77567291db6ebd0641284f80bf50163c6a257"><code>9dc7756</code></a>
docs(linter/typescript/no-unnecessary-condition): clarify options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/25110">#25110</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.77.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.1.5 to 8.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>create-vite@8.2.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@8.2.0/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>plugin-legacy@8.2.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/plugin-legacy@8.2.0/packages/plugin-legacy/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.2.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.2.0/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.2.0-beta.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.2.0-beta.0/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/vitejs/vite/compare/v8.2.0-beta.0...v8.2.0">8.2.0</a>
(2026-07-30)</h2>
<h3>Features</h3>
<ul>
<li>add <code>input</code> to <code>server.fs.allow</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/23035">#23035</a>)
(<a
href="https://github.com/vitejs/vite/commit/95a3cdab83e1125b03d2e8dd942fb6b64209e5fa">95a3cda</a>)</li>
<li><strong>bundled-dev:</strong> reload once after rebuild instead of
via the fallback page (<a
href="https://redirect.github.com/vitejs/vite/issues/23106">#23106</a>)
(<a
href="https://github.com/vitejs/vite/commit/b24381d741941b9ce2b1c07db62cc5f4d7bad981">b24381d</a>)</li>
<li><strong>bundled-dev:</strong> support worker file update accepted by
HMR (<a
href="https://redirect.github.com/vitejs/vite/issues/23068">#23068</a>)
(<a
href="https://github.com/vitejs/vite/commit/0d04351fdc12258c75b9f1cda5780fdb836ed0ef">0d04351</a>)</li>
<li><strong>config:</strong> include column in config incompatibility
location (<a
href="https://redirect.github.com/vitejs/vite/issues/23064">#23064</a>)
(<a
href="https://github.com/vitejs/vite/commit/8a245726944ed29225920d49be77c33c6e03afc8">8a24572</a>)</li>
<li><strong>dev:</strong> resolve interface name for explicit host in
network URLs (<a
href="https://redirect.github.com/vitejs/vite/issues/22965">#22965</a>)
(<a
href="https://github.com/vitejs/vite/commit/3ac77d9dd742968961af38a5a91ed6b061ceda7d">3ac77d9</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>bundledDev:</strong> print build errors to the terminal when
an HMR update fails (<a
href="https://redirect.github.com/vitejs/vite/issues/23024">#23024</a>)
(<a
href="https://github.com/vitejs/vite/commit/41c465896e8b11b1eb9c5fbdafbdcc528e189a2c">41c4658</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/23069">#23069</a>)
(<a
href="https://github.com/vitejs/vite/commit/4c07b74416f859d7e8bdace13409ef2d080edf76">4c07b74</a>)</li>
<li><strong>hmr:</strong> preserve environment snapshot during server
restart (<a
href="https://redirect.github.com/vitejs/vite/issues/22992">#22992</a>)
(<a
href="https://github.com/vitejs/vite/commit/b1186c36d06bb94941c58e8272fc4acb8512c93b">b1186c3</a>)</li>
<li><strong>importAnalysis:</strong> interop imports injected into
optimized dep files by plugins (<a
href="https://redirect.github.com/vitejs/vite/issues/23029">#23029</a>)
(<a
href="https://github.com/vitejs/vite/commit/8c2a87d41fb24536e59643351758084cde4d0dd7">8c2a87d</a>)</li>
<li><strong>module-runner:</strong> keep stack trace interception
working when <code>Object.prototype</code> is frozen (<a
href="https://redirect.github.com/vitejs/vite/issues/23073">#23073</a>)
(<a
href="https://github.com/vitejs/vite/commit/599c5b02a8b6879b05ede988020f1331e877aaea">599c5b0</a>)</li>
<li><strong>server:</strong> strip base in indexHtml module graph lookup
(<a
href="https://redirect.github.com/vitejs/vite/issues/22932">#22932</a>)
(<a
href="https://github.com/vitejs/vite/commit/fa005d19af5d847931c6dbefc63841c137383e6c">fa005d1</a>)</li>
<li>support resolving top-level input option with plugins (<a
href="https://redirect.github.com/vitejs/vite/issues/23101">#23101</a>)
(<a
href="https://github.com/vitejs/vite/commit/41df81a6a4c3eef08f7a9a8ac9530cd136c0eafa">41df81a</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>config:</strong> correct cacheDir default fallback
description (<a
href="https://redirect.github.com/vitejs/vite/issues/23060">#23060</a>)
(<a
href="https://github.com/vitejs/vite/commit/aafa103af5d71fb59d7c3dd617d0cbef3b222f1f">aafa103</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li>config CJS module vars in ESM case (<a
href="https://redirect.github.com/vitejs/vite/issues/23010">#23010</a>)
(<a
href="https://github.com/vitejs/vite/commit/d8cd38830251b95fd7dddcd0eee0ce94cc61c2f4">d8cd388</a>)</li>
</ul>
<h2><a
href="https://github.com/vitejs/vite/compare/v8.1.5...v8.2.0-beta.0">8.2.0-beta.0</a>
(2026-07-22)</h2>
<h3>Features</h3>
<ul>
<li>add <code>input</code> option (<a
href="https://redirect.github.com/vitejs/vite/issues/22642">#22642</a>)
(<a
href="https://github.com/vitejs/vite/commit/9beae37d7221b25463a011feb40b0303ca328d87">9beae37</a>)</li>
<li><strong>config:</strong> warn features incompatible with native
loader in bundle loader (<a
href="https://redirect.github.com/vitejs/vite/issues/22850">#22850</a>)
(<a
href="https://github.com/vitejs/vite/commit/05302b07267f6b4f9dbeac5b1d73fcc3dc06d730">05302b0</a>)</li>
<li><strong>css:</strong> export PostCSS config type for type-safe
configs (<a
href="https://redirect.github.com/vitejs/vite/issues/22792">#22792</a>)
(<a
href="https://github.com/vitejs/vite/commit/302c755a8125b9a26214e3b413922b5513e41981">302c755</a>)</li>
<li><strong>dev:</strong> label network URLs with their interface name
(<a
href="https://redirect.github.com/vitejs/vite/issues/22830">#22830</a>)
(<a
href="https://github.com/vitejs/vite/commit/78accc42a5b8887d9df624f7d4a934d3ead677d1">78accc4</a>)</li>
<li><strong>optimizer:</strong> support aube lockfile (<a
href="https://redirect.github.com/vitejs/vite/issues/22813">#22813</a>)
(<a
href="https://github.com/vitejs/vite/commit/6319827116c5be2a19c1b91c84ba3d38ad26a41c">6319827</a>)</li>
<li><strong>optimizer:</strong> support nub lockfile (<a
href="https://redirect.github.com/vitejs/vite/issues/22891">#22891</a>)
(<a
href="https://github.com/vitejs/vite/commit/65d3604f6fdbfcf6e86244d7fe3c1ca86acae701">65d3604</a>)</li>
<li>update rolldown-related dependencies and use client-side HMR in
bundled-dev (<a
href="https://redirect.github.com/vitejs/vite/issues/22961">#22961</a>)
(<a
href="https://github.com/vitejs/vite/commit/960e9efbc1372000caac46cc2f123cef4824e2bb">960e9ef</a>)</li>
<li><strong>wasm:</strong> expand test suite, unwrap WebAssembly.Global
and enable js-string builtins (<a
href="https://redirect.github.com/vitejs/vite/issues/22674">#22674</a>)
(<a
href="https://github.com/vitejs/vite/commit/9e79b51579457a9af4fa623b68a0bfabbf38010b">9e79b51</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>build:</strong> map CSS chunks in chunk import maps (fix <a
href="https://redirect.github.com/vitejs/vite/issues/22946">#22946</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/22947">#22947</a>)
(<a
href="https://github.com/vitejs/vite/commit/e16ff3a1199293ac9cdfa6132c08fdea162215f3">e16ff3a</a>)</li>
<li><strong>config:</strong> exclude virtual modules from native config
compat check (<a
href="https://redirect.github.com/vitejs/vite/issues/22979">#22979</a>)
(<a
href="https://github.com/vitejs/vite/commit/2ced1fe4e4e480ed78cb7aa5c78319e57bfa7783">2ced1fe</a>)</li>
<li><strong>css:</strong> rewrite urls in OnceExit-injected content (<a
href="https://redirect.github.com/vitejs/vite/issues/22983">#22983</a>)
(<a
href="https://github.com/vitejs/vite/commit/abb793e18c92592c21fbb8e1f3fc450b5839f04f">abb793e</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22985">#22985</a>)
(<a
href="https://github.com/vitejs/vite/commit/04f345b37064cd0bba6447eb5c32be5c22162f3d">04f345b</a>)</li>
<li><strong>deps:</strong> update dependency magic-string to v1 (<a
href="https://redirect.github.com/vitejs/vite/issues/22998">#22998</a>)
(<a
href="https://github.com/vitejs/vite/commit/c60b4d7cdb85b7d4f78671cdcfb863e5f8b66bb7">c60b4d7</a>)</li>
<li><strong>hmr:</strong> remove hot data after prune (<a
href="https://redirect.github.com/vitejs/vite/issues/23002">#23002</a>)
(<a
href="https://github.com/vitejs/vite/commit/be9631658f5191ee5c5665e780239d42a330280a">be96316</a>)</li>
<li>resolve root to real path (<a
href="https://redirect.github.com/vitejs/vite/issues/22832">#22832</a>)
(<a
href="https://github.com/vitejs/vite/commit/55bba7bbd9de40d031360e4408fe91bff5b29ec9">55bba7b</a>)</li>
</ul>
<h3>Performance Improvements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/24a611f1c83a976d32262628d42f683609746635"><code>24a611f</code></a>
release: v7.2.4</li>
<li><a
href="https://github.com/vitejs/vite/commit/2d66b7b14aa6dfd62f3d6a59ee8382ed5ca6fd32"><code>2d66b7b</code></a>
fix: revert &quot;perf(deps): replace debug with obug (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21107">#21107</a>)&quot;</li>
<li><a
href="https://github.com/vitejs/vite/commit/a668014dba377c2b82a32d8124f1761e9ea74f82"><code>a668014</code></a>
release: v7.2.3</li>
<li><a
href="https://github.com/vitejs/vite/commit/acfe939e1f7c303c34b0b39b883cc302da767fa2"><code>acfe939</code></a>
perf(deps): replace debug with obug (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21107">#21107</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/4f8171eb3046bd70c83964689897dab4c6b58bc0"><code>4f8171e</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21128">#21128</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/50297208452241061cb44d09a4bbdf77a11ac01e"><code>5029720</code></a>
chore(deps): update rolldown-related dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21127">#21127</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/5909efd8fbfd1bf1eab65427aea0613124b2797a"><code>5909efd</code></a>
fix: allow multiple <code>bindCLIShortcuts</code> calls with shortcut
merging (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21103">#21103</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/39a0a15fd24ed37257c48b795097a3794e54d255"><code>39a0a15</code></a>
chore(deps): update rolldown-related dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21095">#21095</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/6a34ac3422686e7cf7cc9a25d299cb8e5a8d92a0"><code>6a34ac3</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21096">#21096</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/02ceaec45e17bef19159188a28d9196fed1761be"><code>02ceaec</code></a>
chore(deps): update dependency <code>@​rollup/plugin-commonjs</code> to
v29 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21099">#21099</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/create-vite@8.2.0/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-11 01:06:37 -04:00
dependabot[bot] f1de248ed5 Bump the gh-actions group with 4 updates (#1171)
Bumps the gh-actions group with 4 updates:
[docker/login-action](https://github.com/docker/login-action),
[github/codeql-action/init](https://github.com/github/codeql-action),
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
and
[github/codeql-action/analyze](https://github.com/github/codeql-action).

Updates `docker/login-action` from 4.5.2 to 4.6.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/login-action/releases">docker/login-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.6.0</h2>
<ul>
<li>Harden buildx scoped config path handling by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1059">docker/login-action#1059</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1095.0 in <a
href="https://redirect.github.com/docker/login-action/pull/1051">docker/login-action#1051</a></li>
<li>Bump js-yaml from 5.2.1 to 5.2.2 in <a
href="https://redirect.github.com/docker/login-action/pull/1057">docker/login-action#1057</a></li>
<li>Bump postcss from 8.5.10 to 8.5.22 in <a
href="https://redirect.github.com/docker/login-action/pull/1056">docker/login-action#1056</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.5.2...v4.6.0">https://github.com/docker/login-action/compare/v4.5.2...v4.6.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/login-action/commit/dbcb813823bdd20940b903addbd779551569679f"><code>dbcb813</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1051">#1051</a>
from docker/dependabot/npm_and_yarn/aws-sdk-dependen...</li>
<li><a
href="https://github.com/docker/login-action/commit/5bcb015ee6ec720ecdeaef2dc1164122e9b209fc"><code>5bcb015</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/b30b2f2d3196c1714318ba0c3c3bec211d949752"><code>b30b2f2</code></a>
build(deps): bump the aws-sdk-dependencies group across 1 directory with
2 up...</li>
<li><a
href="https://github.com/docker/login-action/commit/9087f1e6d666fe0292409e3c819680c18526e108"><code>9087f1e</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1057">#1057</a>
from docker/dependabot/npm_and_yarn/js-yaml-5.2.2</li>
<li><a
href="https://github.com/docker/login-action/commit/0009830ea169ca16c24c0ea4cac1c325bfa3aee4"><code>0009830</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/23255232d3e43c8f0052d9a0dba82a515a88ce92"><code>2325523</code></a>
build(deps): bump js-yaml from 5.2.1 to 5.2.2</li>
<li><a
href="https://github.com/docker/login-action/commit/4ec1d4a769e8b05a89a7396551dc38b329211688"><code>4ec1d4a</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1056">#1056</a>
from docker/dependabot/npm_and_yarn/postcss-8.5.22</li>
<li><a
href="https://github.com/docker/login-action/commit/5fc99ba47bca274c5a499688f71c7ea79c0ea1b3"><code>5fc99ba</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1053">#1053</a>
from docker/dependabot/github_actions/aws-actions/co...</li>
<li><a
href="https://github.com/docker/login-action/commit/e512bd59d16c53d79ea5c0f0e345fe554453c4bb"><code>e512bd5</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1052">#1052</a>
from docker/dependabot/github_actions/codeql-actions...</li>
<li><a
href="https://github.com/docker/login-action/commit/a146c91b8f371700d323bae808af7cbdc2766ed5"><code>a146c91</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1059">#1059</a>
from crazy-max/harden-buildx-scope-paths</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/login-action/compare/371161bbe7024a29a25c5e19bfcbc0804fe9ad2c...dbcb813823bdd20940b903addbd779551569679f">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/init` from 4.37.3 to 4.37.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.6</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>v4.37.5</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>v4.37.4</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/5595ccaf912efad79be6eef63a5619ff05969be3"><code>5595cca</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4071">#4071</a>
from github/update-v4.37.6-6a9359a1b</li>
<li><a
href="https://github.com/github/codeql-action/commit/ec9c75796a7f2cee5af0c5ffa0b81dc3bb58754b"><code>ec9c757</code></a>
Add change note for PR 4070</li>
<li><a
href="https://github.com/github/codeql-action/commit/45c8742e17cbd668814137f95e605d925b8722a2"><code>45c8742</code></a>
Update changelog for v4.37.6</li>
<li><a
href="https://github.com/github/codeql-action/commit/6a9359a1bd054c53cae7bb737bd8d796cfbf3014"><code>6a9359a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4070">#4070</a>
from github/mbg/remote-address/change-file-default</li>
<li><a
href="https://github.com/github/codeql-action/commit/065cdc0394d424981db720df63ebc570e41b775f"><code>065cdc0</code></a>
Change <code>DEFAULT_CONFIG_FILE_NAME</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/f99dd5aeee9cf92e92d0c700cb0aa7afd7bbf431"><code>f99dd5a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4066">#4066</a>
from github/dependabot/npm_and_yarn/js-yaml-5.2.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/1804b211a343d69a6584d26fb3a68a8fe6ca39d4"><code>1804b21</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4068">#4068</a>
from github/mergeback/v4.37.5-to-main-d1ba80a1</li>
<li><a
href="https://github.com/github/codeql-action/commit/3020a2f46286abb1704269b22ada83bd0e81c64f"><code>3020a2f</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/93c3a5a40b7affbf8ea6a480767ed0db8e8d3c5c"><code>93c3a5a</code></a>
Update changelog and version after v4.37.5</li>
<li><a
href="https://github.com/github/codeql-action/commit/d1ba80a13dd99fba24a470575428917156a28b43"><code>d1ba80a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4067">#4067</a>
from github/update-v4.37.5-1cd4d01d5</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...5595ccaf912efad79be6eef63a5619ff05969be3">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.3 to 4.37.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.6</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>v4.37.5</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>v4.37.4</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/5595ccaf912efad79be6eef63a5619ff05969be3"><code>5595cca</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4071">#4071</a>
from github/update-v4.37.6-6a9359a1b</li>
<li><a
href="https://github.com/github/codeql-action/commit/ec9c75796a7f2cee5af0c5ffa0b81dc3bb58754b"><code>ec9c757</code></a>
Add change note for PR 4070</li>
<li><a
href="https://github.com/github/codeql-action/commit/45c8742e17cbd668814137f95e605d925b8722a2"><code>45c8742</code></a>
Update changelog for v4.37.6</li>
<li><a
href="https://github.com/github/codeql-action/commit/6a9359a1bd054c53cae7bb737bd8d796cfbf3014"><code>6a9359a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4070">#4070</a>
from github/mbg/remote-address/change-file-default</li>
<li><a
href="https://github.com/github/codeql-action/commit/065cdc0394d424981db720df63ebc570e41b775f"><code>065cdc0</code></a>
Change <code>DEFAULT_CONFIG_FILE_NAME</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/f99dd5aeee9cf92e92d0c700cb0aa7afd7bbf431"><code>f99dd5a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4066">#4066</a>
from github/dependabot/npm_and_yarn/js-yaml-5.2.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/1804b211a343d69a6584d26fb3a68a8fe6ca39d4"><code>1804b21</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4068">#4068</a>
from github/mergeback/v4.37.5-to-main-d1ba80a1</li>
<li><a
href="https://github.com/github/codeql-action/commit/3020a2f46286abb1704269b22ada83bd0e81c64f"><code>3020a2f</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/93c3a5a40b7affbf8ea6a480767ed0db8e8d3c5c"><code>93c3a5a</code></a>
Update changelog and version after v4.37.5</li>
<li><a
href="https://github.com/github/codeql-action/commit/d1ba80a13dd99fba24a470575428917156a28b43"><code>d1ba80a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4067">#4067</a>
from github/update-v4.37.5-1cd4d01d5</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...5595ccaf912efad79be6eef63a5619ff05969be3">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.6</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>v4.37.5</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>v4.37.4</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.6 - 04 Aug 2026</h2>
<ul>
<li>Changed the default filepath for the new remote file address format
that was introduced in CodeQL Action 4.37.0 / 3.37.0 to
<code>.github/codeql-config.yml</code> to align it with the suggested
path that is used elsewhere. <a
href="https://redirect.github.com/github/codeql-action/pull/4070">#4070</a></li>
</ul>
<h2>4.37.5 - 03 Aug 2026</h2>
<ul>
<li>Fixed a bug where a network error while streaming the download of
the CodeQL bundle could terminate the <code>init</code> Action instead
of falling back to downloading the bundle before extracting it. <a
href="https://redirect.github.com/github/codeql-action/pull/4061">#4061</a></li>
</ul>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/5595ccaf912efad79be6eef63a5619ff05969be3"><code>5595cca</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4071">#4071</a>
from github/update-v4.37.6-6a9359a1b</li>
<li><a
href="https://github.com/github/codeql-action/commit/ec9c75796a7f2cee5af0c5ffa0b81dc3bb58754b"><code>ec9c757</code></a>
Add change note for PR 4070</li>
<li><a
href="https://github.com/github/codeql-action/commit/45c8742e17cbd668814137f95e605d925b8722a2"><code>45c8742</code></a>
Update changelog for v4.37.6</li>
<li><a
href="https://github.com/github/codeql-action/commit/6a9359a1bd054c53cae7bb737bd8d796cfbf3014"><code>6a9359a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4070">#4070</a>
from github/mbg/remote-address/change-file-default</li>
<li><a
href="https://github.com/github/codeql-action/commit/065cdc0394d424981db720df63ebc570e41b775f"><code>065cdc0</code></a>
Change <code>DEFAULT_CONFIG_FILE_NAME</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/f99dd5aeee9cf92e92d0c700cb0aa7afd7bbf431"><code>f99dd5a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4066">#4066</a>
from github/dependabot/npm_and_yarn/js-yaml-5.2.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/1804b211a343d69a6584d26fb3a68a8fe6ca39d4"><code>1804b21</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4068">#4068</a>
from github/mergeback/v4.37.5-to-main-d1ba80a1</li>
<li><a
href="https://github.com/github/codeql-action/commit/3020a2f46286abb1704269b22ada83bd0e81c64f"><code>3020a2f</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/93c3a5a40b7affbf8ea6a480767ed0db8e8d3c5c"><code>93c3a5a</code></a>
Update changelog and version after v4.37.5</li>
<li><a
href="https://github.com/github/codeql-action/commit/d1ba80a13dd99fba24a470575428917156a28b43"><code>d1ba80a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4067">#4067</a>
from github/update-v4.37.5-1cd4d01d5</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...5595ccaf912efad79be6eef63a5619ff05969be3">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-11 01:06:28 -04:00
dependabot[bot] 78d5d0632a Bump the python-deps group across 1 directory with 5 updates (#1182)
Bumps the python-deps group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [python-socketio](https://github.com/miguelgrinberg/python-socketio) |
`5.16.3` | `5.16.4` |
| [rarfile](https://github.com/markokr/rarfile) | `4.4` | `4.5` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.51.8` | `4.51.11` |
| [prek](https://github.com/j178/prek) | `0.4.11` | `0.4.12` |
| [ruff](https://github.com/astral-sh/ruff) | `0.16.1` | `0.16.2` |


Updates `python-socketio` from 5.16.3 to 5.16.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/releases">python-socketio's
releases</a>.</em></p>
<blockquote>
<h2>Release 5.16.4</h2>
<p>See <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">CHANGES.md</a>
for release notes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">python-socketio's
changelog</a>.</em></p>
<blockquote>
<h1>python-socketio change log</h1>
<p><strong>Release 5.16.4</strong> - 2026-08-07</p>
<ul>
<li>Delete incomplete binary packet when client disconnects (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/4bec3ef87bcfd6ab5b94cd3ac09d873283a6960e">commit</a>)</li>
</ul>
<p><strong>Release 5.16.3</strong> - 2026-06-15</p>
<ul>
<li>Catch all exceptions in redis and rabbitmq client managers <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1581">#1581</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/80bb5c9b07e6b53e45f610ec29a24124c539d41b">commit</a>)</li>
</ul>
<p><strong>Release 5.16.2</strong> - 2026-05-21</p>
<ul>
<li>Prevent unnecessary resource allocations <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1574">#1574</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ca140fe44d0ceb3004073645222abec182d8784b">commit</a>)</li>
<li>Add zizmor to CI builds <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1570">#1570</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/664dc27ec6f34179ed1724430eda3520627fc642">commit</a>)</li>
</ul>
<p><strong>Release 5.16.1</strong> - 2026-02-06</p>
<ul>
<li>Use configured JSON module in managers <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1549">#1549</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6229261ae6e8c01e675097242e333ee84587a544">commit</a>)</li>
<li>Admin UI fixes: remove duplicate tasks, report transport upgrades
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1c2eab13a92fac9e43663eb0b5f099eb1c40ea5b">commit</a>)</li>
<li>Switch to Furo documentation template (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/add47d8c7abca697a2804141bbf29bfb095f7d5e">commit</a>)</li>
<li>Add Python free-threading to CI <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1554">#1554</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ccdd2004a038ae4b8171a05120c5d0787332f7ee">commit</a>)</li>
</ul>
<p><strong>Release 5.16.0</strong> - 2025-12-24</p>
<ul>
<li>Address deprecation warnings (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b235699d9b06564753c570b76055997e9d62a938">commit</a>)</li>
<li>Drop Python 3.8 and 3.9 from CI builds (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/d0728d2f74538762dd551fa9cd0cd1fd5aedfa37">commit</a>)</li>
</ul>
<p><strong>Release 5.15.1</strong> - 2025-12-16</p>
<ul>
<li>Restore support multiple arguments via pubsub emits <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1540">#1540</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c279f26bb8c9887c4ca99d4d81ad331c4844438c">commit</a>)</li>
</ul>
<p><strong>Release 5.15.0</strong> - 2025-11-22</p>
<ul>
<li>Retry initial Redis connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1536">#1534</a>
([commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1">#1</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad">https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad</a>)
[commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/2">#2</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d">https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d</a>))</li>
<li>Correctly regenerate RabbitMQ binding after a connection failure <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1516">#1516</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c52e93b4a328d98a968bfbdec0cfd598b73ee913">commit</a>)
(thanks <strong>Gritty_dev</strong>!)</li>
<li>Support <code>ext_type</code> in the <code>MsgPackPacket</code>
class <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1521">#1521</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/208925344a48485d2cd56e40eb74266c3bcb5311">commit</a>)</li>
<li>Support sending <code>bytesarray</code>s when using pub/sub managers
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6c9b9974f72e2efdf62407ecab24ee6995448098">commit</a>)</li>
<li>Fix typos in documentation <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1520">#1520</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/db3f1c2a0105c30cb833ddfca8f05fe4320468fd">commit</a>)
(thanks <strong>Lê Nam Khánh</strong>!)</li>
<li>Improvements to the logging documentation (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b423d0e38eef559b7e81acb7e32059de305f982c">commit</a>)</li>
</ul>
<p><strong>Release 5.14.3</strong> - 2025-10-29</p>
<ul>
<li>Support Python's native <code>ConnectionRefusedError</code>
exception to reject a connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1515">#1515</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f3b18bde3f16437b223491d4c3e440ea37105fe3">commit</a>)</li>
<li>Push binary data to the aiopika client manager <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1514">#1514</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/194e1b7f277b5f72e1de78d3f614e7b8b6c788ac">commit</a>)</li>
</ul>
<p><strong>Release 5.14.2</strong> - 2025-10-15</p>
<ul>
<li>Restore binary message support in message queue setups <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1509">#1509</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/bab4a10f48aaae11d7f832ebe5c30ad3f85d31b3">commit</a>)</li>
<li>Fix formatting of client connection error <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1507">#1507</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f298c9b54d76ab09ff72935937e1b9575bc45ffd">commit</a>)</li>
<li>Add 3.14 and pypy-3.11 CI tasks (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1f4cd3b025c294f25208ec3c05b5f8df6209e403">commit</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/d0cf60952281c0b8f41a7a73f01da8129da89032"><code>d0cf609</code></a>
Release 5.16.4</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/4bec3ef87bcfd6ab5b94cd3ac09d873283a6960e"><code>4bec3ef</code></a>
Delete incomplete binary packet when client disconnects</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/1e44ea3be1258ca2344872a98a4840743738080e"><code>1e44ea3</code></a>
Bump socket.io-parser from 4.2.6 to 4.2.7 in /examples/client/javascript
(<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/15">#15</a>...</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/a8568a449f28a81decb2f3d7adc7b0a2af88e12c"><code>a8568a4</code></a>
Bump aiohttp from 3.14.1 to 3.14.3 in /examples/server/aiohttp (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1591">#1591</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/3826ad453ba50b7d6876180a149a5b2fb0a01e73"><code>3826ad4</code></a>
Bump body-parser from 1.20.5 to 1.20.6 in /examples/client/javascript
(<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1590">#1590</a>)...</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/2d21903008b185b66ee644bfe231bb953298e9b1"><code>2d21903</code></a>
Remove failing codecov service</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/cb558519ffcc290974478902ceebd7d1a96a220e"><code>cb55851</code></a>
Bump aiohttp from 3.14.0 to 3.14.1 in /examples/server/aiohttp (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1584">#1584</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/71585b1df83f36029b1ead9c1b4cb42da85192de"><code>71585b1</code></a>
Bump tornado from 6.5.5 to 6.5.7 in /examples/server/tornado (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1583">#1583</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/02950be3756c3baedd63b5109de9ddac0af10a99"><code>02950be</code></a>
Version 5.16.4.dev0</li>
<li>See full diff in <a
href="https://github.com/miguelgrinberg/python-socketio/compare/v5.16.3...v5.16.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `rarfile` from 4.4 to 4.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/markokr/rarfile/releases">rarfile's
releases</a>.</em></p>
<blockquote>
<h2>rarfile v4.5</h2>
<p>Security fixes:</p>
<ul>
<li>Skip comments that are larger than 256k.</li>
</ul>
<p>Fixes:</p>
<ul>
<li>Truncate filenames at NUL byte.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/markokr/rarfile/blob/master/doc/news.rst">rarfile's
changelog</a>.</em></p>
<blockquote>
<h2>Version 4.5 (2026-08-02)</h2>
<p>Security fixes:</p>
<ul>
<li>Skip comments that are larger than 256k.
[<code>GHSA-94vx-95fq-wwvp
&lt;https://github.com/markokr/rarfile/security/advisories/GHSA-94vx-95fq-wwvp&gt;</code>_]</li>
</ul>
<p>Fixes:</p>
<ul>
<li>Truncate filenames at NUL byte.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/markokr/rarfile/commit/60c8513276ea462c39822db487c10111b9039442"><code>60c8513</code></a>
Refresh apt index</li>
<li><a
href="https://github.com/markokr/rarfile/commit/d62647091dc24bb384788c75b966d9dd4f0deaaf"><code>d626470</code></a>
v4.4</li>
<li><a
href="https://github.com/markokr/rarfile/commit/8321daa5417a62adce0db160510a1cdc43744af0"><code>8321daa</code></a>
Limit comment size</li>
<li><a
href="https://github.com/markokr/rarfile/commit/be6a4a69069852dcc16af3f6ad180e0266cbf15a"><code>be6a4a6</code></a>
Truncate filenames at NUL</li>
<li>See full diff in <a
href="https://github.com/markokr/rarfile/compare/v4.4...v4.5">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.8 to 4.51.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.11 - CDP Mode: Patch 127</h2>
<h2>CDP Mode: Patch 127</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3ba187938eca01c8582c0c832b5d00c44105b96f">Fix
memory leaks, fix bugs, and update timing</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8372dbc85d60c504c678a738df648791d712aec1">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/710ae0abd46732bd145e578b6a22fb5eecde27b9">Update
examples</a></li>
</ul>
<p>Special thanks to <a
href="https://github.com/crippledgeek"><code>@​crippledgeek</code></a>
(<a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4454">seleniumbase/SeleniumBase#4454</a>
and <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4455">seleniumbase/SeleniumBase#4455</a>)</p>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 127 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4457">seleniumbase/SeleniumBase#4457</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.10...v4.51.11">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.10...v4.51.11</a></p>
<h2>4.51.10 - CDP Mode: Patch 126</h2>
<h2>CDP Mode: Patch 126</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a7e28ac407fc63afdcfbaadc642b5a97b77a1375">Patch
the vendored version of nest_asyncio for Python 3.14+</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/076956c14a944b25ff191189b32123220e490fff">Update
timing of stealthy CDP Mode clicks</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0455ee62040c1b5185430035fd851518a9c83b84">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 126 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4453">seleniumbase/SeleniumBase#4453</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.9...v4.51.10">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.9...v4.51.10</a></p>
<h2>4.51.9 - CDP Mode: Patch 125</h2>
<h2>CDP Mode: Patch 125</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9954e1df1c17fd33a95999a78e011506d3e7bcc5">Fix
non-authenticated proxy in the sb_cdp format</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/35bad5b60b1f47a54a129d8aeb01ac0dcabadccd">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2bac11ba394f8edff0fff591f34400c946c01c62">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 125 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4450">seleniumbase/SeleniumBase#4450</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.8...v4.51.9">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.8...v4.51.9</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/85ca8c17da2bb85ca584c19ccc1773f64f0e1f8d"><code>85ca8c1</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4457">#4457</a>
from seleniumbase/cdp-mode-patch-127</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e5c180747c8fdc7da7990f6c8cf78fc166b5d801"><code>e5c1807</code></a>
Version 4.51.11</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/710ae0abd46732bd145e578b6a22fb5eecde27b9"><code>710ae0a</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8372dbc85d60c504c678a738df648791d712aec1"><code>8372dbc</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3ba187938eca01c8582c0c832b5d00c44105b96f"><code>3ba1879</code></a>
Fix memory leaks, fix bugs, and update timing</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/58995fc57a3bc2e6169fde7a4b210c557d768e52"><code>58995fc</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4453">#4453</a>
from seleniumbase/cdp-mode-patch-126</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9d98315c3989a4739d6e1b2aa1da7d0cb8a56732"><code>9d98315</code></a>
Version 4.51.10</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b050714d848b370bd7500acfc01010607b6cb6d3"><code>b050714</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0455ee62040c1b5185430035fd851518a9c83b84"><code>0455ee6</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/076956c14a944b25ff191189b32123220e490fff"><code>076956c</code></a>
Update timing of stealthy CDP Mode clicks</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.8...v4.51.11">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.11 to 0.4.12
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.12</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-03.</p>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--require-group</code> for hook group intersections (<a
href="https://redirect.github.com/j178/prek/pull/2472">#2472</a>)</li>
<li>Align fast-path and builtin pre-commit hooks (<a
href="https://redirect.github.com/j178/prek/pull/2433">#2433</a>)</li>
<li>Do not shuffle file list for verbose output (<a
href="https://redirect.github.com/j178/prek/pull/2431">#2431</a>)</li>
<li>Improve top-level command descriptions (<a
href="https://redirect.github.com/j178/prek/pull/2429">#2429</a>)</li>
<li>Install <code>uv</code> from Astral CDN and drop source racing (<a
href="https://redirect.github.com/j178/prek/pull/2455">#2455</a>)</li>
<li>Make <code>prek install --force</code> bypass external hooks paths
(<a
href="https://redirect.github.com/j178/prek/pull/2437">#2437</a>)</li>
<li>Show builtin hook flags in verbose list output (<a
href="https://redirect.github.com/j178/prek/pull/2427">#2427</a>)</li>
<li>Verify uv release archive checksums (<a
href="https://redirect.github.com/j178/prek/pull/2456">#2456</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Precompute file tags in parallel (<a
href="https://redirect.github.com/j178/prek/pull/2440">#2440</a>)</li>
<li>Skip diffs after known hook modifications (<a
href="https://redirect.github.com/j178/prek/pull/2447">#2447</a>)</li>
<li>Skip worktree diffs for read-only languages (<a
href="https://redirect.github.com/j178/prek/pull/2432">#2432</a>)</li>
<li>Track builtin hook file changes directly (<a
href="https://redirect.github.com/j178/prek/pull/2404">#2404</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Use full object IDs in diff snapshots (<a
href="https://redirect.github.com/j178/prek/pull/2448">#2448</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add a multi-repository configuration example (<a
href="https://redirect.github.com/j178/prek/pull/2434">#2434</a>)</li>
<li>Rewrite benchmark documentation (<a
href="https://redirect.github.com/j178/prek/pull/2469">#2469</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a
href="https://github.com/BitWeaverDev"><code>@​BitWeaverDev</code></a></li>
<li><a
href="https://github.com/allanlewis"><code>@​allanlewis</code></a></li>
</ul>
<h2>Install prek 0.4.12</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.12/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.12/prek-installer.ps1
| iex&quot;
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.12</h2>
<p>Released on 2026-08-03.</p>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--require-group</code> for hook group intersections (<a
href="https://redirect.github.com/j178/prek/pull/2472">#2472</a>)</li>
<li>Align fast-path and builtin pre-commit hooks (<a
href="https://redirect.github.com/j178/prek/pull/2433">#2433</a>)</li>
<li>Do not shuffle file list for verbose output (<a
href="https://redirect.github.com/j178/prek/pull/2431">#2431</a>)</li>
<li>Improve top-level command descriptions (<a
href="https://redirect.github.com/j178/prek/pull/2429">#2429</a>)</li>
<li>Install <code>uv</code> from Astral CDN and drop source racing (<a
href="https://redirect.github.com/j178/prek/pull/2455">#2455</a>)</li>
<li>Make <code>prek install --force</code> bypass external hooks paths
(<a
href="https://redirect.github.com/j178/prek/pull/2437">#2437</a>)</li>
<li>Show builtin hook flags in verbose list output (<a
href="https://redirect.github.com/j178/prek/pull/2427">#2427</a>)</li>
<li>Verify uv release archive checksums (<a
href="https://redirect.github.com/j178/prek/pull/2456">#2456</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Precompute file tags in parallel (<a
href="https://redirect.github.com/j178/prek/pull/2440">#2440</a>)</li>
<li>Skip diffs after known hook modifications (<a
href="https://redirect.github.com/j178/prek/pull/2447">#2447</a>)</li>
<li>Skip worktree diffs for read-only languages (<a
href="https://redirect.github.com/j178/prek/pull/2432">#2432</a>)</li>
<li>Track builtin hook file changes directly (<a
href="https://redirect.github.com/j178/prek/pull/2404">#2404</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Use full object IDs in diff snapshots (<a
href="https://redirect.github.com/j178/prek/pull/2448">#2448</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add a multi-repository configuration example (<a
href="https://redirect.github.com/j178/prek/pull/2434">#2434</a>)</li>
<li>Rewrite benchmark documentation (<a
href="https://redirect.github.com/j178/prek/pull/2469">#2469</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a
href="https://github.com/BitWeaverDev"><code>@​BitWeaverDev</code></a></li>
<li><a
href="https://github.com/allanlewis"><code>@​allanlewis</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/728238cf01e7b9e9ee8d1457f20c772fdc8e8426"><code>728238c</code></a>
Bump version to 0.4.12 (<a
href="https://redirect.github.com/j178/prek/issues/2473">#2473</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/e5403ca77cf44eb2d285328f0dd63386efddbddd"><code>e5403ca</code></a>
Add <code>--require-group</code> for hook group intersections (<a
href="https://redirect.github.com/j178/prek/issues/2472">#2472</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/370fc41b6b520b5fa0e34deb80d6415fc4417f7d"><code>370fc41</code></a>
Use ssl-certs to load custom certificates (<a
href="https://redirect.github.com/j178/prek/issues/2470">#2470</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/7cc64cac5f95c71b152406dd63658499ede597fe"><code>7cc64ca</code></a>
Rewrite benchmark documentation (<a
href="https://redirect.github.com/j178/prek/issues/2469">#2469</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6a81c105d682e48bd5cff68533cf66ec150f19c1"><code>6a81c10</code></a>
Update ubuntu Docker tag to v26 (<a
href="https://redirect.github.com/j178/prek/issues/2466">#2466</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/500a9d4149febbe639b8ac01fe1f8065ba5204ec"><code>500a9d4</code></a>
Run Conda tests sequentially (<a
href="https://redirect.github.com/j178/prek/issues/2468">#2468</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ebc1c38f41a44995394fb2c0f4ba971763d23be5"><code>ebc1c38</code></a>
Run .NET tests sequentially on Unix (<a
href="https://redirect.github.com/j178/prek/issues/2467">#2467</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/88fec177545361e7b2618b84defc8d24195ad048"><code>88fec17</code></a>
Update Rust crate tokio-util to v0.7.19 (<a
href="https://redirect.github.com/j178/prek/issues/2463">#2463</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/9d9c9f504a62b78c6b2154273d635b080c69e625"><code>9d9c9f5</code></a>
Use full object IDs in diff snapshots (<a
href="https://redirect.github.com/j178/prek/issues/2448">#2448</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/0c7fc8474377fde1811eec879eb0a42010129d80"><code>0c7fc84</code></a>
Update Rust crate tokio to v1.53.1 (<a
href="https://redirect.github.com/j178/prek/issues/2462">#2462</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.11...v0.4.12">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.1 to 0.16.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.2</h2>
<h2>Release Notes</h2>
<p>Released on 2026-08-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Avoid false positives on
<code>singledispatch</code> functions (<code>PYI041</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Register formatting capabilities dynamically to exclude TOML files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/MeGaGiGaGon"><code>@​MeGaGiGaGon</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
<h2>Install ruff 0.16.2</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.ps1
| iex&quot;
</code></pre>
<h2>Download ruff 0.16.2</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip">ruff-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz">ruff-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz">ruff-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz">ruff-powerpc64-unknown-linux-gnu.tar.gz</a></td>
<td>PPC64 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz">ruff-powerpc64le-unknown-linux-gnu.tar.gz</a></td>
<td>PPC64LE Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz">ruff-riscv64gc-unknown-linux-gnu.tar.gz</a></td>
<td>RISCV Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz">ruff-s390x-unknown-linux-gnu.tar.gz</a></td>
<td>S390x Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.2</h2>
<p>Released on 2026-08-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Avoid false positives on
<code>singledispatch</code> functions (<code>PYI041</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Register formatting capabilities dynamically to exclude TOML files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/MeGaGiGaGon"><code>@​MeGaGiGaGon</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/sharkdp"><code>@​sharkdp</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/5b48a040974781ba90b47c8df628f8fd9b6c95dd"><code>5b48a04</code></a>
Bump 0.16.2 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27555">#27555</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/1b9e5fc483b95a01fe02ff104820280b1b32e8ae"><code>1b9e5fc</code></a>
Update Swatinem/rust-cache action to v2.9.2 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27568">#27568</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c4e86fc0394c92a9334ba2eb026c77c21db403be"><code>c4e86fc</code></a>
[ty] Add helper extension methods for half-range and equality
constraints (<a
href="https://redirect.github.com/astral-sh/ruff/issues/2">#2</a>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/17a00de2e298612201a8fe30790e9399204af1b9"><code>17a00de</code></a>
[ty] Reuse primer commands in memory reports (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27553">#27553</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6ea296b96923e142eb13af2bc6ad261c280d8eb1"><code>6ea296b</code></a>
[ty] Normalize type labels in structured docstrings (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26923">#26923</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/2fc445f0053f4ec27c717fae0de3671d73c103be"><code>2fc445f</code></a>
[ty] Diagnose invalid <strong>getattr</strong> calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27502">#27502</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/22c7823c4e8bffcca97688d8438c9b567d6817d8"><code>22c7823</code></a>
[ty] Enable (but downrank) auto-import completion suggestions from
stub-only ...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/05160d507f05345a72db9c28ab4edf7c92334819"><code>05160d5</code></a>
[ty] Diagnose invalid descriptor <code>__get__</code> calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27400">#27400</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/baea3d0dcec6d6f6d1659321940f3725771c5f45"><code>baea3d0</code></a>
[ty] Expose strict analysis options in the playground (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27543">#27543</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c88946ebeb92be6d276087f0d528cd6471df4ead"><code>c88946e</code></a>
[ty] Bump ecosystem-analyzer for strict project settings (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27542">#27542</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.1...0.16.2">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-11 01:06:19 -04:00
Guflly 3c51b7cfaa Fix OIDC redirects on custom ports (#1180)
Fixes #1175

Preserves the forwarded host and port when Shelfmark builds OIDC
callback URLs. The reverse-proxy examples now retain custom ports as
well.

Tests:
- `uv run pytest -n 0 -q tests/core/test_proxy_headers.py
tests/core/test_oidc_routes.py`
- `uv run ruff check shelfmark/main.py tests/core/test_proxy_headers.py`
- `uv run ruff format --check shelfmark/main.py
tests/core/test_proxy_headers.py`
2026-08-11 01:05:23 -04:00
FlyinPancakeandCopilot Autofix powered by AI 3a9cff9816 feat(metadata): add Moly.hu metadata provider (#1172)
First of all, I don't know if you even want to merge a scraper-based
metadata provider. I made this just for my use-case. If you'd rather
not, I completely understand it.

An alternative would be adopting [Audiobookshelf's Metadata Provider
API](https://audiobookshelf.org/docs/documentation/community/community-providers)
which I contributed to it for exactly the reason to not have scrapers.

## What

Adds [Moly.hu](https://moly.hu) — the Hungarian community book catalog —
as a metadata provider, following the existing provider plugin
architecture (`@register_provider` + settings tab with enable checkbox
and Test Connection button, disabled by default).

## Why

None of the current providers cover Hungarian editions well: Hardcover
and Open Library rarely index them, and Google Books coverage is spotty.
Moly.hu is the de-facto catalog for Hungarian books (local editions
*and* Hungarian translations of foreign works). With this provider,
Universal mode works end-to-end for Hungarian titles: moly search →
localized title/author feed the release search → indexers that carry
Hungarian content can actually match. Related pain points: #595 (books
missing from metadata providers), #1035 (interest in niche sources).

## How

- HTML scraping with BeautifulSoup (already a dependency), no API key
needed
- Scraping approach (search URL, page structure, language-tag mapping)
adapted from the long-lived Calibre `Moly_hu` plugin (GPL v3, credited
in the module docstring), with fallback selector chains inherited from
it
- Sliding-window rate limit (30 req/min) to stay polite to a small
community site
- Standard `@cacheable` decorators; fetch failures return `None` so they
are not cached (same behavior as the Google Books provider)
- Search results carry cover thumbnails, rating and series info as
display fields; `get_book` parses title (zero-width chars stripped,
nested series link excluded), authors, ISBN-13/10, publisher, publish
year, description (spoiler-warning prefix stripped), tags/genres, cover,
and language (from moly's language tags, defaulting to `hu`)
- ISBN search resolves through moly's site search

## Testing

- `tests/metadata/test_moly_parse.py`: offline tests with fixture HTML
mirroring live moly.hu markup — search parsing/dedup, pagination guard,
failure-not-cached behavior, book-page parsing, ISBN resolution, ISBN
validation helper
- `uv run pytest tests/metadata` green (45 passed), `ruff check` / `ruff
format` clean
- Verified live against moly.hu (search, get_book, ISBN lookup) and
running in Docker alongside Hardcover

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-11 00:46:32 -04:00
dependabot[bot] 453d1f2b56 Bump oxlint-tsgolint from 0.25.0 to 7.0.2001 in /src/frontend (#1156)
Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from
0.25.0 to 7.0.2001.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.2001</h2>
<h2>Highlights</h2>
<p><a
href="https://oxc.rs/blog/2026-07-22-type-aware-linting-stable">Announcing
Type-Aware Linting Stable</a></p>
<h2>What's Changed</h2>
<ul>
<li>fix(release): preserve binary executable permissions by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1104">oxc-project/tsgolint#1104</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v7.0.2000...v7.0.2001">https://github.com/oxc-project/tsgolint/compare/v7.0.2000...v7.0.2001</a></p>
<h2>v7.0.2000</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(no-unnecessary-condition): improve diagnostics by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1092">oxc-project/tsgolint#1092</a></li>
<li>ci: use pnpm publish and drop global npm install by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1095">oxc-project/tsgolint#1095</a></li>
<li>feat(no-floating-promises): improve diagnostics by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1093">oxc-project/tsgolint#1093</a></li>
<li>fix(no-unnecessary-type-assertion): preserve type-changing
assertions by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1097">oxc-project/tsgolint#1097</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1098">oxc-project/tsgolint#1098</a></li>
<li>chore(deps): update module github.com/dlclark/regexp2/v2 to v2.5.2
by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1099">oxc-project/tsgolint#1099</a></li>
<li>chore(deps): update npm packages by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1100">oxc-project/tsgolint#1100</a></li>
<li>fix(ci): disable pnpm git checks for generated release packages by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1103">oxc-project/tsgolint#1103</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.25.0...v7.0.2000">https://github.com/oxc-project/tsgolint/compare/v0.25.0...v7.0.2000</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/482dcf70bffce7ea56f63128c74beb67dec658a2"><code>482dcf7</code></a>
fix(release): preserve binary executable permissions (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1104">#1104</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/7ea9b74861b5249be86aa19f5d44518e1b2554be"><code>7ea9b74</code></a>
fix(ci): disable pnpm git checks for generated release packages (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1103">#1103</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/a90133b97edcda3458445c5bd676c6d20db74042"><code>a90133b</code></a>
chore(deps): update npm packages (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1100">#1100</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/f5a7520fe69ec59cc84efd096de9f5d66cda13c4"><code>f5a7520</code></a>
chore(deps): update module github.com/dlclark/regexp2/v2 to v2.5.2 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1099">#1099</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/5cc766e7df4d9da6a12970c7788a65c55329b635"><code>5cc766e</code></a>
chore(deps): update github actions (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1098">#1098</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/4e9120aaefad311b2f959de053ce468967d06190"><code>4e9120a</code></a>
fix(no-unnecessary-type-assertion): preserve type-changing assertions
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1097">#1097</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/bbcafc7b10c33c092507f97b8f76488d5c79d9ba"><code>bbcafc7</code></a>
feat(no-floating-promises): improve diagnostics (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1093">#1093</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/305e137c155f012ddc89a9d62aab4866e09a8114"><code>305e137</code></a>
ci: use pnpm publish and drop global npm install (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1095">#1095</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/1b97ad9b435269f251876a4f2932e494f6cc0127"><code>1b97ad9</code></a>
feat(no-unnecessary-condition): improve diagnostics (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1092">#1092</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.25.0...v7.0.2001">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-05 09:25:21 -04:00
dependabot[bot] db11da5bda Bump the python-deps group across 1 directory with 2 updates (#1163)
Bumps the python-deps group with 2 updates in the / directory:
[qbittorrent-api](https://github.com/rmartin16/qbittorrent-api) and
[ruff](https://github.com/astral-sh/ruff).

Updates `qbittorrent-api` from 2026.7.0 to 2026.8.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/releases">qbittorrent-api's
releases</a>.</em></p>
<blockquote>
<h2>release-2026.8.0</h2>
<h2>What's Changed</h2>
<h3>Fixes</h3>
<ul>
<li>fix: preserve cached client when slicing or copying List objects by
<a href="https://github.com/Sanjays2402"><code>@​Sanjays2402</code></a>
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/644">rmartin16/qbittorrent-api#644</a></li>
</ul>
<h3>CI</h3>
<ul>
<li>ignore conflict409 on adding torrents in tests by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/640">rmartin16/qbittorrent-api#640</a></li>
<li>make CI tests resilient to qBittorrent's eventual consistency by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/643">rmartin16/qbittorrent-api#643</a></li>
</ul>
<h3>Chores</h3>
<ul>
<li>Bump the github-actions group with 4 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/647">rmartin16/qbittorrent-api#647</a></li>
<li>Bump pre-commit hook for ruff-pre-commit from v0.15.20 to v0.16.1 by
<a href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in
<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/649">rmartin16/qbittorrent-api#649</a></li>
<li>Bump pre-commit hook for mirrors-mypy from v2.1.0 to v2.3.0 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/650">rmartin16/qbittorrent-api#650</a></li>
<li>Bump the uv group with 7 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/648">rmartin16/qbittorrent-api#648</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/Sanjays2402"><code>@​Sanjays2402</code></a>
made their first contribution in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/644">rmartin16/qbittorrent-api#644</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.7.0...v2026.8.0">https://github.com/rmartin16/qbittorrent-api/compare/v2026.7.0...v2026.8.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md">qbittorrent-api's
changelog</a>.</em></p>
<blockquote>
<h3>v2026.8.0 (01 aug 2026)</h3>
<ul>
<li>Fix slicing returned objects (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/644">#644</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/1c9f4f72367547e782e58a61be65c4db9df08006"><code>1c9f4f7</code></a>
bump to v2026.8.0</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/ca122da2b5af3bdd6434471072b15070380c282d"><code>ca122da</code></a>
fix: preserve cached client when slicing or copying List objects (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/644">#644</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/4b3cab11c7090e32e7341b7144d3dbcce933b07f"><code>4b3cab1</code></a>
Bump the uv group with 7 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/648">#648</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/1bbc79b928ef11bec32360d17800695916a37c2a"><code>1bbc79b</code></a>
Bumped pre-commit hook for mirrors-mypy from v2.1.0 to v2.3.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/650">#650</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/97897ea6c39a1e86617212fdb073aa6e71efe53f"><code>97897ea</code></a>
Bumped pre-commit hook for ruff-pre-commit from v0.15.20 to v0.16.1 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/649">#649</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/27ef5fa77a518d80a78a51d0d648c4af5aa75c3b"><code>27ef5fa</code></a>
Bump the github-actions group with 4 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/647">#647</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/f76602bf71d302ae7e180d2d47b1c840f94eb1d8"><code>f76602b</code></a>
make CI tests resilient to qBittorrent's eventual consistency (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/643">#643</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/3006f83fa51abc9c5e3fadeff42e4c1ecd82e91c"><code>3006f83</code></a>
ignore conflict409 on adding torrents in tests (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/640">#640</a>)</li>
<li>See full diff in <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.7.0...v2026.8.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.0 to 0.16.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.1</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-30.</p>
<h3>Preview features</h3>
<ul>
<li>Add an option to opt out of human-readable names (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27160">#27160</a>)</li>
<li>[<code>flake8-pytest-style</code>] Make fixes safe by default and
unsafe only when comments are present (<code>PT018</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27201">#27201</a>)</li>
<li>[<code>pyupgrade</code>] Skip fix when a defaulted
<code>TypeVar</code> precedes a non-defaulted one (<code>UP040</code>,
<code>UP046</code>, <code>UP047</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27133">#27133</a>)</li>
<li>[<code>ruff</code>] Fix false positive with unpacked arguments
(<code>RUF065</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26959">#26959</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Bump <code>gen-lsp-types</code> to gracefully handle unknown
enumeration values in LSP messages (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27230">#27230</a>)</li>
<li>[<code>flake8-bugbear</code>] Mark <code>range</code> as immutable
(<code>B008</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27247">#27247</a>)</li>
<li>[<code>flake8-comprehensions</code>] NFKC-normalize keyword names in
<code>C408</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26813">#26813</a>)</li>
<li>[<code>flake8-return</code>] Fix false positive when variable is
read in <code>finally</code> clause (<code>RET504</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25441">#25441</a>)</li>
<li>[<code>pydocstyle</code>] Skip section detection inside RST
directive bodies (<code>D214</code>, <code>D405</code>,
<code>D413</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23635">#23635</a>)</li>
<li>[<code>refurb</code>] Parenthesize <code>yield</code> arguments in
the <code>FURB192</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27192">#27192</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Mark <code>PT022</code> fixes as
unsafe (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26440">#26440</a>)</li>
<li>[<code>refurb</code>] Mark fixes that remove unknown separators as
unsafe (<code>FURB105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27200">#27200</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix indexing of excluded nested Ruff workspaces (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27303">#27303</a>)</li>
<li>Lint TOML files in the LSP (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26862">#26862</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Cover <code>pycon</code> Markdown formatting (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27153">#27153</a>)</li>
<li>[<code>flake8-bandit</code>] Document <code>TYPE_CHECKING</code>
exception (<code>S101</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27004">#27004</a>)</li>
<li>[<code>flake8-import-conventions</code>] Document that
<code>extend-aliases</code> can override default aliases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27191">#27191</a>)</li>
<li>[<code>pylint</code>] Add missing fix safety gotchas for
<code>non-augmented-assignment</code> (<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27250">#27250</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Reduce syntax error noise by swallowing dedents like indents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27170">#27170</a>)</li>
<li>Vendor latest annotate-snippets (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27033">#27033</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/bxff"><code>@​bxff</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/LHMQ878"><code>@​LHMQ878</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.1</h2>
<p>Released on 2026-07-30.</p>
<h3>Preview features</h3>
<ul>
<li>Add an option to opt out of human-readable names (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27160">#27160</a>)</li>
<li>[<code>flake8-pytest-style</code>] Make fixes safe by default and
unsafe only when comments are present (<code>PT018</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27201">#27201</a>)</li>
<li>[<code>pyupgrade</code>] Skip fix when a defaulted
<code>TypeVar</code> precedes a non-defaulted one (<code>UP040</code>,
<code>UP046</code>, <code>UP047</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27133">#27133</a>)</li>
<li>[<code>ruff</code>] Fix false positive with unpacked arguments
(<code>RUF065</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26959">#26959</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Bump <code>gen-lsp-types</code> to gracefully handle unknown
enumeration values in LSP messages (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27230">#27230</a>)</li>
<li>[<code>flake8-bugbear</code>] Mark <code>range</code> as immutable
(<code>B008</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27247">#27247</a>)</li>
<li>[<code>flake8-comprehensions</code>] NFKC-normalize keyword names in
<code>C408</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26813">#26813</a>)</li>
<li>[<code>flake8-return</code>] Fix false positive when variable is
read in <code>finally</code> clause (<code>RET504</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25441">#25441</a>)</li>
<li>[<code>pydocstyle</code>] Skip section detection inside RST
directive bodies (<code>D214</code>, <code>D405</code>,
<code>D413</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23635">#23635</a>)</li>
<li>[<code>refurb</code>] Parenthesize <code>yield</code> arguments in
the <code>FURB192</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27192">#27192</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Mark <code>PT022</code> fixes as
unsafe (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26440">#26440</a>)</li>
<li>[<code>refurb</code>] Mark fixes that remove unknown separators as
unsafe (<code>FURB105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27200">#27200</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix indexing of excluded nested Ruff workspaces (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27303">#27303</a>)</li>
<li>Lint TOML files in the LSP (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26862">#26862</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Cover <code>pycon</code> Markdown formatting (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27153">#27153</a>)</li>
<li>[<code>flake8-bandit</code>] Document <code>TYPE_CHECKING</code>
exception (<code>S101</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27004">#27004</a>)</li>
<li>[<code>flake8-import-conventions</code>] Document that
<code>extend-aliases</code> can override default aliases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27191">#27191</a>)</li>
<li>[<code>pylint</code>] Add missing fix safety gotchas for
<code>non-augmented-assignment</code> (<code>PLR6104</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27250">#27250</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Reduce syntax error noise by swallowing dedents like indents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27170">#27170</a>)</li>
<li>Vendor latest annotate-snippets (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27033">#27033</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/bxff"><code>@​bxff</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a href="https://github.com/Avasam"><code>@​Avasam</code></a></li>
<li><a href="https://github.com/epage"><code>@​epage</code></a></li>
<li><a href="https://github.com/LHMQ878"><code>@​LHMQ878</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/80790b348b5188e7fc253665540f442c6ec7dd05"><code>80790b3</code></a>
Bump 0.16.1 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27330">#27330</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/63830f3e97b56ca3be0dd8f1092f76c4acc63213"><code>63830f3</code></a>
[ty] Borrow from constraint set storage less often (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27328">#27328</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f40dca98a7f1b6fff0cee5ecf1e6364d5a8bdc15"><code>f40dca9</code></a>
[ty] Preserve forwarded expanded-variadic diagnostic sources (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27266">#27266</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/0d804975a2645d6e4a795cf501fd764b88aa47e3"><code>0d80497</code></a>
Lint TOML files in the LSP (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26862">#26862</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d91586bd5b30f77f6614d57b73fc7dbea9051a0e"><code>d91586b</code></a>
Update prek dependencies (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27293">#27293</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/7da4b8b8d78fd6df2b3e06d8466d9cd49822900d"><code>7da4b8b</code></a>
[ty] Respect bounds and constraints in generic materializations (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27228">#27228</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b20daf741241a6829ff8963a203f7847561deb62"><code>b20daf7</code></a>
[ty] refactor: add helper function to send partial results (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27249">#27249</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/4d4c8fa1c75b00561ea24eefefb13eb5ff80e01f"><code>4d4c8fa</code></a>
[ty] Emit diagnostic when specializing a non-generic class (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26883">#26883</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/7c3e2db97deb5c5edd6e4303403ef6caf2bde8be"><code>7c3e2db</code></a>
[ty] Fix enum class container assignability (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27318">#27318</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d5ef97fcd03e108f7510f84b8ed85bb4051311fe"><code>d5ef97f</code></a>
[<code>flake8-return</code>] Fix false positive when variable is read in
<code>finally</code> claus...</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.0...0.16.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-05 09:23:43 -04:00
dependabot[bot] 0b22618d96 Bump the gh-actions group with 5 updates (#1157)
Bumps the gh-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [docker/login-action](https://github.com/docker/login-action) |
`4.4.0` | `4.5.2` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `8.3.2`
| `9.0.0` |
| [github/codeql-action/init](https://github.com/github/codeql-action) |
`4.37.0` | `4.37.3` |
|
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
| `4.37.0` | `4.37.3` |
|
[github/codeql-action/analyze](https://github.com/github/codeql-action)
| `4.37.0` | `4.37.3` |

Updates `docker/login-action` from 4.4.0 to 4.5.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/login-action/releases">docker/login-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.5.2</h2>
<ul>
<li>Surface Docker Hub OIDC error responses by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1058">docker/login-action#1058</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.5.1...v4.5.2">https://github.com/docker/login-action/compare/v4.5.1...v4.5.2</a></p>
<h2>v4.5.1</h2>
<ul>
<li>Support <code>dhi.io</code> as Docker Hub OIDC registry by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1054">docker/login-action#1054</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.5.0...v4.5.1">https://github.com/docker/login-action/compare/v4.5.0...v4.5.1</a></p>
<h2>v4.5.0</h2>
<ul>
<li><a href="https://github.com/docker/login-action#docker-hub">Docker
Hub OIDC</a> login support by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1048">docker/login-action#1048</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1091.0 in <a
href="https://redirect.github.com/docker/login-action/pull/1037">docker/login-action#1037</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.92.0 to 0.94.0 in
<a
href="https://redirect.github.com/docker/login-action/pull/1044">docker/login-action#1044</a>
<a
href="https://redirect.github.com/docker/login-action/pull/1050">docker/login-action#1050</a></li>
<li>Bump brace-expansion from 1.1.13 to 1.1.16 in <a
href="https://redirect.github.com/docker/login-action/pull/1046">docker/login-action#1046</a></li>
<li>Bump js-yaml from 5.2.0 to 5.2.1 in <a
href="https://redirect.github.com/docker/login-action/pull/1038">docker/login-action#1038</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.4.0...v4.5.0">https://github.com/docker/login-action/compare/v4.4.0...v4.5.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/login-action/commit/371161bbe7024a29a25c5e19bfcbc0804fe9ad2c"><code>371161b</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1058">#1058</a>
from crazy-max/fix-dockerhub-oidc-error-handling</li>
<li><a
href="https://github.com/docker/login-action/commit/5dc73df38ebcfa6f96479901e253d172c3e35849"><code>5dc73df</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/2aa1edee0b06c23880529064a4f7d7d3d2f9bc87"><code>2aa1ede</code></a>
surface Docker Hub OIDC error responses</li>
<li><a
href="https://github.com/docker/login-action/commit/abd2ef45e78c5afb21d64d4ca52ee8550d9572c7"><code>abd2ef4</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1055">#1055</a>
from crazy-max/test-registry-auth-oidc</li>
<li><a
href="https://github.com/docker/login-action/commit/d49d3a9839fef51322fa44989a44fdc43fccfc22"><code>d49d3a9</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1054">#1054</a>
from crazy-max/oidc-missing-dhi</li>
<li><a
href="https://github.com/docker/login-action/commit/b58b17c30b4db92a4ed049b213cae512b12e460b"><code>b58b17c</code></a>
test: cover Docker Hub OIDC with registry-auth</li>
<li><a
href="https://github.com/docker/login-action/commit/be646c21cec26cea303e29290d5f6ba6fde8e606"><code>be646c2</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/d77c059cb9956cedaa427dc022d89f39acba678f"><code>d77c059</code></a>
support dhi.io as Docker Hub OIDC registry</li>
<li><a
href="https://github.com/docker/login-action/commit/06fb636fac595d6fb4b28a5dfcb21a6f5091859c"><code>06fb636</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1037">#1037</a>
from docker/dependabot/npm_and_yarn/aws-sdk-dependen...</li>
<li><a
href="https://github.com/docker/login-action/commit/a8bc9539118a762b0e5788b53a50907977cc1b8d"><code>a8bc953</code></a>
[dependabot skip] chore: update generated content</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/login-action/compare/af1e73f918a031802d376d3c8bbc3fe56130a9b0...371161bbe7024a29a25c5e19bfcbc0804fe9ad2c">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 8.3.2 to 9.0.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v9.0.0 🌈 Change <code>prune-cache</code> default to
<code>false</code></h2>
<h2>Changes</h2>
<p>This release disables the default cache cache pruning to ease the
load on the PyPi infrastructure.
Since users might experience more GitHub Actions cache usage which might
result in higher costs this is marked as a breaking change. To read more
on why we did this (now) you can read the detailed analysis and
reasoning in <a
href="https://redirect.github.com/astral-sh/setup-uv/issues/967">#967</a></p>
<p>Besides this big breaking change we also have a small bugfix while
building caches for linux distributions that behave a big different than
the &quot;big ones&quot; and a speed up in version resolution by only
reading the version manifest until a matching version is found saving
runtime and network bandwith.</p>
<h2>🚨 Breaking changes</h2>
<ul>
<li>Change <code>prune-cache</code> default to <code>false</code> <a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/967">#967</a>)</li>
</ul>
<h2>🐛 Bug fixes</h2>
<ul>
<li>fix: fall back to distribution ID when os-release has no version
field <a href="https://github.com/cxzhong"><code>@​cxzhong</code></a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/961">#961</a>)</li>
</ul>
<h2>🚀 Enhancements</h2>
<ul>
<li>Speed up version client by partial response reads <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/807">#807</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>chore: update known checksums for 0.11.30 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/968">#968</a>)</li>
<li>chore: update known checksums for 0.11.29 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/960">#960</a>)</li>
</ul>
<h2>📚 Documentation</h2>
<ul>
<li>docs: update version references to v8.3.2 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/949">#949</a>)</li>
</ul>
<h2>⬆️ Dependency updates</h2>
<ul>
<li>chore(deps): roll up Dependabot updates <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/970">#970</a>)</li>
<li>chore(deps): roll up Dependabot updates <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/962">#962</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/c771a70e6277c0a99b617c7a806ffedaca235ff9"><code>c771a70</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/970">#970</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/2f537ca87c1ffa233ca2a1b84815388e3e42d845"><code>2f537ca</code></a>
chore: update known checksums for 0.11.30 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/968">#968</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/2269552d547df6f50e57442326930d30d943afe3"><code>2269552</code></a>
Speed up version client by partial response reads (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/807">#807</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/47a7f4fb2e900d6c33a5b5f231fa21dbfaeba52f"><code>47a7f4f</code></a>
Change <code>prune-cache</code> default to <code>false</code> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/967">#967</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/71966eff34a27b0a62ed4b9f6f6e383e071b1bb5"><code>71966ef</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/962">#962</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f12b1f0a84bd6dc2331b36b2bbdbb1d1e617dbcc"><code>f12b1f0</code></a>
fix: fall back to distribution ID when os-release has no version field
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/961">#961</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/ecd24dd710f2fb0dca1693a67af11fc4a5c5ec84"><code>ecd24dd</code></a>
chore: update known checksums for 0.11.29 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/960">#960</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/6a191366842ac1502ba6c07e9b5acd5c2d9d8db3"><code>6a19136</code></a>
docs: update version references to v8.3.2 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/949">#949</a>)</li>
<li>See full diff in <a
href="https://github.com/astral-sh/setup-uv/compare/11f9893b081a58869d3b5fccaea48c9e9e46f990...c771a70e6277c0a99b617c7a806ffedaca235ff9">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/init` from 4.37.0 to 4.37.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.3</h2>
<p>No user facing changes.</p>
<h2>v4.37.2</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>v4.37.1</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81"><code>e4fba86</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4031">#4031</a>
from github/update-v4.37.3-72f6a9da0</li>
<li><a
href="https://github.com/github/codeql-action/commit/fb50ab5d62a274adf3ef3e22cfe750ae87a0ede7"><code>fb50ab5</code></a>
Update changelog for v4.37.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/72f6a9da0def52d9193d6a758f0378b65091f8d1"><code>72f6a9d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4030">#4030</a>
from github/mbg/fix/no-proxy</li>
<li><a
href="https://github.com/github/codeql-action/commit/3b5ee58597653d9cc6785f3f1277f796d81f3646"><code>3b5ee58</code></a>
Use default <code>request</code> options instead of
<code>undefined</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/bfb6be4b5ecd3650f02f530571453e8c64ef0778"><code>bfb6be4</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4028">#4028</a>
from github/mergeback/v4.37.2-to-main-e0647621</li>
<li><a
href="https://github.com/github/codeql-action/commit/526ab84f9858816d9cf5f7b9df4dd5e2235f0eba"><code>526ab84</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/d6217b9b8c14166e4851db94c11155d03bd13c07"><code>d6217b9</code></a>
Update changelog and version after v4.37.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0647621c2984b5ed2f768cb892365bf2a616ad1"><code>e064762</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4027">#4027</a>
from github/update-v4.37.2-385bcdc5a</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0faed839190caa67a5cd42f1cc16246028ca3df"><code>e0faed8</code></a>
Add a couple of change notes</li>
<li><a
href="https://github.com/github/codeql-action/commit/73aad0eaa9df172668665a150d17b8bc5a650c20"><code>73aad0e</code></a>
Update changelog for v4.37.2</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.37.0 to 4.37.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.3</h2>
<p>No user facing changes.</p>
<h2>v4.37.2</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>v4.37.1</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81"><code>e4fba86</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4031">#4031</a>
from github/update-v4.37.3-72f6a9da0</li>
<li><a
href="https://github.com/github/codeql-action/commit/fb50ab5d62a274adf3ef3e22cfe750ae87a0ede7"><code>fb50ab5</code></a>
Update changelog for v4.37.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/72f6a9da0def52d9193d6a758f0378b65091f8d1"><code>72f6a9d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4030">#4030</a>
from github/mbg/fix/no-proxy</li>
<li><a
href="https://github.com/github/codeql-action/commit/3b5ee58597653d9cc6785f3f1277f796d81f3646"><code>3b5ee58</code></a>
Use default <code>request</code> options instead of
<code>undefined</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/bfb6be4b5ecd3650f02f530571453e8c64ef0778"><code>bfb6be4</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4028">#4028</a>
from github/mergeback/v4.37.2-to-main-e0647621</li>
<li><a
href="https://github.com/github/codeql-action/commit/526ab84f9858816d9cf5f7b9df4dd5e2235f0eba"><code>526ab84</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/d6217b9b8c14166e4851db94c11155d03bd13c07"><code>d6217b9</code></a>
Update changelog and version after v4.37.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0647621c2984b5ed2f768cb892365bf2a616ad1"><code>e064762</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4027">#4027</a>
from github/update-v4.37.2-385bcdc5a</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0faed839190caa67a5cd42f1cc16246028ca3df"><code>e0faed8</code></a>
Add a couple of change notes</li>
<li><a
href="https://github.com/github/codeql-action/commit/73aad0eaa9df172668665a150d17b8bc5a650c20"><code>73aad0e</code></a>
Update changelog for v4.37.2</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.37.0 to 4.37.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.3</h2>
<p>No user facing changes.</p>
<h2>v4.37.2</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>v4.37.1</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.4 - 29 Jul 2026</h2>
<ul>
<li>This version of the CodeQL Action adds support for the
<code>tools</code> input for the <code>codeql-action/init</code> step to
be specified using a <code>github-codeql-tools</code> <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">repository
property</a>. This feature will gradually be rolled out following the
release of this version. Once rolled out, this allows for the CodeQL CLI
version that is used in GitHub-managed workflows, such as Default Setup,
to be set to a custom value. For example, customers who run into issues
with rate limits when a new CodeQL CLI version is released can set the
value to <code>toolcache</code> to always use the CodeQL CLI version
that is available in the runner toolcache. For Advanced Setup workflows,
the value provided for <code>tools</code> in the workflow definition
always takes precedence unless the value of the repository property
starts with <code>!</code>. <a
href="https://redirect.github.com/github/codeql-action/pull/4037">#4037</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.2">2.26.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4051">#4051</a></li>
</ul>
<h2>4.37.3 - 22 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.37.2 - 21 Jul 2026</h2>
<ul>
<li>The new address format for the <code>config-file</code> input that
was introduced in CodeQL Action 4.37.0 is now enabled by default. In
addition to the format described there, the <code>remote=</code> prefix
can now be used to explicitly indicate that the input refers to a remote
file. All previous input formats continue to be accepted as well. <a
href="https://redirect.github.com/github/codeql-action/pull/4023">#4023</a></li>
<li>The CodeQL Action can now make use of <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">configured
private registries</a> in Default Setup to retrieve CodeQL configuration
files from remote repositories that require authentication. This will
allow customers to store their CodeQL configuration in a single
repository that can then be referenced by Default Setup workflows in
other repositories. We expect to roll this and other, related changes
out to everyone in July. <a
href="https://redirect.github.com/github/codeql-action/pull/4007">#4007</a></li>
</ul>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81"><code>e4fba86</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4031">#4031</a>
from github/update-v4.37.3-72f6a9da0</li>
<li><a
href="https://github.com/github/codeql-action/commit/fb50ab5d62a274adf3ef3e22cfe750ae87a0ede7"><code>fb50ab5</code></a>
Update changelog for v4.37.3</li>
<li><a
href="https://github.com/github/codeql-action/commit/72f6a9da0def52d9193d6a758f0378b65091f8d1"><code>72f6a9d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4030">#4030</a>
from github/mbg/fix/no-proxy</li>
<li><a
href="https://github.com/github/codeql-action/commit/3b5ee58597653d9cc6785f3f1277f796d81f3646"><code>3b5ee58</code></a>
Use default <code>request</code> options instead of
<code>undefined</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/bfb6be4b5ecd3650f02f530571453e8c64ef0778"><code>bfb6be4</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4028">#4028</a>
from github/mergeback/v4.37.2-to-main-e0647621</li>
<li><a
href="https://github.com/github/codeql-action/commit/526ab84f9858816d9cf5f7b9df4dd5e2235f0eba"><code>526ab84</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/d6217b9b8c14166e4851db94c11155d03bd13c07"><code>d6217b9</code></a>
Update changelog and version after v4.37.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0647621c2984b5ed2f768cb892365bf2a616ad1"><code>e064762</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/4027">#4027</a>
from github/update-v4.37.2-385bcdc5a</li>
<li><a
href="https://github.com/github/codeql-action/commit/e0faed839190caa67a5cd42f1cc16246028ca3df"><code>e0faed8</code></a>
Add a couple of change notes</li>
<li><a
href="https://github.com/github/codeql-action/commit/73aad0eaa9df172668665a150d17b8bc5a650c20"><code>73aad0e</code></a>
Update changelog for v4.37.2</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-05 09:23:34 -04:00
dependabot[bot] 42f308bc89 Bump the npm-deps group in /src/frontend with 7 updates (#1155)
Bumps the npm-deps group in /src/frontend with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [react](https://github.com/react/react/tree/HEAD/packages/react) |
`19.2.7` | `19.2.8` |
|
[react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom)
| `19.2.7` | `19.2.8` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `26.1.1` | `26.1.2` |
|
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
| `6.0.3` | `6.0.4` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.27.0` | `6.29.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.59.0` | `0.61.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.74.0` | `1.76.0` |

Updates `react` from 19.2.7 to 19.2.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/releases">react's
releases</a>.</em></p>
<blockquote>
<h2>19.2.8 (July 21st, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Performance improvements when decoding
(<a
href="https://redirect.github.com/facebook/react/pull/37087">#37087</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/react/react/commit/1dd4ecbdabf826f527fc9a58c05ea70375b7d170"><code>1dd4ecb</code></a>
[FlightReply] Performance improvements when decoding (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/37087">#37087</a>)</li>
<li><a
href="https://github.com/react/react/commit/b0d2fdb78bdfae075a7fa02ddcebbf25f90952c2"><code>b0d2fdb</code></a>
[19.2.x] Update required references to GitHub repo (<a
href="https://github.com/react/react/tree/HEAD/packages/react/issues/36753">#36753</a>)</li>
<li>See full diff in <a
href="https://github.com/react/react/commits/v19.2.8/packages/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-dom` from 19.2.7 to 19.2.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/react/react/releases">react-dom's
releases</a>.</em></p>
<blockquote>
<h2>19.2.8 (July 21st, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Performance improvements when decoding
(<a
href="https://redirect.github.com/facebook/react/pull/37087">#37087</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/react/react/commit/1dd4ecbdabf826f527fc9a58c05ea70375b7d170"><code>1dd4ecb</code></a>
[FlightReply] Performance improvements when decoding (<a
href="https://github.com/react/react/tree/HEAD/packages/react-dom/issues/37087">#37087</a>)</li>
<li><a
href="https://github.com/react/react/commit/b0d2fdb78bdfae075a7fa02ddcebbf25f90952c2"><code>b0d2fdb</code></a>
[19.2.x] Update required references to GitHub repo (<a
href="https://github.com/react/react/tree/HEAD/packages/react-dom/issues/36753">#36753</a>)</li>
<li>See full diff in <a
href="https://github.com/react/react/commits/v19.2.8/packages/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 26.1.1 to 26.1.2
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.0.3 to 6.0.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/releases">@​vitejs/plugin-react's
releases</a>.</em></p>
<blockquote>
<h2>plugin-react@6.0.4</h2>
<h3>Fixed <code>$RefreshSig$ is not defined</code> error when running
<code>vite dev</code> with <code>NODE_ENV=production</code></h3>
<p>When running <code>vite dev</code> with
<code>NODE_ENV=production</code>, the app errored with
<code>$RefreshSig$ is not defined</code>.
This error is now fixed.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.0.4 (2026-07-22)</h2>
<h3>Fixed <code>$RefreshSig$ is not defined</code> error when running
<code>vite dev</code> with <code>NODE_ENV=production</code></h3>
<p>When running <code>vite dev</code> with
<code>NODE_ENV=production</code>, the app errored with
<code>$RefreshSig$ is not defined</code>.
This error is now fixed.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/f4b549822ec239799d746c030abb0b9a7d8f0a04"><code>f4b5498</code></a>
release: plugin-react@6.0.4</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/7a4065906e07e616aee23c4fcc76a76b74a7d694"><code>7a40659</code></a>
fix(react): <code>$RefreshSig$ is not defined</code> with
NODE_ENV=production vite dev ...</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/98b32d47a3f2517d52e8a51d8e28ff2ed13678a2"><code>98b32d4</code></a>
fix(deps): update react 19.2.8 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1298">#1298</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/8ae5449be23079dd17fdefc64064a3d94be6fc39"><code>8ae5449</code></a>
fix: babel-plugin-react-compiler cannot be imported when used in a
framework ...</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/f09ea01b0b66a4900c3e42cef2aa0147e78b097c"><code>f09ea01</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1282">#1282</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.4/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.27.0 to 6.29.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.29.0</h2>
<ul>
<li>fix(glob): do not follow symbolic links in async glob (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1900">#1900</a>)
(b7d5ce2f545d91953a97733aa1567e8728b20644) - thanks <a
href="https://github.com/mogelbrod"><code>@​mogelbrod</code></a>!</li>
<li>Add built-in compiler for tsrx
(db05e0142a41fad2ad45d62ba5106e0d97c92b45)</li>
<li>Fix -u shortcut for --duration
(932b9262af275d209923a5efab1b6f23067bb006)</li>
</ul>
<h2>Release 6.28.0</h2>
<ul>
<li>Update oxc-resolver (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1889">#1889</a>)
(1444f6aaf04d42ad07ee0b88da4dfae0e116043a)</li>
<li>Keep entry-exported members public (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1890">#1890</a>)
(94967c13a589a7e83408b1495c31323ac126fcab)</li>
<li>Don't un-ignore sibling paths on unrelated gitignore negations
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1891">#1891</a>)
(5c026ba50c1e89804fc5094a52dc4c4c37d92bc2)</li>
<li>Memoize the gitignore shadowed-pattern check
(a5fa3b0ebb7f84c107dba1c1ca9a9b73995f668f)</li>
<li>Ignore nested files under a gitignore dir/* pattern
(404a53e3e49fa7c1f51b60bcb30ea50450f75aab)</li>
<li>Track types referenced by JSDoc imports (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1888">#1888</a>)
(6ae48aadbe03952690c8608e6df42bd039cf6624)</li>
<li>Update oxc-parser (02ca17a72c3f0afa7df32297d2dd2f5463ac6e00)</li>
<li>feat: markdownlint-cli2 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1887">#1887</a>)
(323b96f55b38b53f5e4648d72fecd968fae35147) - thanks <a
href="https://github.com/Zamiell"><code>@​Zamiell</code></a>!</li>
<li>Update rolldown snapshot
(009e509dee6a5013fd3937abb4ec81684601b023)</li>
<li>Resolve $GITHUB_ACTION_PATH in GHA composite actions
(ead489f066733f701acfe5b81eac0a6c813fb5c5)</li>
<li>Don't report <code>node:</code> specifiers as unlisted dependencies
(1a7114f0a159fe82328041e11fc61c5c1730cc01)</li>
<li>Discover tsdown CLI entries
(0d47a45bfc518a7bf73a4b4878aeab236d6f9791)</li>
<li>Discover Convex function modules
(e01f21c44773186e7ad74e7badf9fc81b82edfb5)</li>
<li>Ignore common system binaries
(cd003065fda5422550a412bba07ebbb1f9bae126)</li>
<li>Add OpenClaw plugin (73a2d7dd45f65ea312fde38cb4fa4f5a4fc34bf2)</li>
<li>Discover Tailwind CLI input stylesheet (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1551">#1551</a>)
(9ae5feed922ecb7e8c436545e9b45125bd73b457)</li>
<li>Discover Angular global stylesheets from angular.json
(fb9e0488f6f21284714d0651fcf1dd2de02d425a)</li>
<li>Hint when project patterns exclude a compiled extension
(74de516d3d73839536fc2a43c2c0ec38a6299631)</li>
<li>Ignore common global binaries
(a99a206015fe414a4de12016cc62499910afaf6f)</li>
<li>Run multiple preprocessors in sequence
(844358367e9d1939bbf47f8dcb97d810741f56c1)</li>
<li>fix(nuxt): resolve nuxt module paths (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1896">#1896</a>)
(3c8594f5ffc641b00575b6d7455990db1277ac75) - thanks <a
href="https://github.com/danielroe"><code>@​danielroe</code></a>!</li>
<li>Report unused re-exports when ignoreExportsUsedInFile is set (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1895">#1895</a>)
(a113a5f4eedc81ef56b00a3e488cc94febefede5) - thanks <a
href="https://github.com/mlm20"><code>@​mlm20</code></a>!</li>
<li>Pass -w to pnpm add in sentry ecosystem test
(ea8c8ac6fe9519f00ca6a61131b345f5de521704)</li>
<li>Update sentry snapshot
(b75768d544d9f869ebce8f8c6dd8490f3db87023)</li>
<li>Record all traversed dirs in glob cache (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1897">#1897</a>)
(81be1d436eae15518df764cbcb443899e11a9569)</li>
<li>Invalidate glob cache when .gitignore changes
(baff301f2dceda97bf8bf73809d811cc44c72c8c)</li>
<li>Improve Nuxt and Nitro plugin resolution
(86ffab7bcdd095631d6b0b17254e8acd6b5022bc)</li>
<li>fix: don't treat [-]-c[heck] as config flag for prettier (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1902">#1902</a>)
(b7266ee8240a9b8686e91a44a4706d3605d094c4) - thanks <a
href="https://github.com/davidkna-sap"><code>@​davidkna-sap</code></a>!</li>
<li>Use Entra ID to publish VS Code extension
(4236253482f884d92cfde2ccf85c7fb9aca17f7e)</li>
<li>Remove obsolete trust policy exclusions
(630d5f9835f4303ec9aa7d090ad40a177808c4fb)</li>
<li>Update dependencies (810147b5aa21bb57ad103fd19ba92844e42cd84c)</li>
<li>Migrate from typescript/native-preview to typescript
(140a25a577a64273a7a77f2ff2c8f224118ac298)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/d9a6fe096fe2711a54c62dbbe988fa9221267538"><code>d9a6fe0</code></a>
Release knip@6.29.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/932b9262af275d209923a5efab1b6f23067bb006"><code>932b926</code></a>
Fix -u shortcut for --duration</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/db05e0142a41fad2ad45d62ba5106e0d97c92b45"><code>db05e01</code></a>
Add built-in compiler for tsrx</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b7d5ce2f545d91953a97733aa1567e8728b20644"><code>b7d5ce2</code></a>
fix(glob): do not follow symbolic links in async glob (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1900">#1900</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/fc16b3875eabd27315c46653056a4a5b9eca4366"><code>fc16b38</code></a>
Release knip@6.28.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/140a25a577a64273a7a77f2ff2c8f224118ac298"><code>140a25a</code></a>
Migrate from typescript/native-preview to typescript</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/810147b5aa21bb57ad103fd19ba92844e42cd84c"><code>810147b</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b7266ee8240a9b8686e91a44a4706d3605d094c4"><code>b7266ee</code></a>
fix: don't treat [-]-c[heck] as config flag for prettier (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1902">#1902</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/86ffab7bcdd095631d6b0b17254e8acd6b5022bc"><code>86ffab7</code></a>
Improve Nuxt and Nitro plugin resolution</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/baff301f2dceda97bf8bf73809d811cc44c72c8c"><code>baff301</code></a>
Invalidate glob cache when .gitignore changes</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.29.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.59.0 to 0.61.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this package will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0">Keep a Changelog</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/65fe65d8429e1d1bdf86c517ff08bd119ee87660"><code>65fe65d</code></a>
release(apps): oxlint v1.76.0 &amp;&amp; oxfmt v0.61.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24976">#24976</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/83abe3b49c0913b1a984a7eec5e433a59fd76eae"><code>83abe3b</code></a>
release(apps): oxlint v1.75.0 &amp;&amp; oxfmt v0.60.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24713">#24713</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/e2e0f94253c5ce91a00394e2cba974bc152798db"><code>e2e0f94</code></a>
chore(docs): update sponsor section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24588">#24588</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.61.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.74.0 to 1.76.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.76.0] - 2026-07-27</h2>
<h3>🚀 Features</h3>
<ul>
<li>8d31dfa linter: Verify eslint/no-restricted-globals config schema
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24598">#24598</a>)
(vigneshwar)</li>
<li>7069621 linter: Verify jest/vitest prefer-lowercase-title config
schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24724">#24724</a>)
(Bartok)</li>
<li>016cf2a linter/oxc: Add bad-match-all-arg rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24900">#24900</a>)
(camc314)</li>
<li>cdc941e linter/n: Implement <code>exports-style</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24087">#24087</a>)
(Mikhail Baev)</li>
<li>1ad6f6c linter/eslint: Implement <code>id-denylist</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24632">#24632</a>)
(Mikhail Baev)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>3ff2e0e linter: Clarify config extends types (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24936">#24936</a>)
(Boshen)</li>
</ul>
<h2>[1.75.0] - 2026-07-20</h2>
<h3>🚀 Features</h3>
<ul>
<li>dd18383 linter/node: Implement no-top-level-await rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24634">#24634</a>)
(Connor Shea)</li>
<li>16a65f2 linter/react: Implement function-component-definition rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24471">#24471</a>)
(Cole Ellison)</li>
<li>7f1f585 linter: Reuse <code>jest/padding-around-test-blocks</code>
for <code>vitest/padding-around-test-blocks</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24519">#24519</a>)
(Mikhail Baev)</li>
<li>99978a8 linter/import/consistent-type-specifier-style: Support
<code>prefer-top-level-if-only-type-imports</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24502">#24502</a>)
(camc314)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>8694167 linter/eslint/prefer-destructuring: Handle typed
declarations (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24616">#24616</a>)
(camc314)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/65fe65d8429e1d1bdf86c517ff08bd119ee87660"><code>65fe65d</code></a>
release(apps): oxlint v1.76.0 &amp;&amp; oxfmt v0.61.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24976">#24976</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/3ff2e0e6fa1670d2300b2fb44dddc08c2df50a00"><code>3ff2e0e</code></a>
docs(linter): clarify config extends types (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24936">#24936</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/8d31dfa3934b0c8d276e022ad546836ee6d1dcd7"><code>8d31dfa</code></a>
feat(linter): verify eslint/no-restricted-globals config schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24598">#24598</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/7069621199a47158b853743ab6664126ec7b24b4"><code>7069621</code></a>
feat(linter): verify jest/vitest prefer-lowercase-title config schema
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24724">#24724</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/016cf2acd64e4f6d34226aecc84e69d342708858"><code>016cf2a</code></a>
feat(linter/oxc): add bad-match-all-arg rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24900">#24900</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/cdc941e5f81d00dfca63cc17cc39eb6d1462a9ed"><code>cdc941e</code></a>
feat(linter/n): implement <code>exports-style</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24087">#24087</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/1ad6f6c823da92a9b70a9f8c23d355d1b99f9e75"><code>1ad6f6c</code></a>
feat(linter/eslint): implement <code>id-denylist</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24632">#24632</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/83abe3b49c0913b1a984a7eec5e433a59fd76eae"><code>83abe3b</code></a>
release(apps): oxlint v1.75.0 &amp;&amp; oxfmt v0.60.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24713">#24713</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6ce51d3ff39d675bb3ce12abe31c5807f9683833"><code>6ce51d3</code></a>
chore(deps): update dependency oxlint-tsgolint to v7.0.2000 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24763">#24763</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/dd18383ee1504b319aee45f832045bcd1a7285d5"><code>dd18383</code></a>
feat(linter/node): implement no-top-level-await rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24634">#24634</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.76.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-05 09:23:22 -04:00
CamGoed e93fbd2a9b Fix issue with stale v1 hash queries to qbittorrent (#1162)
## Problem

Shelfmark can lose track of hybrid v1/v2 torrents after qBittorrent
completes their metadata download.

Shelfmark initially identifies the torrent by its v1 infohash. Once
metadata resolves, qBittorrent may switch the torrent’s primary `hash`
to the truncated v2 hash, causing lookups using the original v1 hash to
return nothing.

For example:

- v1: `edf46c7f938a3c678081734d7bff8b9c652ba5e5`
- qBittorrent `hash`: `0bed5f40753b342cb143e83c2b21924cc8474731`
- full v2:
`0bed5f40753b342cb143e83c2b21924cc847473134e44d1bd300bdc58c13010f`

At that point, querying `/api/v2/torrents/info` with the original v1
hash returns no records. Querying with the new primary hash works, and
the returned record still contains the original hash in `infohash_v1`.

`find_existing()` also ignored its provided category, so audiobook
torrents fall back to the default ebook category instead. This means the
fallback method for a mismatched download ID never occurs for
audiobooks, leading to a "failed" download that is actually successful
in qBittorrent. As a result, the downloaded files are not automatically
transferred/hardlinked to the output directory.

## Fix

- Match torrents against `hash`, `infohash_v1`, and `infohash_v2`.
- Wait for magnet metadata to finish downloading before returning the
torrent ID.
- Return qBittorrent’s current primary `hash`.
- Search the provided category first, then the configured default, and
finally the full torrent list.


Logs showing the issue:

```
2026-08-03 22:42:30,262 - shelfmark.release_sources.audiobookbay.scraper - DEBUG - scraper.py:450 - Generated Magnet Link: magnet:?xt=urn:btih:EDF46C7F938A3C678081734D7BFF8B9C652BA5E5&tr=...

2026-08-03 22:42:30,376 - shelfmark.download.clients.qbittorrent - DEBUG - qbittorrent.py:521 - qBittorrent add result: TorrentsAddedMetadata({'added_torrent_ids': ['edf46c7f938a3c678081734d7bff8b9c652ba5e5'], 'failure_count': 0, 'pending_count': 0, 'success_count': 1})

2026-08-03 22:42:30,427 - shelfmark.download.clients.qbittorrent - INFO - qbittorrent.py:545 - Added torrent: edf46c7f938a3c678081734d7bff8b9c652ba5e5

2026-08-03 22:42:30,427 - shelfmark.download.clients.base_handler - INFO - base_handler.py:868 - Added to qbittorrent: edf46c7f938a3c678081734d7bff8b9c652ba5e5 for 'Pathogenesis: A History of the World in Eight Plagues'

2026-08-03 22:42:30,427 - shelfmark.download.clients.base_handler - DEBUG - base_handler.py:906 - Starting poll for edf46c7f938a3c678081734d7bff8b9c652ba5e5 (content_type=audiobook)

2026-08-03 22:42:32,590 - shelfmark.download.clients.base_handler - DEBUG - base_handler.py:958 - Download edf46c7f938a3c678081734d7bff8b9c652ba5e5 not yet visible in client (attempt 1/15)

2026-08-03 22:43:02,345 - shelfmark.download.clients.base_handler - ERROR - base_handler.py:969 - Download edf46c7f938a3c678081734d7bff8b9c652ba5e5 not found after 15 attempts

2026-08-03 22:43:02,345 - shelfmark.download.clients.base_handler - INFO - base_handler.py:426 - Skipping download client cleanup for protocol=torrent after download error (client=qbittorrent id=edf46c7f938a3c678081734d7bff8b9c652ba5e5)
```
<br>


The successful torrent: 
<br>


<img width="968" height="159" alt="image"
src="https://github.com/user-attachments/assets/d63c4444-6a4d-4214-97a0-732acc338970"
/>
<br>


v1 vs v2 hash: 
<br>


<img width="749" height="212" alt="image"
src="https://github.com/user-attachments/assets/d985b78a-84fe-4a26-9697-126c787e7303"
/>


I ran some python queries from the shelfmark container that show the
mismatch:

```
qBittorrent URL: http://gluetun-mam:8081
Tracked hash:    edf46c7f938a3c678081734d7bff8b9c652ba5e5

=== PROPERTIES LOOKUP USING SHELFMARK HASH ===
HTTP status: 404
Not Found

=== EXACT /torrents/info HASH LOOKUP ===
Returned torrents: 0
=== FIND VISIBLE PATHOGENESIS TORRENT ===
Matching visible torrents: 1

Name:         Pathogenesis: A History of the World in Eight Plagues
Primary hash: 0bed5f40753b342cb143e83c2b21924cc8474731
Category:     audiobooks
State:        stalledUP
Progress:     1
Properties HTTP status: 200
Infohash v1:  edf46c7f938a3c678081734d7bff8b9c652ba5e5
Infohash v2:  0bed5f40753b342cb143e83c2b21924cc847473134e44d1bd300bdc58c13010f
```
2026-08-05 09:19:25 -04:00
dependabot[bot]andCaliBrain cdd156e142 Bump the python-deps group across 1 directory with 2 updates (#1153)
Bumps the python-deps group with 2 updates in the / directory:
[tqdm](https://github.com/tqdm/tqdm) and
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `tqdm` from 4.69.1 to 4.70.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.70.0 stable</h2>
<ul>
<li><code>contrib.concurrent</code>: major improvements
<ul>
<li>support <code>process_map(mp_context, max_tasks_per_child)</code>,
<code>thread_map(thread_name_prefix)</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1265">#1265</a>)</li>
<li>fix <code>total</code> based on shortest iterable length (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1473">#1473</a>)</li>
<li>use default <code>max_workers</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1543">#1543</a> &lt;-
<a href="https://redirect.github.com/tqdm/tqdm/issues/1530">#1530</a>,
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1518">#1518</a>)</li>
<li>support <code>timeout</code>, <code>buffersize</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1576">#1576</a>)</li>
<li>improve ETA (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1708">#1708</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1161">#1161</a>)</li>
<li>update <code>as_completed</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1709">#1709</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1565">#1565</a>)</li>
<li>add <code>tqdm.concurrent.intepreter_map</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1777">#1777</a>)</li>
</ul>
</li>
<li><code>asyncio</code>: support iterables with only
<code>__aiter__</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1714">#1714</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1686">#1686</a>)</li>
<li>support <code>reset(float(&quot;inf&quot;))</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1783">#1783</a> &lt;-
<a href="https://redirect.github.com/tqdm/tqdm/issues/1781">#1781</a>,
<a
href="https://redirect.github.com/tqdm/tqdm/issues/651">#651</a>)</li>
<li>framework: test &amp; reduce wheel size (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1782">#1782</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/96f2e60e4584cdab57a23602e27043d0465254ad"><code>96f2e60</code></a>
Merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1777">#1777</a> from
shermansiu/feat/interpreter-pool</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/c27393ec3a0a91d83dd53f04b80ee61f9c0cd5e4"><code>c27393e</code></a>
misc tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/061c6236d56f8c1ed0934606c3b4ee5c59cf122e"><code>061c623</code></a>
Disable <code>tqdm.monitor_interval</code> for subinterpreters because
they do not have ...</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/9fc160ba7f959f955058985b0d1122fc9f0b2729"><code>9fc160b</code></a>
Update how we check for <code>interpreter_map</code> support in the
tests</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/b42463a20fffc17ad4df2aa145076afb0dc4486d"><code>b42463a</code></a>
Ensure that subinterpreters can import tqdm while unpickling the
initializer</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/16d5486c402a2808ec9c398538e0bc56d00866de"><code>16d5486</code></a>
Add support for nested progress bars</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/9f5890fda6cf43e66782fbf34647f808bdc66d58"><code>9f5890f</code></a>
Add initial implementation for interpreter_map</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/321f920bb7368e27eee04fed1c0de2a8a236fd9d"><code>321f920</code></a>
Merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1783">#1783</a> from
LuShadowX/reset-inf-total</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/4664b5701ebc5299290a1fb31a229fb1bfc64703"><code>4664b57</code></a>
minor tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/426a0988a1e9970041f5a649ae8a6376c5293fbe"><code>426a098</code></a>
Treat inf total as unknown in reset() too</li>
<li>Additional commits viewable in <a
href="https://github.com/tqdm/tqdm/compare/v4.69.1...v4.70.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.7 to 4.51.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.8 - Add <code>drag_and_drop()</code> with CDP</h2>
<h2>Add <code>drag_and_drop()</code> with CDP</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b05c11f370e69d7566d59d90883c8e8fec1c0024">Add
a CDP-based drag_and_drop() method</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4442">seleniumbase/SeleniumBase#4442</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9d9ffb4f3b335da6674917b395958c9378186067">Update
CDP Mode examples</a>
--&gt; Specifically for <code>drag_and_drop()</code></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/57f2a4ec5dd286222b114acb5d2272ad459d787d">Update
the docs</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Add <code>drag_and_drop()</code> with CDP by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4443">seleniumbase/SeleniumBase#4443</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.7...v4.51.8">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.7...v4.51.8</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8abc55e9f5ef3f2e1d8c4d92351bcbbf7163e7ce"><code>8abc55e</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4443">#4443</a>
from seleniumbase/drag-and-drop-with-cdp</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/89642ff4894e3351739dc359632566902379ca64"><code>89642ff</code></a>
Version 4.51.8</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9d9ffb4f3b335da6674917b395958c9378186067"><code>9d9ffb4</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/57f2a4ec5dd286222b114acb5d2272ad459d787d"><code>57f2a4e</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b05c11f370e69d7566d59d90883c8e8fec1c0024"><code>b05c11f</code></a>
Add a CDP-based <code>drag_and_drop()</code> method</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.7...v4.51.8">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-07-31 00:23:42 -04:00
CaliBrainandClaude Opus 5 21f2b6b95c Fix torrent post-import category follow-ups and clear the lint backlog (#1154)
rTorrent set_category and remove now uppercase the info hash, which
reaches us lowercase while rTorrent's XML-RPC lookups are case
sensitive. remove() had this bug before #1148, making
PROWLARR_TORRENT_ACTION=remove a silent no-op for rTorrent.

Transmission set_category appends the post-import label instead of
replacing the whole label list. The unsupported-client path in
post_process_cleanup logs at debug instead of warning, so Real-Debrid
and AllDebrid users stop seeing a warning on every successful import.

The Real-Debrid and AllDebrid clients now follow the conventions used by
the other clients (_raise_runtime_error helpers, narrow error tuples,
ClassVar, Path.open), and register_client is generic over a TypeVar
bound to DownloadClient so decorated classes keep their concrete type.
make fix and the lint, format and typecheck targets all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 00:17:28 -04:00
CaliBrain 10554444a9 Create a Tor watchguard and make iptables non mandatory (#1152)
Fix https://github.com/calibrain/shelfmark/issues/1150
2026-07-30 23:41:55 -04:00
CaliBrain ce026e2eb8 IRC health checks (#1151) 2026-07-30 23:39:12 -04:00
Tilian B ff770940ca Add torrent post-import category action (#1148)
## Summary

- add a **Change Category** torrent completion action and conditionally
show its post-import category/label setting
- update kept torrents only after a successful library import
- support qBittorrent categories, Transmission labels, Deluge's Label
plugin, and rTorrent's `custom1` label
- preserve existing Keep/Remove behavior and document the new
environment setting

## Behavior

Category changes happen from `post_process_cleanup`, after output
transfer and post-processing complete. This keeps the existing hardlink
flow unchanged. An empty post-import category is a no-op, and client API
failures are logged without turning a successful library import into a
failure.

## Validation

- `pytest -n 0 tests/prowlarr/test_qbittorrent_client.py
tests/prowlarr/test_transmission_client.py
tests/prowlarr/test_deluge_client.py
tests/prowlarr/test_rtorrent_client.py tests/prowlarr/test_handler.py
tests/config/test_generate_env_docs.py` — 161 passed
- `ruff check` on all changed Python files — passed
- `basedpyright` on the changed client implementation files — passed
- full `basedpyright shelfmark/download/clients` currently reports two
pre-existing errors in the new debrid connection-test code at
`settings.py:546` and `settings.py:563`, outside this PR's diff
- multi-architecture Docker images built successfully for `linux/amd64`
and `linux/arm64`
2026-07-30 23:38:53 -04:00
PaulVumon 340853477f feat(download): add native Real-Debrid and AllDebrid debrid service clients (#1146)
## Summary
Adds native download client support for debrid services (**Real-Debrid**
and **AllDebrid**), routing magnet links and torrents through their APIs
to download content via their CDN infrastructure.

## Features
- **Real-Debrid Client (\RealDebridClient\)**:
- API v1.0 integration (magnet upload, file selection, status polling,
link unrestricting, HTTP download)
  - Premium account validation via connection test
- **AllDebrid Client (\AllDebridClient\)**:
- API v4/v4.1 integration (magnet upload, status polling, file tree
listing, link unlocking with delayed link support, HTTP download)
  - Multi-tier link resolution strategy with automatic fallback
  - Premium account validation via connection test
- **Common & UI**:
- Ebook & Audiobook file filtering (\.epub\, \.m4b\, \.mp3\, \.pdf\,
\.flac\, etc.)
- Settings UI options in \PROWLARR_TORRENT_CLIENT\ dropdown with API key
configuration and test connection buttons
2026-07-29 22:22:48 -04:00
816a735cde Add a {Language} naming template variable, and consolidate language resolution (#1142)
Fixes #1138
Fixes #1141

## Problem

Two language editions of one book resolve to the same canonical title,
so they render to the same path and the second gets a `_1` collision
suffix. Audiobookshelf treats a folder as exactly one library item, so
the pair becomes a single book with both files as tracks and a summed
runtime.

Shelfmark already parses and displays the language. It just never
reached the template engine.

## `{Language}` template variable

A template like `{Author}/{Title}{ (Language)}/{Author} - {Title}` now
yields:

```
/library/J K Rowling/Harry Potter (sv)/J K Rowling - Harry Potter.m4b
/library/J K Rowling/Harry Potter/J K Rowling - Harry Potter.m4b
```

The untagged edition's path is byte-identical to today, so no existing
layout shifts.

Three details worth flagging:

**The value is casefolded.** On a case-insensitive filesystem `(SV)` and
`(sv)` would collapse back into one folder, reintroducing the exact
collision being fixed.

**Values meaning "we don't know" render nothing** rather than producing
`Project Hail Mary (unknown)` folders. Anna's Archive reports that
string literally (`direct_download.py`, `language = detected or
"unknown"`).

**The frontend wasn't sending the release language at all**, so the
token would have stayed empty for exactly the audiobook sources in the
report. Prowlarr and AudiobookBay do not put language in `extra` the way
`direct_download` does, hence the payload plumbing. It reads
`release.language`, never `book.language` — the latter is the provider's
canonical edition and would mislabel a translation, with a regression
test for that specifically.

Not gated to audiobooks: Calibre-Web-Automated stages ingested files by
basename and discards folder structure, so the rename (filename)
template is the only lever those users have. Verified that form works:
`J K Rowling - Harry Potter (sv).epub`.

## Language consolidation (#1141)

Three release sources each carried their own alias map, all resolving to
the same ISO 639-1 codes, alongside a bundled database that only one of
them used. Adding a language meant editing three places.

Aliases now live in `data/book-languages.json` beside the code and name
they belong to, and `shelfmark/core/languages.py` resolves any of them —
two-letter code, ISO 639-2 three-letter in either the bibliographic or
terminological form, or English name. Prowlarr and AudiobookBay drop
their tables. Direct Download keeps its own path-parsing heuristics,
including the ambiguous short codes that collide with English words
(`de`, `en`, `no`, `in`), and takes only the alias data.

This also closes a coverage gap. MyAnonamouse offers 62 languages;
Prowlarr mapped 37, and an unmapped code is *dropped* rather than passed
through, so the other 25 carried no language at all — leaving
`{Language}` empty and the collision unfixed for Latin, Farsi, Tamil,
Urdu and the rest. Seven languages MAM offers had no database entry at
all: Bosnian, Burmese, Estonian, Icelandic, Manx, Scottish Gaelic,
Sanskrit.

Also fixes the Traditional Chinese code, which used a U+2011
non-breaking hyphen. Nothing compares against the ASCII spelling today
so it was latent, but it would silently defeat the first thing that did.

## Validation

Verified end to end against a live Prowlarr and MyAnonamouse, not just
unit tests. A real search returning both an English and a Swedish
edition, through the actual `queue_release` → `DownloadTask` → naming
path:

```
STEP 1  real MAM search        -> 37 releases, languages: ['en', 'sv']
STEP 3  queue_release          -> task.language='sv'
STEP 4  build_metadata_dict    -> metadata['Language']='sv'
STEP 5  build_library_path     -> /library/J K Rowling/Harry Potter (sv)/...
two language editions resolve to DIFFERENT folders: True
```

The refactor is pinned by a snapshot of both per-source maps taken
*before* they were deleted. All 131 aliases are asserted to still
resolve to the same code, one parametrised test each, so a regression
names the specific alias.

Also verified: the filename-only template, the retry round-trip
(`serialize_task_for_retry` → `_restore_task_from_retry_payload`, plus a
legacy payload with no `language` key), and placeholder handling.

Added a `KNOWN_TOKENS` ordering invariant test — `find_placeholder()`
does a substring `.find()` in list order and nothing protected that
contract, so a future token in the wrong position could silently shadow
an existing one. And a lockstep guard on the frontend, since
`KNOWN_TOKENS` is hand-duplicated in TypeScript.

**One caveat worth stating.** Three MAM codes are confirmed by
observation (`ENG`→`en`, `SWE`→`sv`, `MAL`→`ml`, the last from a real
`[MAL / EPUB]` Tagore release). The remaining ~59 are derived from ISO
639-2 rather than observed, because MAM's catalogue is overwhelmingly
English — enabling 27 extra languages still yielded only one non-English
hit across 258 results. Mitigated rather than closed: both 639-2
variants are present for every language where they differ, and a wrong
alias is an unused entry while a missing one loses the language. Happy
to correct any code a maintainer knows differs.

## Test results

2056 Python tests pass (up from 1906). Frontend typecheck, lint, format
and 126 unit tests pass.

Pre-existing failures on my machine, unchanged by this branch and
unrelated: `tests/bypass/` needs `seleniumbase`, and
`tests/config/test_entrypoint_permissions.py` uses bash-4 syntax that
macOS bash 3.2 rejects.

---------

Co-authored-by: delize <4028612+delize@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-07-28 15:19:59 -04:00
dependabot[bot] d1cdaaeb5e Bump the python-deps group across 1 directory with 3 updates (#1144)
Bumps the python-deps group with 3 updates in the / directory:
[tqdm](https://github.com/tqdm/tqdm),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[prek](https://github.com/j178/prek).

Updates `tqdm` from 4.69.0 to 4.69.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.69.1 stable</h2>
<ul>
<li><code>contrib.logging</code>: preserve filters (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1775">#1775</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1581">#1581</a>)</li>
<li><code>rich</code>: misc fixes (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1773">#1773</a>)
<ul>
<li>support generators (without <code>len</code>) (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1391">#1391</a>)</li>
<li>fix potential <code>AttributeError</code> on exit (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1674">#1674</a>)</li>
</ul>
</li>
<li>fix <code>total=float('inf')</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1781">#1781</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/651">#651</a>)</li>
<li>fix potential <code>AttributeError</code> on exit (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1778">#1778</a> &lt;-
<a href="https://redirect.github.com/tqdm/tqdm/issues/1668">#1668</a>,
<a href="https://redirect.github.com/tqdm/tqdm/issues/1537">#1537</a>,
<a
href="https://redirect.github.com/tqdm/tqdm/issues/261">#261</a>)</li>
<li>fix minor docs typos (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1780">#1780</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1746">#1746</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/93370ff891582e458c40196ea78a1a9d720fbb45"><code>93370ff</code></a>
bump version, merge pull requests <a
href="https://redirect.github.com/tqdm/tqdm/issues/1781">#1781</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1773">#1773</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1778">#1778</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1775">#1775</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1780">#1780</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1746">#1746</a></li>
<li><a
href="https://github.com/tqdm/tqdm/commit/238501fa4f86fae2ce268710dd9de0474d36c732"><code>238501f</code></a>
docs: fix redundant word typo in tests_synchronisation.py</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/b78624a9eacffcefa566e1bc6e476f6a03c6ec0a"><code>b78624a</code></a>
contrib.logging: preserve filters</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/9f92bc6439b906f359a9f533d527d7be0ac2f5b7"><code>9f92bc6</code></a>
remove unnecessary comments</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/494372e2be901951b230331870a458025ea1ea9b"><code>494372e</code></a>
Fix AttributeError in <code>close()</code> on failed
<code>__init__</code></li>
<li><a
href="https://github.com/tqdm/tqdm/commit/796cea14a9e43d40838fbe47c4e9287b30552042"><code>796cea1</code></a>
misc tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/164ef7302b4c8c9dd455b523d8e8c38c61e68d50"><code>164ef73</code></a>
rich: misc fixes</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/f18c88e92707add150662885ec8d424e60c80bda"><code>f18c88e</code></a>
fix properly</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/90f59704b59c69a7ea1210a76ccffec58faa8538"><code>90f5970</code></a>
minor tidy</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/ef15578141f2df10f9c169ec619d8a5217f6a37f"><code>ef15578</code></a>
fix: handle total=inf in format_meter to avoid OverflowError</li>
<li>Additional commits viewable in <a
href="https://github.com/tqdm/tqdm/compare/v4.69.0...v4.69.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.6 to 4.51.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.7 - Add <code>click_and_hold()</code> with CDP</h2>
<h2>Add <code>click_and_hold()</code> with CDP</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6316b0aa95c947fc4f974662212f3cf77d1f829e">Add
a CDP-based click_and_hold() method</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e667ad0ff5e19c8f85f7b7f42ba9f672a63639e3">Adjust
timings and refactor</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f932c2d874c000d0149f2754a32bc955cfd71aa7">Update
examples</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7775f1db77594bd1642714de013d999e49c36e5c">Update
the docs</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Add <code>click_and_hold()</code> with CDP by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4441">seleniumbase/SeleniumBase#4441</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.6...v4.51.7">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.6...v4.51.7</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ec403eec792569e5d5dda5ff8d8772f1d9c141ae"><code>ec403ee</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4441">#4441</a>
from seleniumbase/click-and-hold-with-cdp</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/dc07cb87d21ca6991e1e156f6b60db2beb661039"><code>dc07cb8</code></a>
Version 4.51.7</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7775f1db77594bd1642714de013d999e49c36e5c"><code>7775f1d</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f932c2d874c000d0149f2754a32bc955cfd71aa7"><code>f932c2d</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e667ad0ff5e19c8f85f7b7f42ba9f672a63639e3"><code>e667ad0</code></a>
Adjust timings and refactor</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6316b0aa95c947fc4f974662212f3cf77d1f829e"><code>6316b0a</code></a>
Add a CDP-based <code>click_and_hold()</code> method</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.6...v4.51.7">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.10 to 0.4.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.11</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-25.</p>
<h3>Highlights</h3>
<ul>
<li>
<p>This release adds two new builtin hooks, <code>deny-pattern</code>
and <code>require-pattern</code>,
as native alternatives for <code>pygrep</code> use cases.
<code>deny-pattern</code> fails when a
configured pattern is found, while <code>require-pattern</code> ensures
every selected
file contains a match. By matching natively without spawning a Python
subprocess, they run over 4x faster than <code>pygrep</code> in
benchmarks. Note that
they use <a href="https://docs.rs/regex/latest/regex/#syntax">Rust
<code>regex</code> syntax</a>, which does
not support look-around features such as negative lookbehind.</p>
</li>
<li>
<p><code>prek run</code> now supports <code>--glob
&lt;PATTERN&gt;</code> to run hooks on tracked files
matching a glob. It can be repeated or combined with
<code>--files</code> and
<code>--directory</code>.</p>
</li>
<li>
<p>Hook priorities now support reusable aliases:</p>
<pre lang="toml"><code>[priorities]
checks = 10
<p>[[repos]]
repo = &quot;builtin&quot;
hooks = [
{ id = &quot;check-json&quot;, priority = &quot;checks&quot; },
{ id = &quot;check-yaml&quot;, priority = &quot;checks&quot; },
]
</code></pre></p>
<p>This makes parallel scheduling easier to read and maintain.</p>
</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>deny-pattern</code> and <code>require-pattern</code>
builtin hooks (<a
href="https://redirect.github.com/j178/prek/pull/2359">#2359</a>)</li>
<li>Support <code>--glob</code> patterns in <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/pull/2381">#2381</a>)</li>
<li>Support reusable aliases for hook priorities (<a
href="https://redirect.github.com/j178/prek/pull/2331">#2331</a>)</li>
<li>Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2390">#2390</a>)</li>
<li>Improve user-facing warnings and errors (<a
href="https://redirect.github.com/j178/prek/pull/2380">#2380</a>)</li>
<li>Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/pull/2394">#2394</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/pull/2384">#2384</a>)</li>
<li>Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/pull/2391">#2391</a>)</li>
</ul>
<h3>Bug fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.11</h2>
<p>Released on 2026-07-25.</p>
<h3>Highlights</h3>
<ul>
<li>
<p>This release adds two new builtin hooks, <code>deny-pattern</code>
and <code>require-pattern</code>,
as native alternatives for <code>pygrep</code> use cases.
<code>deny-pattern</code> fails when a
configured pattern is found, while <code>require-pattern</code> ensures
every selected
file contains a match. By matching natively without spawning a Python
subprocess, they run over 4x faster than <code>pygrep</code> in
benchmarks. Note that
they use
<a href="https://docs.rs/regex/latest/regex/#syntax">Rust
<code>regex</code> syntax</a>, which does
not support look-around features such as negative lookbehind.</p>
</li>
<li>
<p><code>prek run</code> now supports <code>--glob
&lt;PATTERN&gt;</code> to run hooks on tracked files
matching a glob. It can be repeated or combined with
<code>--files</code> and
<code>--directory</code>.</p>
</li>
<li>
<p>Hook priorities now support reusable aliases:</p>
<pre lang="toml"><code>[priorities]
checks = 10
<p>[[repos]]
repo = &quot;builtin&quot;
hooks = [
{ id = &quot;check-json&quot;, priority = &quot;checks&quot; },
{ id = &quot;check-yaml&quot;, priority = &quot;checks&quot; },
]
</code></pre></p>
<p>This makes parallel scheduling easier to read and maintain.</p>
</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>deny-pattern</code> and <code>require-pattern</code>
builtin hooks (<a
href="https://redirect.github.com/j178/prek/pull/2359">#2359</a>)</li>
<li>Support <code>--glob</code> patterns in <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/pull/2381">#2381</a>)</li>
<li>Support reusable aliases for hook priorities (<a
href="https://redirect.github.com/j178/prek/pull/2331">#2331</a>)</li>
<li>Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2390">#2390</a>)</li>
<li>Improve user-facing warnings and errors (<a
href="https://redirect.github.com/j178/prek/pull/2380">#2380</a>)</li>
<li>Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/pull/2394">#2394</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/pull/2384">#2384</a>)</li>
<li>Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/pull/2391">#2391</a>)</li>
</ul>
<h3>Bug fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/92ba6c8c21e7acf5ce056b7c9b8dcba7325c3f5a"><code>92ba6c8</code></a>
Bump version to 0.4.11 (<a
href="https://redirect.github.com/j178/prek/issues/2402">#2402</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f575e428961414bc079060061bc570b71e553942"><code>f575e42</code></a>
Bump quinn-proto from 0.11.14 to 0.11.16 (<a
href="https://redirect.github.com/j178/prek/issues/2401">#2401</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c0ed56d92af1530e0acc98da2a8544bcf1dd01e7"><code>c0ed56d</code></a>
Preserve system download policy when applying metadata (<a
href="https://redirect.github.com/j178/prek/issues/2395">#2395</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3b8b5c53ea8ce674112e22f9f84addf3637ca9e0"><code>3b8b5c5</code></a>
Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/issues/2394">#2394</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ff11cbb2d30478d9b2607dd1886cf90e33979365"><code>ff11cbb</code></a>
Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/issues/2390">#2390</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c7dfc32c27f74ee04f9a4dc47b842fbb3e417631"><code>c7dfc32</code></a>
Match identify tags across filename parts (<a
href="https://redirect.github.com/j178/prek/issues/2399">#2399</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/928dc5cf3b7c7486664d6a7e34ce8d89a603d7f1"><code>928dc5c</code></a>
Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/issues/2391">#2391</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6c898499d8b7741f7e6b60cc42b195660e6d1afa"><code>6c89849</code></a>
Honor filenames in builtin hook entry and args (<a
href="https://redirect.github.com/j178/prek/issues/2389">#2389</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/28bc3f013e0c97c39834f2f02a708355ed642462"><code>28bc3f0</code></a>
Add description for no-commit-to-branch (<a
href="https://redirect.github.com/j178/prek/issues/2388">#2388</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1d9adddb83df05770ea2a5562f141171be174d77"><code>1d9addd</code></a>
Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/issues/2384">#2384</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.10...v0.4.11">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 01:23:47 -04:00
CaliBrain a1367f431d Ship Prowlarr per-entry rows as opt-in, not the default (#1145)
#1140 fixed the guid-only dedup that hid results from filter-specific
indexer entries, but shipped the new behaviour on by default:
PROWLARR_COLLAPSE_DUPLICATES defaulted off, so every existing Prowlarr
user got extra rows for any release that two indexer entries both
returned, and the setting only let them opt back into what they already
had.

Default it on. The dedup key stays indexer-qualified, so the entries are
still distinct internally; collapse then merges them back to one row,
resolved by the Prowlarr priority rather than by query order as before.
The visible result set matches what users had prior to #1140, and anyone
who wants the per-entry rows (freeleech and the like) turns the setting
off.

Beyond the noisier list, the default mattered because split rows differ
only by indexer name while sharing a title, size and peer count. Two of
them have distinct source_ids, so the queue's duplicate guard does not
fire, and the second grab's find_existing() matches the first by
infohash and runs post-processing over the same download again,
delivering the book twice.

The search-side fallback in config.get(..., True) is flipped to agree
with the field default. In production the field default governs, since
the config cache is seeded from the registry and the fallback only
applies to an unregistered key. The source tests monkeypatch config.get
with a plain dict lookup, though, so the fallback is what they exercise:
leaving it False would have kept every default-behaviour test asserting
the opposite of what ships. A new test pins the two together.

The deduplication tests now opt out explicitly, since they assert the
split itself. test_collapse_off_by_default_keeps_both_rows becomes a
pair, one for the untouched setting collapsing to a single row and one
for opting out.

docs/environment-variables.md is regenerated rather than hand-edited. It
was already stale on main, so it also picks up RTORRENT_AUDIOBOOK_LABEL,
DIRECT_DOWNLOAD_LANGUAGE_FROM_PATH, and reworded IRC_SEARCH_BOT and
RTORRENT_LABEL text from earlier merges.

The rest is fallout from the ruff 0.16.0 bump in #1139, which enabled a
much larger default rule set and started formatting Python code blocks
in Markdown: _find_existing_alias_user() uses min() instead of
sorted()[0] (FURB192, currently failing Python Quality on main), and the
two READMEs get their code blocks reformatted.
2026-07-28 01:23:31 -04:00
Andrew Doeringanddelize a4086f5e06 Keep Prowlarr results from distinct indexer entries separate (#1140)
Results were deduplicated on `guid` alone. When one tracker is
configured in Prowlarr as several indexer entries differing only by a
server-side search filter, all of them return the same guid for the same
torrent, so every entry but the first was silently discarded. Freeleech
and other filter-specific releases became invisible, replaced by the
unfiltered entry's copy, and which copy survived depended on query
ordering rather than user intent.

Include the indexer id in the dedup key so the entries stay distinct.

Release.source_id is qualified the same way. It keys the release cache
and becomes the download task id, so rows sharing a guid would otherwise
collide and a grab would route through whichever entry cached last,
defeating the point of showing them separately. The handler's task
matcher still accepts a bare guid or infoUrl so tasks queued before this
change still resolve.

Ordering now follows the priority already configured in Prowlarr (1-50,
lower preferred) rather than a new setting, since users curate that
ranking there and filtered entries are typically ranked ahead of their
unfiltered counterparts. The enabled-indexer list is fetched once and
reused for the enrichment check, so this costs no extra round trip.
Releases carry extra.indexer_priority, and the sort dropdown gains an
"Indexer priority" entry, ascending, alongside the existing alphabetical
"Indexer" sort; SortOption grew a default_direction for that, defaulting
to desc so "Peers" is unchanged.

PROWLARR_COLLAPSE_DUPLICATES (default off) optionally collapses a
release back to one row, resolved by the same Prowlarr priority. Left
off, every entry that carried a release keeps its own row, which is what
makes filtered results visible again.

Identity handling is defensive about partial payloads: a result that
cannot be identified is never dropped or merged, and collapse only
merges on a strong identifier (guid/downloadUrl/magnetUrl/infoUrl)
because merging on title alone would discard genuinely different
releases that share a name.

Fixes #1137

Co-authored-by: delize <4028612+delize@users.noreply.github.com>
2026-07-28 01:06:39 -04:00
Adam Vigneaux 0d02c6db47 Add qBittorrent API key authentication (#1143)
[qBittorrent

5.2.0](https://www.qbittorrent.org/news#sun-may-03rd-2026---qbittorrent-v5.2.0-release)
(May 2026) added support for API key-based authentication in addition to
the existing username/password-based authentication.

This commit adds support for qBittorrent API key authentication to
Shelfmark, configurable via environment variable or settings UI. If an
API key is set at the same time as the username/password, API key will
be preferred for authentication.

Requires `qbittorrent-api` 2026.5.3, the version that added the
`api_key` argument, or newer. `403 Forbidden` responses are not retried
with API key authentication because a retry has no chance of succeeding.

Tested end-to-end with my live qBittorrent 5.2.3 instance (WebAPI
v2.15.1).

<img width="785" height="616" alt="image"
src="https://github.com/user-attachments/assets/8064e10e-9a7f-49f0-804e-4c441d23a1fc"
/>
2026-07-28 00:54:19 -04:00
dependabot[bot] 7c457ff83e Bump the python-deps group with 4 updates (#1139)
Bumps the python-deps group with 4 updates:
[gevent](https://github.com/gevent/gevent),
[rarfile](https://github.com/markokr/rarfile),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[ruff](https://github.com/astral-sh/ruff).

Updates `gevent` from 26.5.0 to 26.7.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/gevent/gevent/commit/1ae8449b77daeec72ef4247474f1888209a89c44"><code>1ae8449</code></a>
Preparing release 26.7.0</li>
<li><a
href="https://github.com/gevent/gevent/commit/af4fad4d0c9f005c1f875483ee72fcdac3b4fd95"><code>af4fad4</code></a>
Add note about change in binary wheel building.</li>
<li><a
href="https://github.com/gevent/gevent/commit/894a6e1a30ac1f81207d03a7d2e893126b8cd238"><code>894a6e1</code></a>
gevent/resolver/_addresses.py: Apply suggestion from <a
href="https://github.com/koteshyelamati"><code>@​koteshyelamati</code></a>
and move...</li>
<li><a
href="https://github.com/gevent/gevent/commit/4bbfae89de752f1032e76be0977bc9b83df0fa83"><code>4bbfae8</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2190">#2190</a>
from gevent/os-close-no-init-hub</li>
<li><a
href="https://github.com/gevent/gevent/commit/fbc0ca7ab234480165d7db008f140ed6efaa0f69"><code>fbc0ca7</code></a>
Blanket skip two SSL tests that are highly environment sensitive.</li>
<li><a
href="https://github.com/gevent/gevent/commit/bef4cdd10002b1d9cc3c855ac5bfbeab27999e3f"><code>bef4cdd</code></a>
Disable 3.15 on windows entirely for now; everything is crashing and I'm
pret...</li>
<li><a
href="https://github.com/gevent/gevent/commit/95c5b1e102f32530933b6b882687ce9242293925"><code>95c5b1e</code></a>
Attempt some CFFI-related workarounds.</li>
<li><a
href="https://github.com/gevent/gevent/commit/2b754a55f9555d7caca680935ec600a99c517059"><code>2b754a5</code></a>
cython won't build on windows, must stick to precompiled version.
Debugging a...</li>
<li><a
href="https://github.com/gevent/gevent/commit/ebcebb0fb426ed39b8a9724e376444c222a3d5b5"><code>ebcebb0</code></a>
Track down why 3.15 was initting the hub.</li>
<li><a
href="https://github.com/gevent/gevent/commit/dcf4eae4b36046d456c685efd95bc50cc085084e"><code>dcf4eae</code></a>
Merge pull request <a
href="https://redirect.github.com/gevent/gevent/issues/2189">#2189</a>
from ddorian/fix-shutdown-atexit-order</li>
<li>Additional commits viewable in <a
href="https://github.com/gevent/gevent/compare/26.5.0...26.7.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `rarfile` from 4.3 to 4.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/markokr/rarfile/releases">rarfile's
releases</a>.</em></p>
<blockquote>
<h2>rarfile v4.4</h2>
<p>Security fixes:</p>
<ul>
<li>Skip CRC check for some old subblocks. Previously <!-- raw HTML
omitted -->rarfile<!-- raw HTML omitted --> tried to calculate header
CRC by reading data payload for those, but that could cause excessive
allocations.</li>
</ul>
<p>Fixes:</p>
<ul>
<li>RAR5: Reattempt passwords after trying wrong password when header
encryption is used. [<a
href="https://redirect.github.com/markokr/rarfile/pull/131">#131</a>]</li>
<li>Restore fd position in file type detection functions. [<a
href="https://redirect.github.com/markokr/rarfile/pull/121">#121</a>]</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/markokr/rarfile/blob/master/doc/news.rst">rarfile's
changelog</a>.</em></p>
<blockquote>
<h2>Version 4.4 (2026-07-22)</h2>
<p>Security fixes:</p>
<ul>
<li>Skip CRC check for some old subblocks.  Previously
<code>rarfile</code> tried to calculate header CRC by reading
data payload for those, but that could cause excessive
allocations.</li>
</ul>
<p>Fixes:</p>
<ul>
<li>
<p>RAR5: Reattempt passwords after trying wrong password
when header encryption is used.
[<code>[#131](https://github.com/markokr/rarfile/issues/131)
&lt;https://github.com/markokr/rarfile/pull/131&gt;</code>_]</p>
</li>
<li>
<p>Restore fd position in file type detection functions.
[<code>[#121](https://github.com/markokr/rarfile/issues/121)
&lt;https://github.com/markokr/rarfile/pull/121&gt;</code>_]</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/markokr/rarfile/commit/d106d2031e702bb187c746d9035362f0bd23a33c"><code>d106d20</code></a>
Refresh news.rst</li>
<li><a
href="https://github.com/markokr/rarfile/commit/8ab9f71684bddc60ba4631e4468727924b9816c1"><code>8ab9f71</code></a>
ci: restore CI on push</li>
<li><a
href="https://github.com/markokr/rarfile/commit/1b3db8971650236e7ddc8c80e705cf58511d2930"><code>1b3db89</code></a>
v4.4</li>
<li><a
href="https://github.com/markokr/rarfile/commit/c94c9691e3ba59816f0c0dc12fd4078d4639b7ad"><code>c94c969</code></a>
Skip CRC check for some old subblocks.</li>
<li><a
href="https://github.com/markokr/rarfile/commit/e2c0d6ef2b4b35ea20e10a76613b2aa79cdf784e"><code>e2c0d6e</code></a>
Reattempt passwords</li>
<li><a
href="https://github.com/markokr/rarfile/commit/cc6368edc1ccbdb80b619d9e962b8199b00dfed9"><code>cc6368e</code></a>
build(deps): bump tox from 4.53.1 to 4.56.1</li>
<li><a
href="https://github.com/markokr/rarfile/commit/0b3d4536a1012e1538157bc00638ebf68df3786a"><code>0b3d453</code></a>
dependabot: drop unnecessary etc</li>
<li><a
href="https://github.com/markokr/rarfile/commit/edb967cd0f531f8f49ad5106b36a028ead30fde6"><code>edb967c</code></a>
build(deps): bump actions/checkout from 4 to 7</li>
<li><a
href="https://github.com/markokr/rarfile/commit/79bd2e447823c18b8a99eeff9acea05cfbee9cd1"><code>79bd2e4</code></a>
build(deps): bump twine from 5.1.1 to 6.2.0</li>
<li><a
href="https://github.com/markokr/rarfile/commit/1c0c6a6b27c36c2a0306e33db71603950b43ee22"><code>1c0c6a6</code></a>
build(deps): bump actions/upload-artifact from 4 to 7</li>
<li>Additional commits viewable in <a
href="https://github.com/markokr/rarfile/compare/v4.3...v4.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.3 to 4.51.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.6 - CDP Mode: Patch 124</h2>
<h2>CDP Mode: Patch 124</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7d79aa82eb7575706799716403088b7db2604100">Make
CDP Mode stealthier</a>
--&gt; Improve fingerprint on actions and add randomization</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f98dd28d35df3e8e25f98fa2f1fc2c7a420d7287">Sync
up BaseCase and sb_cdp methods</a>
--&gt; (For <code>clear()</code> &amp; <code>clear_input()</code>, which
are the same)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ea68a2eca2b3142f941d9da8537c2cc0e917afaf">Refresh
Python dependencies</a>
--&gt; (Includes <code>certifi</code> and a few optional
dependencies)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e5bbe21beb6817e9bb43ce23ba899e62dc6b0723">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 124 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4439">seleniumbase/SeleniumBase#4439</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.5...v4.51.6">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.5...v4.51.6</a></p>
<h2>4.51.5 - CDP Mode: Patch 123</h2>
<h2>CDP Mode: Patch 123</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a6e951c73c3e2b2ce1082671813692cba2d61a44">Make
CDP Mode super stealthy</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e08ed3a3baeba129ad2ecc155b5c9c26df8a1ea1">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1feb0db4187160e290595dfc6f05653c0f0fcc1e">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 123 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4438">seleniumbase/SeleniumBase#4438</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.4...v4.51.5">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.4...v4.51.5</a></p>
<h2>4.51.4 - CDP Mode: Patch 122</h2>
<h2>CDP Mode: Patch 122</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ae9df3ea9f6340474e8aacf2e7b952342ec53088">Update
CDP Mode</a>
--&gt; For a stealthier fingerprint</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a8b84ff9f8051a52ae72e81dfb6aab3d62458459">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6b6599ac6689c7efe4e5e784814c7d4151de0652">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 122 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4435">seleniumbase/SeleniumBase#4435</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.3...v4.51.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.3...v4.51.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/74c0594ed79332667a1792cf01e28cc34135f57c"><code>74c0594</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4439">#4439</a>
from seleniumbase/cdp-mode-patch-124</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cee06e0934db22fb144019e18b8f3e933c431eb8"><code>cee06e0</code></a>
Version 4.51.6</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e5bbe21beb6817e9bb43ce23ba899e62dc6b0723"><code>e5bbe21</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ea68a2eca2b3142f941d9da8537c2cc0e917afaf"><code>ea68a2e</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f98dd28d35df3e8e25f98fa2f1fc2c7a420d7287"><code>f98dd28</code></a>
Sync up BaseCase and sb_cdp methods</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7d79aa82eb7575706799716403088b7db2604100"><code>7d79aa8</code></a>
Make CDP Mode stealthier</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0dda01d2b0690e77e2a5884c1ab7000cf33a8efb"><code>0dda01d</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4438">#4438</a>
from seleniumbase/cdp-mode-patch-123</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2897f0a992e0cffa6d0af45ac8d2b85416cac26b"><code>2897f0a</code></a>
Version 4.51.5</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e08ed3a3baeba129ad2ecc155b5c9c26df8a1ea1"><code>e08ed3a</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1feb0db4187160e290595dfc6f05653c0f0fcc1e"><code>1feb0db</code></a>
Update CDP Mode examples</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.3...v4.51.6">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.22 to 0.16.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.0</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-23.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.16.0">blog
post</a> for a migration guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now enables a much larger set of rules by default (413, up from
59). See the blog post for more details and the new <a
href="https://docs.astral.sh/ruff/default-rules/">Default Rules</a> page
for a full listing of the enabled rules.</p>
</li>
<li>
<p>Ruff can now format Python code blocks in Markdown files and will do
this by default. See the <a
href="https://docs.astral.sh/ruff/formatter/#markdown-code-formatting">documentation</a>
for more details.</p>
</li>
<li>
<p>Ruff now supports <code>ruff: ignore</code> comments at the ends of
lines, like <code>noqa</code> comments, or on the line preceding a
diagnostic. For example, these both suppress an <a
href="https://docs.astral.sh/ruff/rules/unused-import/"><code>unused-import</code></a>
(<code>F401</code>) diagnostic:</p>
<pre lang="py"><code>import math  # ruff: ignore[F401]
<h1>ruff: ignore[F401]</h1>
<p>import os
</code></pre></p>
</li>
<li>
<p>Fixes are now shown in <code>check</code> and <code>format
--check</code> output:</p>
<pre lang="console"><code>❯ ruff format --check .
unformatted: File would be reformatted
 --&gt; try.md:1:1
  |
1 | ```python
  - import   math
2 + import math
3 | ```
  |
<p>1 file would be reformatted
</code></pre></p>
<p>This example also shows off the Markdown formatting.</p>
</li>
<li>
<p><code>format --check</code> now supports the same output formats as
the linter, including the <code>github</code> and <code>gitlab</code>
outputs for rendering annotations in CI:</p>
<pre lang="console"><code>❯ ruff format --check --output-format github .
::error title=ruff
(unformatted),file=try.md,line=2,col=8,endLine=2,endColumn=10::try.md:2:8:
unformatted: File would be reformatted
</code></pre>
<p>See the CLI help or <a
href="https://docs.astral.sh/ruff/settings/#output-format">documentation</a>
for the full list of supported formats.</p>
</li>
<li>
<p>The <code>filename</code>, <code>location</code>,
<code>end_location</code>, <code>fix.edits[].location</code>, and
<code>fix.edits[].end_location</code> fields in the JSON output format
may now be <code>null</code> rather than defaulting to the empty string
and row 1, column 1, respectively.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.0</h2>
<p>Released on 2026-07-23.</p>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.16.0">blog
post</a> for a migration
guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<ul>
<li>
<p>Ruff now enables a much larger set of rules by default (413, up from
59). See the blog post for
more details and the new <a
href="https://docs.astral.sh/ruff/default-rules/">Default Rules</a> page
for a
full listing of the enabled rules.</p>
</li>
<li>
<p>Ruff can now format Python code blocks in Markdown files and will do
this by default. See the
<a
href="https://docs.astral.sh/ruff/formatter/#markdown-code-formatting">documentation</a>
for more details.</p>
</li>
<li>
<p>Ruff now supports <code>ruff: ignore</code> comments at the ends of
lines, like <code>noqa</code> comments, or on the line preceding a
diagnostic. For example, these both suppress an <a
href="https://docs.astral.sh/ruff/rules/unused-import/"><code>unused-import</code></a>
(<code>F401</code>) diagnostic:</p>
<pre lang="py"><code>import math  # ruff: ignore[F401]
<h1>ruff: ignore[F401]</h1>
<p>import os
</code></pre></p>
</li>
<li>
<p>Fixes are now shown in <code>check</code> and <code>format
--check</code> output:</p>
<pre lang="console"><code>❯ ruff format --check .
unformatted: File would be reformatted
 --&gt; try.md:1:1
  |
1 | ```python
  - import   math
2 + import math
3 | ```
  |
<p>1 file would be reformatted
</code></pre></p>
<p>This example also shows off the Markdown formatting.</p>
</li>
<li>
<p><code>format --check</code> now supports the same output formats as
the linter, including the <code>github</code> and
<code>gitlab</code> outputs for rendering annotations in CI:</p>
<pre lang="console"><code>❯ ruff format --check --output-format github .
::error title=ruff
(unformatted),file=try.md,line=2,col=8,endLine=2,endColumn=10::try.md:2:8:
unformatted: File would be reformatted
</code></pre>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/a2635fd8f39e1d34ce8074cb486809426148f3e9"><code>a2635fd</code></a>
Bump 0.16.0 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27136">#27136</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/34334491652f8ceca5246d15c5c5afe0d6bc77ae"><code>3433449</code></a>
[ty] Reuse full call diagnostics for implicit setter calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27115">#27115</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/22400709220931375e072ad5d7460b9fc781af78"><code>2240070</code></a>
Reflect <code>ruff: ignore</code> and <code>--add-ignore</code>
stabilization in documentation (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27">#27</a>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/17ef71142c52230b923dad46ee5554140fc3fd2e"><code>17ef711</code></a>
Stabilize <code>--add-ignore</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27125">#27125</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ef912bbbe466856aa4aac10ad2a8856eb3d5aef3"><code>ef912bb</code></a>
Add newly stabilized rules to defaults (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27055">#27055</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b30f04023281b46f12011f13ce6b45c247e0d2e3"><code>b30f040</code></a>
Stabilize new default rules (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27035">#27035</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/bcd70c5f10ea97ed52a785d70e7f33b83b7c697a"><code>bcd70c5</code></a>
Exclude Markdown files from <code>format-dev</code> runs (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27052">#27052</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/87e51e2cbbaed376fc13dead40fd772361fa07c0"><code>87e51e2</code></a>
Fix <code>format --check</code> spans for syntax errors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/27045">#27045</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/afe2723a348364ac7f4b9abd76fc67779490c05e"><code>afe2723</code></a>
[<code>flake8-gettext</code>] Stabilize qualified-name and built-in
binding resolution (...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/a9702d8928344f77a41dbe535f655a69fb04e2df"><code>a9702d8</code></a>
[<code>flake8-bandit</code>] Stabilize string literal binding resolution
(<code>S310</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26944">#26944</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.22...0.16.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-27 12:26:06 -04:00
dependabot[bot] 00f3fa565c Bump typescript from 6.0.3 to 7.0.2 in /src/frontend (#1133)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3
to 7.0.2.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/microsoft/TypeScript/commits">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~microsoft1es">microsoft1es</a>, a new
releaser for typescript since your current version.</p>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 18:38:31 -04:00
CaliBrain 7fdaf3f67d Add Audiobook support to IRC (#1136) 2026-07-24 18:34:12 -04:00
dependabot[bot] e9f3b9a3ad Bump the npm-deps group in /src/frontend with 7 updates (#1132)
Bumps the npm-deps group in /src/frontend with 7 updates:

| Package | From | To |
| --- | --- | --- |
|
[@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)
| `4.3.2` | `4.3.3` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.26.0` | `6.27.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.58.0` | `0.59.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.73.0` | `1.74.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.24.0`
| `0.25.0` |
|
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
| `4.3.2` | `4.3.3` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.1.4` | `8.1.5` |

Updates `@tailwindcss/vite` from 4.3.2 to 4.3.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">@​tailwindcss/vite's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.3</h2>
<h3>Fixed</h3>
<ul>
<li>Support <code>--watch --poll[=ms]</code> in
<code>@tailwindcss/cli</code> when filesystem events are unreliable or
unavailable (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20297">#20297</a>)</li>
<li>Canonicalization: match arbitrary hex colors against theme colors
case-insensitively (e.g. <code>bg-[#fff]</code> and
<code>bg-[#FFF]</code> → <code>bg-white</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20298">#20298</a>)</li>
<li>Prevent Preflight from overriding Firefox's native
<code>iframe:focus-visible</code> outline styles (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20292">#20292</a>)</li>
<li>Ensure <code>theme('colors.foo')</code> in JS plugins resolves
correctly when both <code>--color-foo</code> and
<code>--color-foo-bar</code> exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20299">#20299</a>)</li>
<li>Ensure fractional opacity modifiers work with named shadow sizes
like <code>shadow-sm/12.5</code>, <code>text-shadow-sm/12.5</code>,
<code>drop-shadow-sm/12.5</code>, and <code>inset-shadow-sm/12.5</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20302">#20302</a>)</li>
<li>Parse selectors like <code>[data-foo]div</code> as two selectors
instead of one (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20303">#20303</a>)</li>
<li>Ensure <code>@tailwindcss/postcss</code> rebuilds when a
preprocessor like Sass changes the input CSS without changing the input
file on disk (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20310">#20310</a>)</li>
<li>Ensure CSS nesting is handled even when Lightning CSS isn't run,
such as in <code>@tailwindcss/browser</code> and Tailwind Play (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20124">#20124</a>)</li>
<li>Prevent achromatic theme colors from shifting hue when mixed in
polar color spaces like <code>oklch</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20314">#20314</a>)</li>
<li>Ensure <code>--spacing(0)</code> is optimized to <code>0px</code>
instead of <code>0</code> so it remains a <code>&lt;length&gt;</code>
when used in <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20319">#20319</a>)</li>
<li>Load <code>@parcel/watcher</code> only when needed in
<code>@tailwindcss/cli --watch</code> mode, so one-off builds and
<code>--watch --poll</code> work when <code>@parcel/watcher</code> can't
be loaded (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20325">#20325</a>)</li>
<li>Use explicit platform fonts instead of <code>system-ui</code> and
<code>ui-sans-serif</code> so CJK text respects the page's
<code>lang</code> attribute on Windows (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20318">#20318</a>)</li>
<li>Prevent <code>@tailwindcss/upgrade</code> from rewriting ignored
files when run from a subdirectory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20329">#20329</a>)</li>
<li>Ensure earlier <code>@source</code> rules pointing to nested files
are scanned when later <code>@source</code> rules point to files in
parent folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20335">#20335</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from triggering full page
reloads when scanned files are processed by Vite but haven't been loaded
as modules yet (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20336">#20336</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">@​tailwindcss/vite's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.3] - 2026-07-16</h2>
<h3>Fixed</h3>
<ul>
<li>Support <code>--watch --poll[=ms]</code> in
<code>@tailwindcss/cli</code> when filesystem events are unreliable or
unavailable (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20297">#20297</a>)</li>
<li>Canonicalization: match arbitrary hex colors against theme colors
case-insensitively (e.g. <code>bg-[#fff]</code> and
<code>bg-[#FFF]</code> → <code>bg-white</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20298">#20298</a>)</li>
<li>Prevent Preflight from overriding Firefox's native
<code>iframe:focus-visible</code> outline styles (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20292">#20292</a>)</li>
<li>Ensure <code>theme('colors.foo')</code> in JS plugins resolves
correctly when both <code>--color-foo</code> and
<code>--color-foo-bar</code> exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20299">#20299</a>)</li>
<li>Ensure fractional opacity modifiers work with named shadow sizes
like <code>shadow-sm/12.5</code>, <code>text-shadow-sm/12.5</code>,
<code>drop-shadow-sm/12.5</code>, and <code>inset-shadow-sm/12.5</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20302">#20302</a>)</li>
<li>Parse selectors like <code>[data-foo]div</code> as two selectors
instead of one (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20303">#20303</a>)</li>
<li>Ensure <code>@tailwindcss/postcss</code> rebuilds when a
preprocessor like Sass changes the input CSS without changing the input
file on disk (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20310">#20310</a>)</li>
<li>Ensure CSS nesting is handled even when Lightning CSS isn't run,
such as in <code>@tailwindcss/browser</code> and Tailwind Play (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20124">#20124</a>)</li>
<li>Prevent achromatic theme colors from shifting hue when mixed in
polar color spaces like <code>oklch</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20314">#20314</a>)</li>
<li>Ensure <code>--spacing(0)</code> is optimized to <code>0px</code>
instead of <code>0</code> so it remains a <code>&lt;length&gt;</code>
when used in <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20319">#20319</a>)</li>
<li>Load <code>@parcel/watcher</code> only when needed in
<code>@tailwindcss/cli --watch</code> mode, so one-off builds and
<code>--watch --poll</code> work when <code>@parcel/watcher</code> can't
be loaded (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20325">#20325</a>)</li>
<li>Use explicit platform fonts instead of <code>system-ui</code> and
<code>ui-sans-serif</code> so CJK text respects the page's
<code>lang</code> attribute on Windows (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20318">#20318</a>)</li>
<li>Prevent <code>@tailwindcss/upgrade</code> from rewriting ignored
files when run from a subdirectory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20329">#20329</a>)</li>
<li>Ensure earlier <code>@source</code> rules pointing to nested files
are scanned when later <code>@source</code> rules point to files in
parent folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20335">#20335</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from triggering full page
reloads when scanned files are processed by Vite but haven't been loaded
as modules yet (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20336">#20336</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c2b24dd15fed1c59dd521bd86082f520c9f5ad0d"><code>c2b24dd</code></a>
4.3.3 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/20334">#20334</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/bdcd7087b332d263353d46ed366b7b08040ded7a"><code>bdcd708</code></a>
Don't trigger a full page reload for scanned files that Vite processes
as mod...</li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.26.0 to 6.27.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.27.0</h2>
<ul>
<li>Add Temporal plugin (98191a04aad0572bead191b101bfecef75067b0c)</li>
<li>Handle -d alias for react-email dir argument
(53d1fec3213db8d6a84dfa7a82050b122782e065)</li>
<li>Expand pnpm script references with forwarded arguments
(33e9799df39450033061b9c4c07daf22f5d15721)</li>
<li>Treat path-shaped script tokens as file references, extend known
global binaries (d9508c282ab81351beda4b2f859435b49f142c51)</li>
<li>Mark tsdown neverBundle dependencies as referenced
(5fd863ba12e68842f91ab1a94e7e30d1e571da92)</li>
<li>Support TanStack Start in tanstack-router plugin
(bd63cd8af88dac03a98aa17f1add322f7bdf4a94)</li>
<li>Mark vite ssr.external dependencies as referenced
(91de938032062cb667bced0eadef9e67d1e20b1f)</li>
<li>Expand bun, npm, and yarn script references with forwarded arguments
(b5a31767a83e2cec3fb20c3b146d94c0412a4fd6)</li>
<li>Add Latitude as sponsor
(42676759cad5fb10ac96fd7c0457037e906f4b68)</li>
<li>Regenerate plugin list in docs
(1d2cdffb4d4151f848c44e066eff43e9efbf44fe)</li>
<li>Support Vue 2 template auto-imports (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1881">#1881</a>)
(2157f3913f77216d268b2255899b6fc58609f9bb)</li>
<li>Ignore block-commented stylesheet imports (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1880">#1880</a>,
close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1882">#1882</a>)
(a627f53221547d5397d70722fcc2fd723889e579)</li>
<li>Support TypeScript 5.0 narrowing for ssr.external
(989292f79b9d19028bfc7ba988b74ba691041a45)</li>
<li>Resolve local binaries from bun run
(5e9a7f0286e2c2175bb299c514cc7b67a7cf24f1)</li>
<li>Support Vitest inline project config extensions
(f682327f6181f44e3924715efa7404aa39e532f0)</li>
<li>Resolve package names from aliased node_modules paths
(c273d5fbc1b0d3eaf27b38c3f31d3a2a4b6b184a)</li>
<li>Support Tailwind CSS URL imports
(57a4770447cc4c8f9ea4ffb9171c0c92eed4f255)</li>
<li>Resolve unbuilt workspace package exports (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1877">#1877</a>)
(1b0a2c0ee784db165c7f92fe10397a6cb513c1cf)</li>
<li>Skip unresolved imports of gitignored generated files
(605c9049f73838beb1c6fee83c6a5421ae1a6d07)</li>
<li>Attribute imports of aliased packages to the declared dependency
(d05e775c9a3a5676dc9eadcc1093f7d9983efd06)</li>
<li>Flag unresolvable imports of transitive peer deps as unlisted
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1883">#1883</a>)
(18f0bff4ea683837f75ca744d3fbde52df49b297)</li>
<li>Don't count ambient module declarations in script files as imports
(e52aecfd7c022cbe72b1c11dde3f4968579ac409)</li>
<li>Update rolldown snapshot
(a63e92788239062682603a5727ede371db7845c8)</li>
<li>Remove obsolete workarounds from ecosystem tests
(a521cf790d726c18e644e2e316cdc09eb654f607)</li>
<li>Handle snapshotSerializers in Vitest plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1884">#1884</a>)
(b597de951f6f0e897afdbbbb8a7d0c06c8d2437d)</li>
<li>Set the stage (c059c2be5803609924b852c2bf0cd90906a6a831)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/e463b61a1fbbc53c559eb08c92aa751b5c838bc0"><code>e463b61</code></a>
Release knip@6.27.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b597de951f6f0e897afdbbbb8a7d0c06c8d2437d"><code>b597de9</code></a>
Handle snapshotSerializers in Vitest plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1884">#1884</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e52aecfd7c022cbe72b1c11dde3f4968579ac409"><code>e52aecf</code></a>
Don't count ambient module declarations in script files as imports</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/18f0bff4ea683837f75ca744d3fbde52df49b297"><code>18f0bff</code></a>
Flag unresolvable imports of transitive peer deps as unlisted (resolve
<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1883">#1883</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/d05e775c9a3a5676dc9eadcc1093f7d9983efd06"><code>d05e775</code></a>
Attribute imports of aliased packages to the declared dependency</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/605c9049f73838beb1c6fee83c6a5421ae1a6d07"><code>605c904</code></a>
Skip unresolved imports of gitignored generated files</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/1b0a2c0ee784db165c7f92fe10397a6cb513c1cf"><code>1b0a2c0</code></a>
Resolve unbuilt workspace package exports (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1877">#1877</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/57a4770447cc4c8f9ea4ffb9171c0c92eed4f255"><code>57a4770</code></a>
Support Tailwind CSS URL imports</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c273d5fbc1b0d3eaf27b38c3f31d3a2a4b6b184a"><code>c273d5f</code></a>
Resolve package names from aliased node_modules paths</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f682327f6181f44e3924715efa7404aa39e532f0"><code>f682327</code></a>
Support Vitest inline project config extensions</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.27.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.58.0 to 0.59.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.59.0] - 2026-07-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>415fe1e oxfmt: Error on ignorePatterns that cannot match files
outside the config directory (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24286">#24286</a>)
(leaysgur)</li>
</ul>
<h2>[0.55.0] - 2026-06-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>9a2788b linter/unicorn: Implement <code>prefer-export-from</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22935">#22935</a>)
(AliceLanniste)</li>
</ul>
<h2>[0.54.0] - 2026-06-08</h2>
<h3>📚 Documentation</h3>
<ul>
<li>dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22965">#22965</a>)
(Boshen)</li>
<li>f88961a oxfmt: Annotate each config option with supported languages
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22953">#22953</a>)
(leaysgur)</li>
</ul>
<h2>[0.52.0] - 2026-05-26</h2>
<h3>🚀 Features</h3>
<ul>
<li>16b8058 oxfmt: Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22454">#22454</a>)
(leaysgur)</li>
</ul>
<h2>[0.50.0] - 2026-05-15</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>43b9978 formatter/sort_imports: Treat subpath imports as internal
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22440">#22440</a>)
(leaysgur)</li>
</ul>
<h2>[0.49.0] - 2026-05-11</h2>
<h3>🚀 Features</h3>
<ul>
<li>6e8e818 oxfmt: Experimental .svelte support (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21700">#21700</a>)
(leaysgur)</li>
</ul>
<h2>[0.45.0] - 2026-04-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>50c389b oxfmt: Support <code>.editorconfig</code>
<code>quote_type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20989">#20989</a>)
(leaysgur)</li>
</ul>
<h2>[0.44.0] - 2026-04-06</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>dd2df87 npm: Export package.json for oxlint and oxfmt (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20784">#20784</a>)
(kazuya kawaguchi)</li>
<li>4216380 oxfmt: Support <code>.editorconfig</code>
<code>tab_width</code> fallback (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20988">#20988</a>)
(leaysgur)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/2d4e8d20644e0e7446f0a381894b45ea339a0625"><code>2d4e8d2</code></a>
release(apps): oxlint v1.74.0 &amp;&amp; oxfmt v0.59.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24454">#24454</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/415fe1e7bb423cf05019c5e2c9a5705eebbc5447"><code>415fe1e</code></a>
fix(oxfmt): error on ignorePatterns that cannot match files outside the
confi...</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.59.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.73.0 to 1.74.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.74.0] - 2026-07-13</h2>
<h3>🚀 Features</h3>
<ul>
<li>0433a83 linter/eslint/no-inner-declarations: Add
<code>namespaces</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24044">#24044</a>)
(Boshen)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>8337835 linter: Error on <code>ignorePatterns</code> that cannot
match files aoutside the config directory (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24341">#24341</a>)
(leaysgur)</li>
<li>2ce5a33 linter: Resolve <code>ignorePatterns</code> relative to the
config dir (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24339">#24339</a>)
(leaysgur)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>7f80cac linter/vue/prop-name-casing: Precompile
<code>ignoreProps</code> regex pattern (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24413">#24413</a>)
(connorshea)</li>
<li>6272051 linter/typescript/no-require-imports: Compile allow patterns
once (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24417">#24417</a>)
(connorshea)</li>
<li>33805b9 linter/jsdoc/require-param: Compile checkTypesPattern regex
once (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24420">#24420</a>)
(connorshea)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/2d4e8d20644e0e7446f0a381894b45ea339a0625"><code>2d4e8d2</code></a>
release(apps): oxlint v1.74.0 &amp;&amp; oxfmt v0.59.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24454">#24454</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/7f80cac4fdfb9f488886267fe7a85ca2b73be85e"><code>7f80cac</code></a>
perf(linter/vue/prop-name-casing): precompile <code>ignoreProps</code>
regex pattern (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/2">#2</a>...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6272051fcd0b8ef168c8d9ec98df31cce85364b7"><code>6272051</code></a>
perf(linter/typescript/no-require-imports): compile allow patterns once
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24417">#24417</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/33805b96917e706adb02b373d53170297c238ce0"><code>33805b9</code></a>
perf(linter/jsdoc/require-param): compile checkTypesPattern regex once
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24420">#24420</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0433a8376aa3e51ee7a8371f897553cddcf4a663"><code>0433a83</code></a>
feat(linter/eslint/no-inner-declarations): add <code>namespaces</code>
option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24044">#24044</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/83378351e43ecd605c5a52cb1454cbed9421ac1a"><code>8337835</code></a>
fix(linter): error on <code>ignorePatterns</code> that cannot match
files aoutside the c...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/2ce5a33eccb96d1e297b54f4e7c1fc83f67e9ae2"><code>2ce5a33</code></a>
fix(linter): resolve <code>ignorePatterns</code> relative to the config
dir (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24339">#24339</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.74.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint-tsgolint` from 0.24.0 to 0.25.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v0.25.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update pnpm to v11.9.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1043">oxc-project/tsgolint#1043</a></li>
<li>perf(no-unnecessary-type-parameters): reuse AST-walk visitor closure
by <a href="https://github.com/connorshea"><code>@​connorshea</code></a>
in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1034">oxc-project/tsgolint#1034</a></li>
<li>perf(strict-void-return): reuse function-body walk visitor closure
by <a href="https://github.com/connorshea"><code>@​connorshea</code></a>
in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1033">oxc-project/tsgolint#1033</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1048">oxc-project/tsgolint#1048</a></li>
<li>docs: normalize README sponsor section by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1050">oxc-project/tsgolint#1050</a></li>
<li>chore: strip symbols from release binary by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1049">oxc-project/tsgolint#1049</a></li>
<li>chore: add -trimpath to release build by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1051">oxc-project/tsgolint#1051</a></li>
<li>chore(deps): update crate-ci/typos action to v1.48.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1052">oxc-project/tsgolint#1052</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1056">oxc-project/tsgolint#1056</a></li>
<li>chore(deps): update npm packages by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1057">oxc-project/tsgolint#1057</a></li>
<li>fix(no-deprecated): avoid contextual union property false positives
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1059">oxc-project/tsgolint#1059</a></li>
<li>fix(prefer-optional-chain): preserve negated optional guard by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1061">oxc-project/tsgolint#1061</a></li>
<li>perf(linter): gate reportNodeWithSuggestions on FixSuggestions by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1067">oxc-project/tsgolint#1067</a></li>
<li>fix(switch-exhaustiveness-check): honor default case comment
patterns by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1070">oxc-project/tsgolint#1070</a></li>
<li>perf(strict-void-return): skip type queries for never-callable
expressions by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1068">oxc-project/tsgolint#1068</a></li>
<li>perf(no-unsafe-argument): skip type queries for never-unsafe
arguments by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1066">oxc-project/tsgolint#1066</a></li>
<li>Revert &quot;perf(strict-void-return): skip type queries for
never-callable expressions&quot; by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1071">oxc-project/tsgolint#1071</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1072">oxc-project/tsgolint#1072</a></li>
<li>chore(deps): update dependency dprint-json to v0.23.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1080">oxc-project/tsgolint#1080</a></li>
<li>chore(deps): update taiki-e/install-action action to v2.83.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1082">oxc-project/tsgolint#1082</a></li>
<li>chore(deps): update gomod by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1081">oxc-project/tsgolint#1081</a></li>
<li>perf(no-unnecessary-type-arguments): skip signature resolution when
node has no type arguments by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1064">oxc-project/tsgolint#1064</a></li>
<li>refactor: miscellaneous code cleanup by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1077">oxc-project/tsgolint#1077</a></li>
<li>refactor: remove dead code from rules by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1079">oxc-project/tsgolint#1079</a></li>
<li>refactor: drop dead isFunction guards built on a bitwise ast.Kind
mask by <a
href="https://github.com/connorshea"><code>@​connorshea</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1078">oxc-project/tsgolint#1078</a></li>
<li>chore: update Node.js to 26.5.0 by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1087">oxc-project/tsgolint#1087</a></li>
<li>fix(no-unnecessary-type-assertion): avoid recursive unknown checks
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1086">oxc-project/tsgolint#1086</a></li>
<li>fix(no-unnecessary-type-assertions): generic array false positive by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1045">oxc-project/tsgolint#1045</a></li>
<li>fix(no-unnecessary-type-assertion): preserve generic write casts by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1089">oxc-project/tsgolint#1089</a></li>
<li>docs: update sponsor section by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1090">oxc-project/tsgolint#1090</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.24.0...v0.25.0">https://github.com/oxc-project/tsgolint/compare/v0.24.0...v0.25.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/1abf9a5ea5656daffd1fef16654626a37fdde794"><code>1abf9a5</code></a>
docs: update sponsor section</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/6ee7c11801c7afe054ca61cd35d76d84215621cb"><code>6ee7c11</code></a>
fix(no-unnecessary-type-assertion): preserve generic write casts (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1089">#1089</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/e23cc8351b8e3698903a8a73d267b4b326a96e20"><code>e23cc83</code></a>
fix(no-unnecessary-type-assertions): generic array false positive (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1045">#1045</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/c3269c01a0c894a31330e1b4c3bd4edc6eb7694b"><code>c3269c0</code></a>
fix(no-unnecessary-type-assertion): avoid recursive unknown checks (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1086">#1086</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/c214d5c65f2533dfbbce00680282d71a54180ad8"><code>c214d5c</code></a>
chore: update Node.js to 26.5.0 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1087">#1087</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/002b81870918f65cb73b54ce8899e245b3d51110"><code>002b818</code></a>
refactor: drop dead isFunction guards built on a bitwise ast.Kind mask
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1078">#1078</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/d6a1cb214548dc858b3b228ada8e0f2e2cd60935"><code>d6a1cb2</code></a>
refactor: remove dead code from rules (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1079">#1079</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/7823d5902901a02b004a01f3623fa42c22cb4f1f"><code>7823d59</code></a>
refactor: miscellaneous code cleanup (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1077">#1077</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/fcf43ff2e64ad2aaa818177d6189ffdce0ba1c2d"><code>fcf43ff</code></a>
perf(no-unnecessary-type-arguments): skip signature resolution when node
has ...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/68759141e030b9d053d97bbe6fe4faf7e52bd5e8"><code>6875914</code></a>
chore(deps): update gomod (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1081">#1081</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.24.0...v0.25.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `tailwindcss` from 4.3.2 to 4.3.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.3</h2>
<h3>Fixed</h3>
<ul>
<li>Support <code>--watch --poll[=ms]</code> in
<code>@tailwindcss/cli</code> when filesystem events are unreliable or
unavailable (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20297">#20297</a>)</li>
<li>Canonicalization: match arbitrary hex colors against theme colors
case-insensitively (e.g. <code>bg-[#fff]</code> and
<code>bg-[#FFF]</code> → <code>bg-white</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20298">#20298</a>)</li>
<li>Prevent Preflight from overriding Firefox's native
<code>iframe:focus-visible</code> outline styles (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20292">#20292</a>)</li>
<li>Ensure <code>theme('colors.foo')</code> in JS plugins resolves
correctly when both <code>--color-foo</code> and
<code>--color-foo-bar</code> exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20299">#20299</a>)</li>
<li>Ensure fractional opacity modifiers work with named shadow sizes
like <code>shadow-sm/12.5</code>, <code>text-shadow-sm/12.5</code>,
<code>drop-shadow-sm/12.5</code>, and <code>inset-shadow-sm/12.5</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20302">#20302</a>)</li>
<li>Parse selectors like <code>[data-foo]div</code> as two selectors
instead of one (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20303">#20303</a>)</li>
<li>Ensure <code>@tailwindcss/postcss</code> rebuilds when a
preprocessor like Sass changes the input CSS without changing the input
file on disk (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20310">#20310</a>)</li>
<li>Ensure CSS nesting is handled even when Lightning CSS isn't run,
such as in <code>@tailwindcss/browser</code> and Tailwind Play (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20124">#20124</a>)</li>
<li>Prevent achromatic theme colors from shifting hue when mixed in
polar color spaces like <code>oklch</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20314">#20314</a>)</li>
<li>Ensure <code>--spacing(0)</code> is optimized to <code>0px</code>
instead of <code>0</code> so it remains a <code>&lt;length&gt;</code>
when used in <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20319">#20319</a>)</li>
<li>Load <code>@parcel/watcher</code> only when needed in
<code>@tailwindcss/cli --watch</code> mode, so one-off builds and
<code>--watch --poll</code> work when <code>@parcel/watcher</code> can't
be loaded (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20325">#20325</a>)</li>
<li>Use explicit platform fonts instead of <code>system-ui</code> and
<code>ui-sans-serif</code> so CJK text respects the page's
<code>lang</code> attribute on Windows (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20318">#20318</a>)</li>
<li>Prevent <code>@tailwindcss/upgrade</code> from rewriting ignored
files when run from a subdirectory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20329">#20329</a>)</li>
<li>Ensure earlier <code>@source</code> rules pointing to nested files
are scanned when later <code>@source</code> rules point to files in
parent folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20335">#20335</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from triggering full page
reloads when scanned files are processed by Vite but haven't been loaded
as modules yet (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20336">#20336</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">tailwindcss's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.3] - 2026-07-16</h2>
<h3>Fixed</h3>
<ul>
<li>Support <code>--watch --poll[=ms]</code> in
<code>@tailwindcss/cli</code> when filesystem events are unreliable or
unavailable (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20297">#20297</a>)</li>
<li>Canonicalization: match arbitrary hex colors against theme colors
case-insensitively (e.g. <code>bg-[#fff]</code> and
<code>bg-[#FFF]</code> → <code>bg-white</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20298">#20298</a>)</li>
<li>Prevent Preflight from overriding Firefox's native
<code>iframe:focus-visible</code> outline styles (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20292">#20292</a>)</li>
<li>Ensure <code>theme('colors.foo')</code> in JS plugins resolves
correctly when both <code>--color-foo</code> and
<code>--color-foo-bar</code> exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20299">#20299</a>)</li>
<li>Ensure fractional opacity modifiers work with named shadow sizes
like <code>shadow-sm/12.5</code>, <code>text-shadow-sm/12.5</code>,
<code>drop-shadow-sm/12.5</code>, and <code>inset-shadow-sm/12.5</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20302">#20302</a>)</li>
<li>Parse selectors like <code>[data-foo]div</code> as two selectors
instead of one (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20303">#20303</a>)</li>
<li>Ensure <code>@tailwindcss/postcss</code> rebuilds when a
preprocessor like Sass changes the input CSS without changing the input
file on disk (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20310">#20310</a>)</li>
<li>Ensure CSS nesting is handled even when Lightning CSS isn't run,
such as in <code>@tailwindcss/browser</code> and Tailwind Play (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20124">#20124</a>)</li>
<li>Prevent achromatic theme colors from shifting hue when mixed in
polar color spaces like <code>oklch</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20314">#20314</a>)</li>
<li>Ensure <code>--spacing(0)</code> is optimized to <code>0px</code>
instead of <code>0</code> so it remains a <code>&lt;length&gt;</code>
when used in <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20319">#20319</a>)</li>
<li>Load <code>@parcel/watcher</code> only when needed in
<code>@tailwindcss/cli --watch</code> mode, so one-off builds and
<code>--watch --poll</code> work when <code>@parcel/watcher</code> can't
be loaded (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20325">#20325</a>)</li>
<li>Use explicit platform fonts instead of <code>system-ui</code> and
<code>ui-sans-serif</code> so CJK text respects the page's
<code>lang</code> attribute on Windows (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20318">#20318</a>)</li>
<li>Prevent <code>@tailwindcss/upgrade</code> from rewriting ignored
files when run from a subdirectory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20329">#20329</a>)</li>
<li>Ensure earlier <code>@source</code> rules pointing to nested files
are scanned when later <code>@source</code> rules point to files in
parent folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20335">#20335</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from triggering full page
reloads when scanned files are processed by Vite but haven't been loaded
as modules yet (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20336">#20336</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c2b24dd15fed1c59dd521bd86082f520c9f5ad0d"><code>c2b24dd</code></a>
4.3.3 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20334">#20334</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/e48c5e80473c25fe5a27fe267fbaf4f6512424a3"><code>e48c5e8</code></a>
Fix weird character rendering on Windows with Japanese locale (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20318">#20318</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/35a3e9c5159bea77af0d48f0c8849279211cc7e9"><code>35a3e9c</code></a>
Always produce <code>\&lt;length&gt;</code> value when optimizing
<code>--spacing(0)</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20319">#20319</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/4af47fbe942245fd05ad8cd4776c2dbd27237bee"><code>4af47fb</code></a>
Fix hues in achromatic theme colors to be <code>none</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20314">#20314</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/5835691d210b1c530160c844a562c36fa5fcbdb3"><code>5835691</code></a>
Handle CSS nesting natively (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20124">#20124</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/67c745efde4c6b36879e812b4c3d9250f7e0b31e"><code>67c745e</code></a>
Fix bug in attribute selector parsing (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20303">#20303</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/2683903b86d695f9c2647a06eb58bd96ade1eaee"><code>2683903</code></a>
Support fractional opacity modifiers for named shadow sizes (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20302">#20302</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/04588b1e8f3dbc856d8a3fad97c460bee689dbf3"><code>04588b1</code></a>
Fix theme() in JS plugins returning unresolved object instead of DEFAULT
valu...</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/b53fa096c92d830fc64b7cf69581496242583446"><code>b53fa09</code></a>
fix: exclude iframes from focus-visible auto outline in Preflight (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20292">#20292</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/ef79119d4e2b8b0f37710e736605bd0b3419afb7"><code>ef79119</code></a>
Bump dependencies (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20300">#20300</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.1.4 to 8.1.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>v8.1.5</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.5/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.1.4...v8.1.5">8.1.5</a>
(2026-07-16)<!-- raw HTML omitted --></h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>bundled-dev:</strong> avoid duplicated <code>buildEnd</code>
(<a
href="https://redirect.github.com/vitejs/vite/issues/22931">#22931</a>)
(<a
href="https://github.com/vitejs/vite/commit/810032097079be1a7da0e2b09ec9d92dd07ec13f">8100320</a>)</li>
<li><strong>client:</strong> overlay error message format align rolldown
(<a
href="https://redirect.github.com/vitejs/vite/issues/22869">#22869</a>)
(<a
href="https://github.com/vitejs/vite/commit/5a72b8780705b575026617e86b0b92dea63a56a5">5a72b87</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22921">#22921</a>)
(<a
href="https://github.com/vitejs/vite/commit/fef682d3f067d534a559faf6fd9baedda2e9f8f1">fef682d</a>)</li>
<li><strong>deps:</strong> update rolldown-related dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22922">#22922</a>)
(<a
href="https://github.com/vitejs/vite/commit/3c345e475a5546a1cc6374682af89caebfe9c593">3c345e4</a>)</li>
<li><strong>module-runner:</strong> don't crash stack-trace source
mapping when globalThis.Buffer is absent (<a
href="https://redirect.github.com/vitejs/vite/issues/22945">#22945</a>)
(<a
href="https://github.com/vitejs/vite/commit/f8b38e316bcefbf29f762f90ee49c88cd52c43b5">f8b38e3</a>)</li>
<li><strong>optimizer:</strong> respect importer module format for
dynamic import interop with CJS deps (<a
href="https://redirect.github.com/vitejs/vite/issues/22951">#22951</a>)
(<a
href="https://github.com/vitejs/vite/commit/6c08c39ac4fb5868d080a51ff976a44693fc56ab">6c08c39</a>)</li>
<li><strong>ssr:</strong> scope switch-case declarations to the switch,
not the function (<a
href="https://redirect.github.com/vitejs/vite/issues/22893">#22893</a>)
(<a
href="https://github.com/vitejs/vite/commit/b59a73f76f5557492d83d097bb33b3dd02f27d51">b59a73f</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>build:</strong> fix incorrect <code>@default</code> for
build.cssMinify (<a
href="https://redirect.github.com/vitejs/vite/issues/22948">#22948</a>)
(<a
href="https://github.com/vitejs/vite/commit/c88c236186d8e2384653e382dd0960ca1ff5b24c">c88c236</a>)</li>
<li><strong>build:</strong> fix incorrect <code>@default</code> for
build.lib.formats (<a
href="https://redirect.github.com/vitejs/vite/issues/22911">#22911</a>)
(<a
href="https://github.com/vitejs/vite/commit/369ed609a4aace3aee4e4194a54990694aa4e7ac">369ed60</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li>avoid scanner scanning all files under <code>__tests__</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/22912">#22912</a>)
(<a
href="https://github.com/vitejs/vite/commit/c961cae2868cc1521457ec60583867f0440e6949">c961cae</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/5e7fe129a4dde4f41934083b25e490059985f4e6"><code>5e7fe12</code></a>
release: v8.1.5</li>
<li><a
href="https://github.com/vitejs/vite/commit/6c08c39ac4fb5868d080a51ff976a44693fc56ab"><code>6c08c39</code></a>
fix(optimizer): respect importer module format for dynamic import
interop wit...</li>
<li><a
href="https://github.com/vitejs/vite/commit/5a72b8780705b575026617e86b0b92dea63a56a5"><code>5a72b87</code></a>
fix(client): overlay error message format align rolldown (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22869">#22869</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/f8b38e316bcefbf29f762f90ee49c88cd52c43b5"><code>f8b38e3</code></a>
fix(module-runner): don't crash stack-trace source mapping when
globalThis.Bu...</li>
<li><a
href="https://github.com/vitejs/vite/commit/810032097079be1a7da0e2b09ec9d92dd07ec13f"><code>8100320</code></a>
fix(bundled-dev): avoid duplicated <code>buildEnd</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22931">#22931</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/c88c236186d8e2384653e382dd0960ca1ff5b24c"><code>c88c236</code></a>
docs(build): fix incorrect <code>@default</code> for build.cssMinify (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22948">#22948</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/b59a73f76f5557492d83d097bb33b3dd02f27d51"><code>b59a73f</code></a>
fix(ssr): scope switch-case declarations to the switch, not the function
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22">#22</a>...</li>
<li><a
href="https://github.com/vitejs/vite/commit/fef682d3f067d534a559faf6fd9baedda2e9f8f1"><code>fef682d</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22921">#22921</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/3c345e475a5546a1cc6374682af89caebfe9c593"><code>3c345e4</code></a>
fix(deps): update rolldown-related dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22922">#22922</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/369ed609a4aace3aee4e4194a54990694aa4e7ac"><code>369ed60</code></a>
docs(build): fix incorrect <code>@default</code> for build.lib.formats
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22911">#22911</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v8.1.5/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 18:33:52 -04:00
dependabot[bot] 8eb9bd5c21 Bump python from d3400aa to cea0e60 (#1131)
Bumps python from `d3400aa` to `cea0e60`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.6-slim&new-version=3.14.6-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 18:33:45 -04:00
dependabot[bot] a4d587037d Bump seleniumbase from 4.51.2 to 4.51.3 in the python-deps group (#1128)
Bumps the python-deps group with 1 update:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `seleniumbase` from 4.51.2 to 4.51.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.3 - CDP Mode: Patch 121</h2>
<h2>CDP Mode: Patch 121</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a190a7e3f9360d04d14f31ecdb773b0d803babd1">Update
CDP Mode</a>
-- Add <code>scroll</code> &amp; <code>timeout</code> args for some
methods.
-- Handle a special case for clicking <code>svg</code> elements.</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/01c6cec2fedb22ea8afd98333341477716a886e9">Refresh
Python dependencies</a>
-- (<code>websockets</code>, <code>filelock</code>,
<code>platformdirs</code>)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 121 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4431">seleniumbase/SeleniumBase#4431</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.2...v4.51.3">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.2...v4.51.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2d5d3fafb22d894abeb941ab51b0428ad55cb48b"><code>2d5d3fa</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4431">#4431</a>
from seleniumbase/cdp-mode-patch-121</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2cf34788cc111bcf415180dbbe4440490a776b9d"><code>2cf3478</code></a>
Version 4.51.3</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/01c6cec2fedb22ea8afd98333341477716a886e9"><code>01c6cec</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a190a7e3f9360d04d14f31ecdb773b0d803babd1"><code>a190a7e</code></a>
Update CDP Mode</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.2...v4.51.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=seleniumbase&package-manager=uv&previous-version=4.51.2&new-version=4.51.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 18:33:38 -04:00
Calibrain 1747b3466e Fix linting issues 2026-07-21 19:52:25 +00:00
CaliBrain 81a057c8a0 Try and fix OIDC (#1127) 2026-07-21 15:43:54 -04:00
Matt Van HornandMatt Van Horn 91b1064689 fix(naming): respect subfolder order when assigning audiobook part numbers (#1123)
## Summary

Audiobooks whose files are split across nested subfolders now keep their
on-disk folder order when "Rename and Organize" assigns part numbers.
Previously `natural_sort_key` keyed on `Path(path).name`, so identically
named files from different folders (`001.mp3` in `00_Introduction/` vs
`06_Side 6/`) collapsed together and the part sequence scrambled.

## Background

zazizou reported in #1007 that the total file count was right but
`06_Side 6/001.mp3` came out as part 1 instead of
`00_Introduction/001_About.mp3`. `scan.py` flattens every nested file
into one list and `assign_part_numbers` sorts it with
`natural_sort_key`, which discarded the parent-folder prefix. The fix
pads the existing `PAD_NUMBERS_PATTERN` numbers over the full relative
path (`str(path).lower()`) rather than the basename, so nested
audiobooks sort by folder first and then by filename. Flat directories
are unaffected because their files share a prefix, and
`natural_sort_key` is only called from `assign_part_numbers`, so nothing
else changes. I updated the test that pinned the old basename-only
ordering and added nested-subfolder and duplicate-basename cases;
`pytest tests/core/test_naming.py
tests/core/test_part_number_extraction.py` passes (102 tests).

Closes #1007

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-07-21 15:41:03 -04:00
dependabot[bot] c9a2b5eccf Bump the python-deps group across 1 directory with 4 updates (#1126)
Bumps the python-deps group with 4 updates in the / directory:
[tqdm](https://github.com/tqdm/tqdm),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase),
[prek](https://github.com/j178/prek) and
[ruff](https://github.com/astral-sh/ruff).

Updates `tqdm` from 4.68.4 to 4.69.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.69.0 stable</h2>
<ul>
<li>add <code>tqdm.asyncio.gather(..., return_exceptions=False)</code>
(<a href="https://redirect.github.com/tqdm/tqdm/issues/1776">#1776</a>,
<a href="https://redirect.github.com/tqdm/tqdm/issues/1671">#1671</a>
&lt;- <a
href="https://redirect.github.com/tqdm/tqdm/issues/1286">#1286</a>)</li>
<li>misc minor framework updates
<ul>
<li>bump workflow actions &amp; pre-commit hooks</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/6ab24dcc5df910044f1f6e0685f95dbf9cd424f3"><code>6ab24dc</code></a>
bump version, workflow actions, pre-commit hooks</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/99615b978702dcf61986de62dfd252d82720af76"><code>99615b9</code></a>
asyncio: add gather(return_exceptions=False) (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1776">#1776</a>)</li>
<li>See full diff in <a
href="https://github.com/tqdm/tqdm/compare/v4.68.4...v4.69.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.51.0 to 4.51.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.2 - CDP Mode: Patch 120</h2>
<h2>CDP Mode: Patch 120</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7614ca495d8a52a2100516c0fcad079e191c13f4">Fix
WebRTC leak for non-proxied navigation</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4428">seleniumbase/SeleniumBase#4428</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/92c528ae17d0e07294671d09cb253c5e5ebbb8ca">Drop
support for the deprecated Atlas Browser</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4427">seleniumbase/SeleniumBase#4427</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9c0f401a9977efbb7d13114aaf98a52a0532af9c">Remove
Copilot examples (requires login now)</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4429">seleniumbase/SeleniumBase#4429</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/aca0363058c95c4590ff6639e4e51d05010ddbe8">Add
a CDP Mode fingerprint test</a>
-- (Uses the Clearcote fingerprint scanner / auditor)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e152f11df548e76ec34822188a5234f6cb09cd57">Update
Stealthy Playwright Mode examples</a>
-- (<code>sb.goto(url)</code> is stealthier than
<code>page.goto(url)</code>)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/93de30adf71d6b3277512ab78f1ddf1eb0b586d3">Refresh
Python dependencies</a>
-- (<code>filelock</code> and <code>coverage</code>)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 120 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4430">seleniumbase/SeleniumBase#4430</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.1...v4.51.2">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.1...v4.51.2</a></p>
<h2>4.51.1 - Updates to multiple areas</h2>
<h2>Updates to multiple areas</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/706e23c5b25000e64f9b97dbb9118717eafaed05">Update
the xpath-to-css converter</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1c7fa3bbefd870e79e3b3e75044b2a88258f204e">Update
the CDP Mode ad-block list</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cb6fbb103b4dc61d2f6d425c54dc966b4fd6181e">Update
error messages for proxy failures</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fe392b5b3fd90a04d0d266ddbcd76cbcc7ccab7c">Update
proxy validation</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/dd14d5e0c7832150d70b6bd3bd950cc3a8ad10cb">Update
the Slider CAPTCHA solver</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/97d53f601faa2f8247eea00271ce6140e3d7d158">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Updates to multiple areas by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4424">seleniumbase/SeleniumBase#4424</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.0...v4.51.1">https://github.com/seleniumbase/SeleniumBase/compare/v4.51.0...v4.51.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f9fca2dc604067020363b285b0fff15910e64cea"><code>f9fca2d</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4430">#4430</a>
from seleniumbase/cdp-mode-patch-120</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e4f803f5adc47880c5563c7ae528d1a190249865"><code>e4f803f</code></a>
Version 4.51.2</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/93de30adf71d6b3277512ab78f1ddf1eb0b586d3"><code>93de30a</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e152f11df548e76ec34822188a5234f6cb09cd57"><code>e152f11</code></a>
Update Stealthy Playwright Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/aca0363058c95c4590ff6639e4e51d05010ddbe8"><code>aca0363</code></a>
Add a CDP Mode fingerprint test</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9c0f401a9977efbb7d13114aaf98a52a0532af9c"><code>9c0f401</code></a>
Remove Copilot examples (requires login now)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/92c528ae17d0e07294671d09cb253c5e5ebbb8ca"><code>92c528a</code></a>
Drop support for the deprecated Atlas Browser</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7614ca495d8a52a2100516c0fcad079e191c13f4"><code>7614ca4</code></a>
Fix WebRTC leak for non-proxied navigation</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/45a338be063e2ae0561779c1ca5433804242d98d"><code>45a338b</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a1fd937c94825d1f668eacc457cb9539bfb22d93"><code>a1fd937</code></a>
Update CDP Mode examples</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.51.0...v4.51.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.9 to 0.4.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.10</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-16.</p>
<h3>Enhancements</h3>
<ul>
<li>Add PHP language support (<a
href="https://redirect.github.com/j178/prek/pull/2314">#2314</a>)</li>
<li>Add freeze option to update settings (<a
href="https://redirect.github.com/j178/prek/pull/2323">#2323</a>)</li>
<li>Add tag filters to update configuration (<a
href="https://redirect.github.com/j178/prek/pull/2354">#2354</a>)</li>
<li>Identify 'mts' and 'cts' as TypeScript files (<a
href="https://redirect.github.com/j178/prek/pull/2209">#2209</a>)</li>
<li>Publish Alpine Docker images (<a
href="https://redirect.github.com/j178/prek/pull/2352">#2352</a>)</li>
<li>Support builtin and meta in try-repo (<a
href="https://redirect.github.com/j178/prek/pull/2350">#2350</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix Python discovery order (<a
href="https://redirect.github.com/j178/prek/pull/2348">#2348</a>)</li>
<li>Fix Windows progress rendering (<a
href="https://redirect.github.com/j178/prek/pull/2328">#2328</a>)</li>
<li>Preserve configured repo values for updates (<a
href="https://redirect.github.com/j178/prek/pull/2324">#2324</a>)</li>
<li>Scope synthetic <code>GIT_WORK_TREE</code> to git commands (<a
href="https://redirect.github.com/j178/prek/pull/2356">#2356</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Expand common workflows guide (<a
href="https://redirect.github.com/j178/prek/pull/2351">#2351</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.10</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.10/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.10/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.4.10</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.10</h2>
<p>Released on 2026-07-16.</p>
<h3>Enhancements</h3>
<ul>
<li>Add PHP language support (<a
href="https://redirect.github.com/j178/prek/pull/2314">#2314</a>)</li>
<li>Add freeze option to update settings (<a
href="https://redirect.github.com/j178/prek/pull/2323">#2323</a>)</li>
<li>Add tag filters to update configuration (<a
href="https://redirect.github.com/j178/prek/pull/2354">#2354</a>)</li>
<li>Identify 'mts' and 'cts' as TypeScript files (<a
href="https://redirect.github.com/j178/prek/pull/2209">#2209</a>)</li>
<li>Publish Alpine Docker images (<a
href="https://redirect.github.com/j178/prek/pull/2352">#2352</a>)</li>
<li>Support builtin and meta in try-repo (<a
href="https://redirect.github.com/j178/prek/pull/2350">#2350</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix Python discovery order (<a
href="https://redirect.github.com/j178/prek/pull/2348">#2348</a>)</li>
<li>Fix Windows progress rendering (<a
href="https://redirect.github.com/j178/prek/pull/2328">#2328</a>)</li>
<li>Preserve configured repo values for updates (<a
href="https://redirect.github.com/j178/prek/pull/2324">#2324</a>)</li>
<li>Scope synthetic <code>GIT_WORK_TREE</code> to git commands (<a
href="https://redirect.github.com/j178/prek/pull/2356">#2356</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Expand common workflows guide (<a
href="https://redirect.github.com/j178/prek/pull/2351">#2351</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/b45e6710082ed28943c96268d0ea99026dbb13ba"><code>b45e671</code></a>
Bump version to 0.4.10 (<a
href="https://redirect.github.com/j178/prek/issues/2358">#2358</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/0cf3be5280613835759de9912ec57eb724d3db22"><code>0cf3be5</code></a>
Scope synthetic <code>GIT_WORK_TREE</code> to git commands (<a
href="https://redirect.github.com/j178/prek/issues/2356">#2356</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/0265dddfff97f1be7fcf3aaeefdeeb12572473de"><code>0265ddd</code></a>
Add tag filters to update configuration (<a
href="https://redirect.github.com/j178/prek/issues/2354">#2354</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/dcfa91b31b3b165bee4bc472291aadaf7910069f"><code>dcfa91b</code></a>
Publish Alpine Docker images (<a
href="https://redirect.github.com/j178/prek/issues/2352">#2352</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1e0b2c108458e781c827695bd075406a13f15cb6"><code>1e0b2c1</code></a>
Expand common workflows guide (<a
href="https://redirect.github.com/j178/prek/issues/2351">#2351</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/753e13c4fe94d83695da6bc16f2939770c9aa219"><code>753e13c</code></a>
Support builtin and meta in try-repo (<a
href="https://redirect.github.com/j178/prek/issues/2350">#2350</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1e2abfb81f5213990413f222ad4d7444af430518"><code>1e2abfb</code></a>
Fix Python discovery order (<a
href="https://redirect.github.com/j178/prek/issues/2348">#2348</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ec15d683e1b9bd8e265d92d7116bf19b574fedc9"><code>ec15d68</code></a>
Update Rust crate indicatif to v0.18.6 (<a
href="https://redirect.github.com/j178/prek/issues/2330">#2330</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ba4939a4856803ea1c4b886d5c8b3b9ba19df74a"><code>ba4939a</code></a>
Update Rust crate fs-err to v3.3.1 (<a
href="https://redirect.github.com/j178/prek/issues/2329">#2329</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/e43acba74e33728d30277a2c229eaed1def17b49"><code>e43acba</code></a>
Improve contribution templates (<a
href="https://redirect.github.com/j178/prek/issues/2347">#2347</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.9...v0.4.10">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.21 to 0.15.22
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.22</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li>
<li>[<code>refurb</code>] Allow subclassing builtins in stub files
(<code>FURB189</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li>
<li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments
with <code>ruff:ignore</code> (<code>RUF105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
<code>ruff:ignore</code> comments (<code>RUF106</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
configuration selectors (<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Ignore mutable type updates in
<code>redefined-loop-name</code> (<code>PLW2901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid redundant lexer token bookkeeping (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li>
<li>Avoid redundant pending-indentation writes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li>
<li>Avoid unnecessary identifier lookahead (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li>
<li>Reuse parser scratch buffers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li>
<li>[<code>flake8-datetimez</code>] Clarify naming guidance for
<code>datetime.today</code> (<code>DTZ002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li>
<li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li>
<li>[<code>ruff</code>] Clarify intentional async contexts for
<code>unused-async</code> (<code>RUF029</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dwego"><code>@​dwego</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/Joosboy"><code>@​Joosboy</code></a></li>
<li><a
href="https://github.com/KaufmanDmitriy"><code>@​KaufmanDmitriy</code></a></li>
<li><a
href="https://github.com/PeterJCLaw"><code>@​PeterJCLaw</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
<h2>Install ruff 0.15.22</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.22</h2>
<p>Released on 2026-07-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li>
<li>[<code>refurb</code>] Allow subclassing builtins in stub files
(<code>FURB189</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li>
<li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments
with <code>ruff:ignore</code> (<code>RUF105</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
<code>ruff:ignore</code> comments (<code>RUF106</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li>
<li>[<code>ruff</code>] Add rule to use human-readable names in
configuration selectors (<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Ignore mutable type updates in
<code>redefined-loop-name</code> (<code>PLW2901</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid redundant lexer token bookkeeping (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li>
<li>Avoid redundant pending-indentation writes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li>
<li>Avoid unnecessary identifier lookahead (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li>
<li>Reuse parser scratch buffers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li>
<li>[<code>flake8-datetimez</code>] Clarify naming guidance for
<code>datetime.today</code> (<code>DTZ002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li>
<li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li>
<li>[<code>ruff</code>] Clarify intentional async contexts for
<code>unused-async</code> (<code>RUF029</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dwego"><code>@​dwego</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/Joosboy"><code>@​Joosboy</code></a></li>
<li><a
href="https://github.com/KaufmanDmitriy"><code>@​KaufmanDmitriy</code></a></li>
<li><a
href="https://github.com/PeterJCLaw"><code>@​PeterJCLaw</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/0177a7e0d2c4a3805afa1960f106d72878766cbc"><code>0177a7e</code></a>
Bump 0.15.22 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26884">#26884</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/fe8ba85a55b76d838e6058d813b64468b5f81eca"><code>fe8ba85</code></a>
[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26847">#26847</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f3cf7c81fa35f8b819a719303bf1789714f1c780"><code>f3cf7c8</code></a>
[<code>ruff</code>] Add <code>rule-codes-in-selectors</code>
(<code>RUF201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26772">#26772</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d244fd75e9036e61be4896b823fe760d7aa632a3"><code>d244fd7</code></a>
Document argfile support (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26803">#26803</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f23975849a0db64a2851029c68fc054799d5e7da"><code>f239758</code></a>
[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code>
(<code>PYI053</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26872">#26872</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/54acbcde56d76bc47b0b3dfe61e57fbaadd2c06b"><code>54acbcd</code></a>
[ty] Support <code>TypeVarTuple</code> and <code>Unpack</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25240">#25240</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/87fc38cacd7e2bd906674c6dc5b8be97aa3a5bc3"><code>87fc38c</code></a>
[ty] Parallelize subtype hierarchy search (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26875">#26875</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e454f91fa63bd745d874ead751ad15d9f521195a"><code>e454f91</code></a>
[ty] Share interned query keys across Salsa queries (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26794">#26794</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6f361a74a232ad283cc6e5e5d3a62109802aab65"><code>6f361a7</code></a>
[ty] only collect expected types for files open in the editor (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25546">#25546</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6d6b2b37686da8b1ee56e54fd99831f1f5fa0381"><code>6d6b2b3</code></a>
[ty] Avoid allocations during Salsa interned lookups (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26877">#26877</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.21...0.15.22">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 15:40:08 -04:00
dependabot[bot]andCaliBrain 28969ac828 Bump the npm-deps group across 1 directory with 7 updates (#1112)
Bumps the npm-deps group with 7 updates in the /src/frontend directory:

| Package | From | To |
| --- | --- | --- |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `26.0.1` | `26.1.1` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.23.0` | `6.26.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.57.0` | `0.58.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.72.0` | `1.73.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.23.0`
| `0.24.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.1.0` | `8.1.4` |
|
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
| `4.1.9` | `4.1.10` |


Updates `@types/node` from 26.0.1 to 26.1.1
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.23.0 to 6.26.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.26.0</h2>
<ul>
<li>ci: add path filters (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1871">#1871</a>)
(4249935adffe1b8eca9570fb325fa19cc8010584) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>Add CodeRabbit as gold sponsor
(1da09fdc8f4d851f3cad30659200018bfb47a5e0)</li>
<li>Fix up docs a bit more
(39125a7f473e006f61629781bff1ac4a050ca460)</li>
<li>Don't report ambient declaration files as unused
(aed361c00a82829c2fc80a65a2f7af174316782e)</li>
<li>Register oclif command files as entries
(3b4d58c9da83d93b6821a2b24f57b919ba886756)</li>
<li>Add electron-vite plugin
(d92107ea504833b3ee7ad2b695e22d40528b24c3)</li>
<li>Add esbuild plugin (ef3b601d957546554de2cb1fbff859f5bdafb741)</li>
<li>Ignore more globally available binaries
(829298129fdfd1b41a1f8dff5022b9fbbe25f454)</li>
<li>Resolve <code>#</code>-imports to source when node condition is
unbuilt (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1873">#1873</a>)
(f2713ed1e499ab286b86615d4b8ec34f711d1bd2)</li>
<li>Ignore gh as a globally available binary
(a6f0772e5db03a8412a3ac036756779f22d1a27d)</li>
<li>Resolve Vitest benchmark files as entries
(57429139f7e93f2a4bee35a53d450c4f45dea9ff)</li>
<li>Extract shared Vue auto-import machinery into plugins/_vue
(73010753d432ae58eb12c7eec9c5723036009749)</li>
<li>Scope compiler extensions per workspace
(5e6f82b963a83e5801484efbc01a4b6a9ce39ea3)</li>
<li>Resolve auto-imported components in the Vue SFC compiler
(009aad8f9dab589898e5dba4c85fa41ea57c1a49)</li>
<li>Add plugins for the Vue auto-import ecosystem
(f638c8302cdd26a63e477344a7cf44ef60af7788)</li>
<li>Enable Vue SFC compiler on unplugin-vue and
<code>@​vitejs/plugin-vue</code>
(9396ab159919147ef81dad16e365e531b32b4b12)</li>
<li>Recognize vite-plugin-vue-meta-layouts (same layouts convention)
(3ceee89228b0173eddc0466bf50e8181286ffebc)</li>
<li>Add vite-plugin-pages and unplugin-icons plugins
(9bc17540bcf8eb142474ed84837c1e2cebb7fe73)</li>
<li>Add vite-plugin-pwa and <code>@​intlify/unplugin-vue-i18n</code>
plugins (45dea0a397ed754c34617ed18deef4dc6f0ec0d4)</li>
<li>Dog, food. (e1249ade2558d3801d85e2dc63349d884f3443d4)</li>
<li>Update query snapshot
(a45941d2db381c04f8a38416533217ee84f77ca7)</li>
<li>Don't misread Nitro route types as Vue component auto-imports
(43aecd5414eb63bec3637f37ffac0c62a71e7e74)</li>
<li>Read oxlint jsPlugins from vite-plus vite.config and .oxlintrc.json
(589ffda4e3a7d0c0d772191ad6f8d6e60dd298cf)</li>
<li>Add vite-plus plugin for run.tasks and staged scripts
(f041c191e4e10dd181ad212b71079e3e10bcf341)</li>
<li>Support <code>@​vite-pwa/nuxt</code> PWA config in nuxt.config
(8fa7b116690e37484798ad98eca002d26c0c80fe)</li>
<li>Add <code>@​vite-pwa/assets-generator</code> plugin
(4254f7d53a284a4ea4612f650ae03495bcb0d582)</li>
<li>Add <code>@​nuxtjs/i18n</code> plugin
(dfb9acbe5a08ebc85562f59a04e7f4bedb4925f1)</li>
<li>Read plugin entries from vite.config options and index.html
(d533da8cc2b431d206eb7c55323ea51846eca0bb)</li>
<li>Fix false positives in VitePress, next-mdx and unplugin-vue-i18n
plugins (b99702a76e26b1943a16517f1633de3a0713c196)</li>
<li>Respect optional peers in pnpm and Yarn packageExtensions
(aab080bbd436494316df045011ab22cbebca06b4)</li>
<li>Detect babel plugins in the Storybook config
(5dea975adf9b88971ad56434132282a099c7d58c)</li>
<li>Add shared AST helpers for imported calls and first property values
(c84bb7a87a17f1921c12bb02bcfd43f905cae595)</li>
<li>Inline trivial resolveFromAST wrappers and normalize orval and sst
(620079d1d07b69a69bbb67b6a6e68963b6c2fc21)</li>
<li>Extract inline resolveFromAST implementations to dedicated files
(b5231c12f915428067d790187d2dd4c44e2559d4)</li>
<li>Normalize resolveFromAST files to a uniform contract
(fc1ba0fb45aaf623de678a57bea3b5567ea04750)</li>
<li>chore: migrate to Astro 7 and Sätteri (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1875">#1875</a>)
(f256a5b276c3d69dd5081c591bbb183aacebf766) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>Show contributor count on docs homepage
(6b8454a2841905ce7f08e1a23b54bc17a0854608)</li>
<li>Exclude gitignored package entry points
(606e5d051b4f0620c776aa23352153b8253bd75b)</li>
<li>Add Tauri plugin (199180da79c71acc80865dc65ce89653a26d9579)</li>
<li>Add Laravel plugin (197453378f2b60e5143a30ec78b438f02b37c53b)</li>
<li>Add Quasar plugin (a220729074bfbb9e7d03ba329e89ad553c3a7799)</li>
</ul>
<h2>Release 6.25.0</h2>
<ul>
<li>fix: derive package name from package.json under Yarn
<code>nodeLinker: pnpm</code> store (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1852">#1852</a>)
(3764605ed150b975fb6c88c4c4aa47f5bf9ae149) - thanks <a
href="https://github.com/blowery"><code>@​blowery</code></a>!</li>
<li>Pick up types used in module augmentations via path aliases (resolve
<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1850">#1850</a>)
(9cc5a4132793990b5fcf9eae6f3db37426d979c0)</li>
<li>feat: add support for <code>packageExtensions</code> in yarn and
pnpm (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1847">#1847</a>)
(61d3164cdac6e9252b3c52ce3bb2909949b4690e) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>fix(ci): do not run integration on forks (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1855">#1855</a>)
(d23c10d1ae764c0b70addaafc79f01c543cc5efa) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>chore(ci): improve security through specific permissions (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1856">#1856</a>)
(1eb42e639f9ec12d6d2ef88e1aaf07397b5bf226) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>chore(ci): add concurrency blocks (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1857">#1857</a>)
(3bf3d115cf677fadcfe8fa72ce0e68cfd435d399) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/441faf08dfa1e87daa342620026947c99a98ec40"><code>441faf0</code></a>
Release knip@6.26.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/a220729074bfbb9e7d03ba329e89ad553c3a7799"><code>a220729</code></a>
Add Quasar plugin</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/197453378f2b60e5143a30ec78b438f02b37c53b"><code>1974533</code></a>
Add Laravel plugin</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/199180da79c71acc80865dc65ce89653a26d9579"><code>199180d</code></a>
Add Tauri plugin</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/606e5d051b4f0620c776aa23352153b8253bd75b"><code>606e5d0</code></a>
Exclude gitignored package entry points</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/fc1ba0fb45aaf623de678a57bea3b5567ea04750"><code>fc1ba0f</code></a>
Normalize resolveFromAST files to a uniform contract</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b5231c12f915428067d790187d2dd4c44e2559d4"><code>b5231c1</code></a>
Extract inline resolveFromAST implementations to dedicated files</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/620079d1d07b69a69bbb67b6a6e68963b6c2fc21"><code>620079d</code></a>
Inline trivial resolveFromAST wrappers and normalize orval and sst</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c84bb7a87a17f1921c12bb02bcfd43f905cae595"><code>c84bb7a</code></a>
Add shared AST helpers for imported calls and first property values</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/5dea975adf9b88971ad56434132282a099c7d58c"><code>5dea975</code></a>
Detect babel plugins in the Storybook config</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.26.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.57.0 to 0.58.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/39677ba50d908ea09f6d9e58ded328461212f52a"><code>39677ba</code></a>
release(apps): oxlint v1.73.0 &amp;&amp; oxfmt v0.58.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/24219">#24219</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.58.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.72.0 to 1.73.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.73.0] - 2026-07-06</h2>
<h3>🚀 Features</h3>
<ul>
<li>a2c97f3 linter/unicorn: Implement <code>explicit-timer-delay</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23612">#23612</a>)
(Mikhail Baev)</li>
<li>85735cb linter/unicorn: Implement
<code>no-confusing-array-with</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23638">#23638</a>)
(Shekhu☺️)</li>
<li>cb4fbb9 linter/eslint: Implement no-unreachable-loop rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23975">#23975</a>)
(Todor Andonov)</li>
<li>dc32112 linter/eslint/no-constant-binary-expression: Check
relational comparisons (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24088">#24088</a>)
(camc314)</li>
<li>d963967 linter/unicorn/no-array-sort: Add
<code>allowAfterSpread</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24043">#24043</a>)
(Boshen)</li>
<li>0a75682 linter: Add per-rule timings for type-aware linting (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22488">#22488</a>)
(camchenry)</li>
<li>743e222 linter/react: Add <code>disallowedValues</code> option for
<code>forbid-dom-props</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23970">#23970</a>)
(Mikhail Baev)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>bdb51c7 linter/jest/prefer-ending-with-an-expect: Validate config
patterns (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24122">#24122</a>)
(camc314)</li>
<li>45d607d linter/react/forbid-component-props: Make allow/disallow
lists optional in schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24024">#24024</a>)
(Boshen)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/39677ba50d908ea09f6d9e58ded328461212f52a"><code>39677ba</code></a>
release(apps): oxlint v1.73.0 &amp;&amp; oxfmt v0.58.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24219">#24219</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/a2c97f348c8bdabe99a08b2fbb45d32ffe49a529"><code>a2c97f3</code></a>
feat(linter/unicorn): implement <code>explicit-timer-delay</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23612">#23612</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/bdb51c73da9edeef02ce39477167765d971fb5cb"><code>bdb51c7</code></a>
fix(linter/jest/prefer-ending-with-an-expect): validate config patterns
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24122">#24122</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/85735cb5df27daffd32651f808a382680ee92aaf"><code>85735cb</code></a>
feat(linter/unicorn): implement <code>no-confusing-array-with</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23638">#23638</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/cb4fbb927f237b0ba4937a8de5a7b28c444b4114"><code>cb4fbb9</code></a>
feat(linter/eslint): implement no-unreachable-loop rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23975">#23975</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/dc321127faa1e0f7bff293319717c52f9c8f6b95"><code>dc32112</code></a>
feat(linter/eslint/no-constant-binary-expression): check relational
compariso...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d96396707923bcffa92e732b15bf23631561f35c"><code>d963967</code></a>
feat(linter/unicorn/no-array-sort): add <code>allowAfterSpread</code>
option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/24043">#24043</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/45d607d48529dc9f32f53436ee816fc02494c64b"><code>45d607d</code></a>
fix(linter/react/forbid-component-props): make allow/disallow lists
optional ...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0a75682fcb38014878d53f37075f32e12101e265"><code>0a75682</code></a>
feat(linter): add per-rule timings for type-aware linting (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22488">#22488</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/743e22293bc5317c79b6b083ffbb2bd5ab5ebefc"><code>743e222</code></a>
feat(linter/react): add <code>disallowedValues</code> option for
<code>forbid-dom-props</code> rule...</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.73.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint-tsgolint` from 0.23.0 to 0.24.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v0.24.0</h2>
<h2>What's Changed</h2>
<ul>
<li>ci: run windows e2e pnpm commands outside workspace by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/969">oxc-project/tsgolint#969</a></li>
<li>test(no-deprecated): add test for only <code>allow</code> by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/970">oxc-project/tsgolint#970</a></li>
<li>fix(no-deprecated): report contextual object literal properties by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/944">oxc-project/tsgolint#944</a></li>
<li>Update README with PRs note on new rules by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/972">oxc-project/tsgolint#972</a></li>
<li>fix(strict-boolean-expressions): guard invalid predicate indexes by
<a href="https://github.com/camchenry"><code>@​camchenry</code></a> in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/971">oxc-project/tsgolint#971</a></li>
<li>fix(no-deprecated): fix crash when getting prop name for non-literal
by <a href="https://github.com/camchenry"><code>@​camchenry</code></a>
in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/973">oxc-project/tsgolint#973</a></li>
<li>test(no-deprecated): add non-literal computed key regression by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/974">oxc-project/tsgolint#974</a></li>
<li>test(no-floating-promises): sync tests with typescript-eslint by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/975">oxc-project/tsgolint#975</a></li>
<li>fix(no-floating-promises): handle spread arguments before rejection
handlers by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/976">oxc-project/tsgolint#976</a></li>
<li>chore(deps): update crate-ci/typos action to v1.46.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/979">oxc-project/tsgolint#979</a></li>
<li>refactor: remove unneeded <code>nil</code> checks in
<code>strict-boolean-expressions</code> by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/980">oxc-project/tsgolint#980</a></li>
<li>perf(no-unsafe-assignment): add fast-path for sender type by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/981">oxc-project/tsgolint#981</a></li>
<li>feat: add per-rule debug timings by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/960">oxc-project/tsgolint#960</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/982">oxc-project/tsgolint#982</a></li>
<li>chore(deps): update dprint plugins by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/984">oxc-project/tsgolint#984</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/985">oxc-project/tsgolint#985</a></li>
<li>chore(deps): update gomod by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/986">oxc-project/tsgolint#986</a></li>
<li>chore(deps): update crate-ci/typos action to v1.46.3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/988">oxc-project/tsgolint#988</a></li>
<li>test(no-deprecated): cover call and jsx deprecated properties by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/989">oxc-project/tsgolint#989</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/991">oxc-project/tsgolint#991</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/993">oxc-project/tsgolint#993</a></li>
<li>chore(deps): update crate-ci/typos action to v1.47.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/995">oxc-project/tsgolint#995</a></li>
<li>chore(deps): update module github.com/dlclark/regexp2/v2 to v2.1.1
by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/994">oxc-project/tsgolint#994</a></li>
<li>fix(prefer-optional-chain): suggest unsafe nullish rewrite by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/996">oxc-project/tsgolint#996</a></li>
<li>chore(deps): update pnpm to v11.4.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/997">oxc-project/tsgolint#997</a></li>
<li>refactor: cache suppress program diagnostics env by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/999">oxc-project/tsgolint#999</a></li>
<li>refactor: use <code>sync.OnceValue</code> for logLevel by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1000">oxc-project/tsgolint#1000</a></li>
<li>test(no-unnecessary-type-assertion): sync tests with
typescript-eslint by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/998">oxc-project/tsgolint#998</a></li>
<li>fix(no-unnecessary-type-assertion): enable skipped upstream cases by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1001">oxc-project/tsgolint#1001</a></li>
<li>fix(justfile): use --ignore-workspace for e2e pnpm commands by <a
href="https://github.com/swandir"><code>@​swandir</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/983">oxc-project/tsgolint#983</a></li>
<li>test(no-unnecessary-type-arguments): sync tests with
typescript-eslint by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1003">oxc-project/tsgolint#1003</a></li>
<li>test(no-unnecessary-type-assertion): cover nullable literal
assertion by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1002">oxc-project/tsgolint#1002</a></li>
<li>fix(no-unnecessary-type-arguments): preserve constructor inference
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1004">oxc-project/tsgolint#1004</a></li>
<li>refactor: remove <code>OXLINT_TSGOLINT_TIMINGS</code> env var by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1005">oxc-project/tsgolint#1005</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1007">oxc-project/tsgolint#1007</a></li>
<li>fix(prefer-optional-chain): optional chain type assertion handling
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1009">oxc-project/tsgolint#1009</a></li>
<li>chore(deps): update typos to v1.47.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1010">oxc-project/tsgolint#1010</a></li>
<li>chore(deps): update typos to v1.47.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1012">oxc-project/tsgolint#1012</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1013">oxc-project/tsgolint#1013</a></li>
<li>chore(deps): update gomod by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1014">oxc-project/tsgolint#1014</a></li>
<li>chore(deps): update github actions to v2.81.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1015">oxc-project/tsgolint#1015</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1016">oxc-project/tsgolint#1016</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1017">oxc-project/tsgolint#1017</a></li>
<li>chore(deps): update gomod to v0.46.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1018">oxc-project/tsgolint#1018</a></li>
<li>chore(deps): update gomod to v2.2.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1021">oxc-project/tsgolint#1021</a></li>
<li>chore(deps): update github actions to v2.82.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1023">oxc-project/tsgolint#1023</a></li>
<li>chore(deps): update dprint plugins to v0.22.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1022">oxc-project/tsgolint#1022</a></li>
<li>chore(deps): update github actions to v7 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/1024">oxc-project/tsgolint#1024</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/5a37e8902f65440900be1436b814919fcdb4e3d4"><code>5a37e89</code></a>
fix(dot-notation): determine the relevant accessor (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1028">#1028</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/67a281f613312a30665e7d39dfb47f5c15b0ca60"><code>67a281f</code></a>
perf(consistent-return): defer per-function type resolution (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1031">#1031</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/a5e2ff0be1102d9082e13ec35f1f0e4ca7fa65ad"><code>a5e2ff0</code></a>
perf(no-unnecessary-qualifier): skip symbol resolution outside
namespaces. (#...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/a8fc6685df0a817e7c5045a4e3e141d342839959"><code>a8fc668</code></a>
perf(no-confusing-void-expression): check ancestor position before type
query...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/03158cc4c0a0ef2c8bdccab71e6d2723fcc1c4f2"><code>03158cc</code></a>
perf(no-unnecessary-type-conversion): hoist constant builtin-name slices
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1040">#1040</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/d9e645c266b6c4b4671b0a3dc5d3935dbda3a5ef"><code>d9e645c</code></a>
perf(prefer-optional-chain): lazily allocate chain-processor caches (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1041">#1041</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/63f578abe093d7a7e8cb523a1e5e96aacf06b220"><code>63f578a</code></a>
refactor(no-unnecessary-condition): remove dead
containsUnguardedElementAcces...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/f174876a906e0350aff2b75d5607775529c9f845"><code>f174876</code></a>
chore(deps): update gomod (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1035">#1035</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/47de9cfea53da0ae274bc78d47388e3bdd5b7341"><code>47de9cf</code></a>
chore(deps): update github actions (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1036">#1036</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/e209b5b27f5fd22810735bfbfdb0785cbc5d4215"><code>e209b5b</code></a>
chore(deps): update actions/cache action to v6 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/1037">#1037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.23.0...v0.24.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.1.0 to 8.1.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>v8.1.4</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.4/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.1.3</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.3/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.1.2</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.2/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.1.1</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.1/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.1.3...v8.1.4">8.1.4</a>
(2026-07-09)<!-- raw HTML omitted --></h2>
<h3>Features</h3>
<ul>
<li><strong>legacy:</strong> prefer oxc as minifier (fix <a
href="https://redirect.github.com/vitejs/vite/issues/21973">#21973</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/22468">#22468</a>)
(<a
href="https://github.com/vitejs/vite/commit/ab5dafa8e66296ef201f615489fb57954bb740ce">ab5dafa</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>build:</strong> add workaround for building on stackblitz
(<a
href="https://redirect.github.com/vitejs/vite/issues/22840">#22840</a>)
(<a
href="https://github.com/vitejs/vite/commit/575c32c29925c554f4ef4068738ab89c6878f615">575c32c</a>)</li>
<li><strong>build:</strong> keep <code>import.meta.url</code> in preload
function as-is (<a
href="https://redirect.github.com/vitejs/vite/issues/22839">#22839</a>)
(<a
href="https://github.com/vitejs/vite/commit/f1f90ed4742b3cf453428c7e581a6016a4d47321">f1f90ed</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22865">#22865</a>)
(<a
href="https://github.com/vitejs/vite/commit/d4295a9ffce428c0e51892373e00c07fccc0498a">d4295a9</a>)</li>
<li><strong>deps:</strong> update rolldown-related dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22866">#22866</a>)
(<a
href="https://github.com/vitejs/vite/commit/7cf07e4c5f7a6af276012e0c2ec06e08499e951e">7cf07e4</a>)</li>
<li><strong>html:</strong> avoid backtracking in import-only check (<a
href="https://redirect.github.com/vitejs/vite/issues/22848">#22848</a>)
(<a
href="https://github.com/vitejs/vite/commit/b5868c01a124d345664450aaebd677bfba964c05">b5868c0</a>)</li>
<li><strong>optimizer:</strong> avoid optimizer run for transform
request before init (<a
href="https://redirect.github.com/vitejs/vite/issues/22852">#22852</a>)
(<a
href="https://github.com/vitejs/vite/commit/72a5e2192506f51a5efd09c059815a5c43a9eacb">72a5e21</a>)</li>
<li><strong>ssr:</strong> align named export function call stacktrace
column with Node (<a
href="https://redirect.github.com/vitejs/vite/issues/22829">#22829</a>)
(<a
href="https://github.com/vitejs/vite/commit/173a1b648c321e0f836e5a94fc47c4fa9b081bfc">173a1b6</a>)</li>
<li>strip pure CSS chunk imports when chunkImportMap is enabled (<a
href="https://redirect.github.com/vitejs/vite/issues/22841">#22841</a>)
(<a
href="https://github.com/vitejs/vite/commit/648bd04933093d0aac9565f21a49811437776886">648bd04</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>fix incorrect <code>@default</code> for <code>server.cors</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/22859">#22859</a>)
(<a
href="https://github.com/vitejs/vite/commit/70435b2551ee4fe3a0d55c8a3bb61b96f44d2763">70435b2</a>)</li>
</ul>
<h3>Miscellaneous Chores</h3>
<ul>
<li><strong>deps:</strong> update dependency postcss-modules to v9 (<a
href="https://redirect.github.com/vitejs/vite/issues/22867">#22867</a>)
(<a
href="https://github.com/vitejs/vite/commit/a9539d69efc7a4ccf988bbf5da31c2b416ba990e">a9539d6</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>eliminate ineffectiveDynamicImport warn (<a
href="https://redirect.github.com/vitejs/vite/issues/22876">#22876</a>)
(<a
href="https://github.com/vitejs/vite/commit/ea22fb352aad9a42c0a9d08f39d8a0bae8c111a5">ea22fb3</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li>avoid warnings (<a
href="https://redirect.github.com/vitejs/vite/issues/22851">#22851</a>)
(<a
href="https://github.com/vitejs/vite/commit/af21ab68adac3380dc9a854d2fe3f776654301cd">af21ab6</a>)</li>
</ul>
<h3>Build System</h3>
<ul>
<li>remove the custom onLog function (<a
href="https://redirect.github.com/vitejs/vite/issues/22878">#22878</a>)
(<a
href="https://github.com/vitejs/vite/commit/2c4a217a63dc0a7fcb10bc710a988f32b173f481">2c4a217</a>)</li>
<li>replace deprecated <code>onwarn</code> with <code>onLog</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/22741">#22741</a>)
(<a
href="https://github.com/vitejs/vite/commit/c581b5588cb8e94603d17bce2ff9fec8e8e0a3bf">c581b55</a>)</li>
</ul>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.1.2...v8.1.3">8.1.3</a>
(2026-07-02)<!-- raw HTML omitted --></h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>css:</strong> inject inlined CSS after the shebang line (<a
href="https://redirect.github.com/vitejs/vite/issues/22717">#22717</a>)
(<a
href="https://github.com/vitejs/vite/commit/1534d362794e856cc718b123cb245e0efcf36b9a">1534d36</a>)</li>
<li><strong>deps:</strong> bump <code>es-module-lexer</code> to 2.3.0
(<a
href="https://redirect.github.com/vitejs/vite/issues/22838">#22838</a>)
(<a
href="https://github.com/vitejs/vite/commit/7103c3af795396e2ad87e1125eb3fc20d60d9430">7103c3a</a>)</li>
<li>preload css for nested dynamic imports (<a
href="https://redirect.github.com/vitejs/vite/issues/22759">#22759</a>)
(<a
href="https://github.com/vitejs/vite/commit/2c530542da1c50b95b7f0cb17adf82f64ecf97f3">2c53054</a>)</li>
<li><strong>ssr:</strong> correct stacktrace column position for first
line (<a
href="https://redirect.github.com/vitejs/vite/issues/22828">#22828</a>)
(<a
href="https://github.com/vitejs/vite/commit/c4acd6982a051fa10dbd7e3a37e00f0c467793b8">c4acd69</a>)</li>
</ul>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.1.1...v8.1.2">8.1.2</a>
(2026-06-30)<!-- raw HTML omitted --></h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> revert es-module-lexer to 2.1.0 (<a
href="https://redirect.github.com/vitejs/vite/issues/22827">#22827</a>)
(<a
href="https://github.com/vitejs/vite/commit/0d3bd7c4111b8345cfc353c7bbb2c30601752e26">0d3bd7c</a>)</li>
<li>restore, &quot;fix: resolve pnpm .modules.yaml from workspace root
instead of cwd (<a
href="https://redirect.github.com/vitejs/vite/issues/22757">#22757</a>)&quot;
(<a
href="https://redirect.github.com/vitejs/vite/issues/22825">#22825</a>)
(<a
href="https://github.com/vitejs/vite/commit/efb98cce73f3f89c4f03936ab7741cd5b0636f5c">efb98cc</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/a477454442eff649b430f9e3c6caf2500fcb7183"><code>a477454</code></a>
release: v8.1.4</li>
<li><a
href="https://github.com/vitejs/vite/commit/ab5dafa8e66296ef201f615489fb57954bb740ce"><code>ab5dafa</code></a>
feat(legacy): prefer oxc as minifier (fix <a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21973">#21973</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22468">#22468</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/173a1b648c321e0f836e5a94fc47c4fa9b081bfc"><code>173a1b6</code></a>
fix(ssr): align named export function call stacktrace column with Node
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22829">#22829</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/575c32c29925c554f4ef4068738ab89c6878f615"><code>575c32c</code></a>
fix(build): add workaround for building on stackblitz (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22840">#22840</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/72a5e2192506f51a5efd09c059815a5c43a9eacb"><code>72a5e21</code></a>
fix(optimizer): avoid optimizer run for transform request before init
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22852">#22852</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/a9539d69efc7a4ccf988bbf5da31c2b416ba990e"><code>a9539d6</code></a>
chore(deps): update dependency postcss-modules to v9 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22867">#22867</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/70435b2551ee4fe3a0d55c8a3bb61b96f44d2763"><code>70435b2</code></a>
docs: fix incorrect <code>@default</code> for <code>server.cors</code>
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22859">#22859</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/2c4a217a63dc0a7fcb10bc710a988f32b173f481"><code>2c4a217</code></a>
build: remove the custom onLog function (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22878">#22878</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/c581b5588cb8e94603d17bce2ff9fec8e8e0a3bf"><code>c581b55</code></a>
build: replace deprecated <code>onwarn</code> with <code>onLog</code>
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22741">#22741</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/ea22fb352aad9a42c0a9d08f39d8a0bae8c111a5"><code>ea22fb3</code></a>
refactor: eliminate ineffectiveDynamicImport warn (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22876">#22876</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v8.1.4/packages/vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `vitest` from 4.1.9 to 4.1.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.10</h2>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li><strong>browser</strong>: Check fs access in builtin commands
[backport to v4]  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode
(claude-opus-4-8)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10680">vitest-dev/vitest#10680</a>
<a href="https://github.com/vitest-dev/vitest/commit/5c18dd267"><!-- raw
HTML omitted -->(5c18d)<!-- raw HTML omitted --></a></li>
<li><strong>vm</strong>: Fix external module resolve error with deps
optimizer query for encoded URI [backport to v4]  -  by <a
href="https://github.com/SveLil"><code>@​SveLil</code></a> and <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10661">vitest-dev/vitest#10661</a>
<a href="https://github.com/vitest-dev/vitest/commit/bae52b511"><!-- raw
HTML omitted -->(bae52)<!-- raw HTML omitted --></a></li>
</ul>
<h5>    <a
href="https://github.com/vitest-dev/vitest/compare/v4.1.9...v4.1.10">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitest-dev/vitest/commit/db616d227b6e0cb07a94f5d1bba262ee95db7e46"><code>db616d2</code></a>
chore: release v4.1.10 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10718">#10718</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/bae52b5112a6fd8200101b88bf8af9685d077295"><code>bae52b5</code></a>
fix(vm): fix external module resolve error with deps optimizer query for
enco...</li>
<li>See full diff in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-07-19 03:29:15 -04:00
dependabot[bot] 2f5d3dde7d Bump seleniumbase from 4.50.6 to 4.51.0 in the python-deps group (#1118)
Bumps the python-deps group with 1 update:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `seleniumbase` from 4.50.6 to 4.51.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.51.0 - CDP Mode: Patch 119</h2>
<h2>CDP Mode: Patch 119</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/5ca71c54fa8e22004591788a7d76aa77add3fccf">Update
CDP Mode</a>
--&gt; New methods for logging from CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a1a0cdf6476505a5fb10190196ced67487749879">Don't
ignore the cache by default on reload()</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/97b6bf3fef6d3cda8835a1af730c31e06ee27505">Update
the docs</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/775a91bc1843508b9655af396585de376b558e7b">Update
examples</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6f38a2469aa9122eeb188ea683f5b39a55753ee5">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 119 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4422">seleniumbase/SeleniumBase#4422</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.6...v4.51.0">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.6...v4.51.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/36627158b4a395a3793dd97e762e282dc97e2a54"><code>3662715</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4422">#4422</a>
from seleniumbase/cdp-mode-patch-119</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/78abd3effed503e5abfa64fd5697a556229dfe02"><code>78abd3e</code></a>
Version 4.51.0</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6f38a2469aa9122eeb188ea683f5b39a55753ee5"><code>6f38a24</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/775a91bc1843508b9655af396585de376b558e7b"><code>775a91b</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/97b6bf3fef6d3cda8835a1af730c31e06ee27505"><code>97b6bf3</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a1a0cdf6476505a5fb10190196ced67487749879"><code>a1a0cdf</code></a>
Don't ignore the cache by default on reload()</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/5ca71c54fa8e22004591788a7d76aa77add3fccf"><code>5ca71c5</code></a>
Update CDP Mode</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.6...v4.51.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=seleniumbase&package-manager=uv&previous-version=4.50.6&new-version=4.51.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 02:52:13 -04:00
dependabot[bot] 2d949d4e7c Bump python from b877e50 to d3400aa (#1119)
Bumps python from `b877e50` to `d3400aa`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.6-slim&new-version=3.14.6-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 02:52:03 -04:00
dependabot[bot] 100e0dd9f8 Bump the gh-actions group across 1 directory with 10 updates (#1120)
Bumps the gh-actions group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [docker/login-action](https://github.com/docker/login-action) |
`4.2.0` | `4.4.0` |
| [docker/metadata-action](https://github.com/docker/metadata-action) |
`6.1.0` | `6.2.0` |
|
[docker/setup-buildx-action](https://github.com/docker/setup-buildx-action)
| `4.1.0` | `4.2.0` |
|
[docker/build-push-action](https://github.com/docker/build-push-action)
| `7.2.0` | `7.3.0` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `8.2.0`
| `8.3.2` |
| [actions/setup-node](https://github.com/actions/setup-node) | `6.4.0`
| `7.0.0` |
| [github/codeql-action/init](https://github.com/github/codeql-action) |
`4.36.2` | `4.37.0` |
|
[github/codeql-action/autobuild](https://github.com/github/codeql-action)
| `4.36.2` | `4.37.0` |
|
[github/codeql-action/analyze](https://github.com/github/codeql-action)
| `4.36.2` | `4.37.0` |
| [dorny/paths-filter](https://github.com/dorny/paths-filter) | `4.0.1`
| `4.0.2` |


Updates `docker/login-action` from 4.2.0 to 4.4.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/login-action/releases">docker/login-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.4.0</h2>
<ul>
<li>Skip empty <code>registry-auth</code> secret mask by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1035">docker/login-action#1035</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1077.0 <a
href="https://redirect.github.com/docker/login-action/pull/1034">docker/login-action#1034</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.3.0...v4.4.0">https://github.com/docker/login-action/compare/v4.3.0...v4.4.0</a></p>
<h2>v4.3.0</h2>
<ul>
<li>Preserve names in esbuild bundle by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/login-action/pull/1022">docker/login-action#1022</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1076.0 <a
href="https://redirect.github.com/docker/login-action/pull/999">docker/login-action#999</a>
<a
href="https://redirect.github.com/docker/login-action/pull/1030">docker/login-action#1030</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.90.0 to 0.92.0 in
<a
href="https://redirect.github.com/docker/login-action/pull/1004">docker/login-action#1004</a>
<a
href="https://redirect.github.com/docker/login-action/pull/1027">docker/login-action#1027</a></li>
<li>Bump <code>@​sigstore/core</code> from 3.1.0 to 3.2.1 in <a
href="https://redirect.github.com/docker/login-action/pull/1023">docker/login-action#1023</a></li>
<li>Bump <code>@​sigstore/verify</code> from 3.1.0 to 3.1.1 in <a
href="https://redirect.github.com/docker/login-action/pull/1029">docker/login-action#1029</a></li>
<li>Bump http-proxy-agent and https-proxy-agent to 9.1.0 in <a
href="https://redirect.github.com/docker/login-action/pull/1017">docker/login-action#1017</a></li>
<li>Bump js-yaml from 4.1.1 to 5.2.0 in <a
href="https://redirect.github.com/docker/login-action/pull/1028">docker/login-action#1028</a></li>
<li>Bump sigstore from 4.1.0 to 4.1.1 in <a
href="https://redirect.github.com/docker/login-action/pull/1031">docker/login-action#1031</a></li>
<li>Bump tmp from 0.2.5 to 0.2.7 in <a
href="https://redirect.github.com/docker/login-action/pull/1002">docker/login-action#1002</a></li>
<li>Bump undici from 6.24.1 to 6.27.0 in <a
href="https://redirect.github.com/docker/login-action/pull/1020">docker/login-action#1020</a></li>
<li>Bump vite from 7.3.3 to 7.3.6 in <a
href="https://redirect.github.com/docker/login-action/pull/1019">docker/login-action#1019</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.2.0...v4.3.0">https://github.com/docker/login-action/compare/v4.2.0...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/login-action/commit/af1e73f918a031802d376d3c8bbc3fe56130a9b0"><code>af1e73f</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1034">#1034</a>
from docker/dependabot/npm_and_yarn/aws-sdk-dependen...</li>
<li><a
href="https://github.com/docker/login-action/commit/da722bde43bacb027adfc67d42dbaa4c0f9e550b"><code>da722bd</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/2916ad60bd5cb72f07aa54c69fdcc61749c09b7a"><code>2916ad6</code></a>
build(deps): bump the aws-sdk-dependencies group across 1 directory with
2 up...</li>
<li><a
href="https://github.com/docker/login-action/commit/ca0a662f786e4cfddce972005bd68f3dafc3a903"><code>ca0a662</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1035">#1035</a>
from crazy-max/fix-registry-auth-empty-mask</li>
<li><a
href="https://github.com/docker/login-action/commit/c455755a579833bf0d2e4e54e3beb413ef10cc80"><code>c455755</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/48351901f89581a7c12870c787d3f06d1f498438"><code>4835190</code></a>
skip empty registry-auth secret mask</li>
<li><a
href="https://github.com/docker/login-action/commit/992421c6e6806a7f6df609d1bfff374f9eca3004"><code>992421c</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1033">#1033</a>
from docker/dependabot/github_actions/docker/bake-ac...</li>
<li><a
href="https://github.com/docker/login-action/commit/b249b43765525dd7951068267a34cf63f22ab4f0"><code>b249b43</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/1032">#1032</a>
from docker/dependabot/github_actions/docker/bake-ac...</li>
<li><a
href="https://github.com/docker/login-action/commit/1b67977736863551a88ff218642a2d7628b10520"><code>1b67977</code></a>
build(deps): bump docker/bake-action from 7.2.0 to 7.3.0</li>
<li><a
href="https://github.com/docker/login-action/commit/9d49d6a3234c78daa10c3c12183ef7b6caa8e69e"><code>9d49d6a</code></a>
build(deps): bump docker/bake-action/subaction/matrix</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/login-action/compare/650006c6eb7dba73a995cc03b0b2d7f5ca915bee...af1e73f918a031802d376d3c8bbc3fe56130a9b0">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/metadata-action` from 6.1.0 to 6.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/metadata-action/releases">docker/metadata-action's
releases</a>.</em></p>
<blockquote>
<h2>v6.2.0</h2>
<ul>
<li>Preserve names in esbuild bundle by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/metadata-action/pull/689">docker/metadata-action#689</a></li>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/663">docker/metadata-action#663</a></li>
<li>Bump <code>@​actions/github</code> from 9.0.0 to 9.1.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/666">docker/metadata-action#666</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.90.0 to 0.92.0 in
<a
href="https://redirect.github.com/docker/metadata-action/pull/672">docker/metadata-action#672</a>
<a
href="https://redirect.github.com/docker/metadata-action/pull/696">docker/metadata-action#696</a></li>
<li>Bump <code>@​sigstore/core</code> from 3.1.0 to 3.2.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/690">docker/metadata-action#690</a></li>
<li>Bump <code>@​sigstore/verify</code> from 3.1.0 to 3.1.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/693">docker/metadata-action#693</a></li>
<li>Bump csv-parse from 6.2.1 to 7.0.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/683">docker/metadata-action#683</a></li>
<li>Bump js-yaml from 4.1.1 to 4.3.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/688">docker/metadata-action#688</a></li>
<li>Bump moment-timezone from 0.6.1 to 0.6.2 in <a
href="https://redirect.github.com/docker/metadata-action/pull/664">docker/metadata-action#664</a></li>
<li>Bump semver from 7.7.4 to 7.8.5 in <a
href="https://redirect.github.com/docker/metadata-action/pull/665">docker/metadata-action#665</a>
<a
href="https://redirect.github.com/docker/metadata-action/pull/695">docker/metadata-action#695</a></li>
<li>Bump sigstore from 4.1.0 to 4.1.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/694">docker/metadata-action#694</a></li>
<li>Bump tmp from 0.2.5 to 0.2.7 in <a
href="https://redirect.github.com/docker/metadata-action/pull/673">docker/metadata-action#673</a></li>
<li>Bump undici from 6.25.0 to 6.27.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/686">docker/metadata-action#686</a></li>
<li>Bump vite from 7.3.2 to 7.3.6 in <a
href="https://redirect.github.com/docker/metadata-action/pull/685">docker/metadata-action#685</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/metadata-action/compare/v6.1.0...v6.2.0">https://github.com/docker/metadata-action/compare/v6.1.0...v6.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/metadata-action/commit/dc802804100637a589fabce1cb79ff13a1411302"><code>dc80280</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/696">#696</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/metadata-action/commit/2b9fe830efc58cb7b0fab7c94300b1afa01864db"><code>2b9fe83</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/metadata-action/commit/8128ce30ab370fd360c8423698dcc077f2db8087"><code>8128ce3</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.91.0 to
0.92.0</li>
<li><a
href="https://github.com/docker/metadata-action/commit/1d1c89551edb081628e818368680beffb2bbccee"><code>1d1c895</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/695">#695</a>
from docker/dependabot/npm_and_yarn/semver-7.8.5</li>
<li><a
href="https://github.com/docker/metadata-action/commit/7f0c2dd4c83ea6258f78bf2fc6a02908417518ad"><code>7f0c2dd</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/694">#694</a>
from docker/dependabot/npm_and_yarn/sigstore-4.1.1</li>
<li><a
href="https://github.com/docker/metadata-action/commit/025f8c5c8167edab853571a387d8e80ccc1e91ed"><code>025f8c5</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/metadata-action/commit/e98d63c3081990566e174100a3afaa97aefbbcf3"><code>e98d63c</code></a>
chore(deps): Bump semver from 7.8.1 to 7.8.5</li>
<li><a
href="https://github.com/docker/metadata-action/commit/37d93799507b94cf1c1885efd7278d52a0fb806a"><code>37d9379</code></a>
chore(deps): Bump sigstore from 4.1.0 to 4.1.1</li>
<li><a
href="https://github.com/docker/metadata-action/commit/a1b80728476a956a25c5eeaff91c4dc46e7ac1bc"><code>a1b8072</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/690">#690</a>
from docker/dependabot/npm_and_yarn/sigstore/core-3.2.1</li>
<li><a
href="https://github.com/docker/metadata-action/commit/e0e338106d6ae0da5b44537049a34620b3559a5c"><code>e0e3381</code></a>
[dependabot skip] chore: update generated content</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/metadata-action/compare/80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9...dc802804100637a589fabce1cb79ff13a1411302">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/setup-buildx-action` from 4.1.0 to 4.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/setup-buildx-action/releases">docker/setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.2.0</h2>
<ul>
<li>Preserve names in esbuild bundle by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/572">docker/setup-buildx-action#572</a></li>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/551">docker/setup-buildx-action#551</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.90.0 to 0.92.0 in
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/557">docker/setup-buildx-action#557</a>
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/580">docker/setup-buildx-action#580</a></li>
<li>Bump <code>@​sigstore/core</code> from 3.1.0 to 3.2.1 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/573">docker/setup-buildx-action#573</a></li>
<li>Bump <code>@​sigstore/verify</code> from 3.1.0 to 3.1.1 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/576">docker/setup-buildx-action#576</a></li>
<li>Bump js-yaml from 4.1.1 to 5.2.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/562">docker/setup-buildx-action#562</a></li>
<li>Bump sigstore from 4.1.0 to 4.1.1 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/577">docker/setup-buildx-action#577</a></li>
<li>Bump tmp from 0.2.5 to 0.2.7 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/556">docker/setup-buildx-action#556</a></li>
<li>Bump undici from 6.25.0 to 6.27.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/570">docker/setup-buildx-action#570</a></li>
<li>Bump vite from 7.3.2 to 7.3.6 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/569">docker/setup-buildx-action#569</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/setup-buildx-action/compare/v4.1.0...v4.2.0">https://github.com/docker/setup-buildx-action/compare/v4.1.0...v4.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/bb05f3f5519dd87d3ba754cc423b652a5edd6d2c"><code>bb05f3f</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/580">#580</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/321c814cb51fbe4af8eca00249525cc0973ea66f"><code>321c814</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/b9a36ef79ba42cfc611885a1e8c388fbf8b8cb3f"><code>b9a36ef</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.91.0 to
0.92.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/ebeab241289497cd564ac98b3cfc9e64607bb276"><code>ebeab24</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/570">#570</a>
from docker/dependabot/npm_and_yarn/undici-6.27.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/5c7b8ae78cec97a3215d4d86679b1d072eaa80cb"><code>5c7b8ae</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/037e618cd98e95e81525b15ff0e9c96f507e6a0e"><code>037e618</code></a>
build(deps): bump undici from 6.25.0 to 6.27.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/66080e5802281ec2e72b7f3108915643e702db85"><code>66080e5</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/577">#577</a>
from docker/dependabot/npm_and_yarn/sigstore-4.1.1</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/409aef0aa3f48f0a742e7dec4e0e04ab19afe93c"><code>409aef0</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/562">#562</a>
from docker/dependabot/npm_and_yarn/js-yaml-4.2.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/49c6e42949280fa0d70fb327633591be54efbfb6"><code>49c6e42</code></a>
build(deps): bump sigstore from 4.1.0 to 4.1.1</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/2211273e8121ecf9ecb7d6c7c0fcd55526d530c7"><code>2211273</code></a>
[dependabot skip] chore: update generated content</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/setup-buildx-action/compare/d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5...bb05f3f5519dd87d3ba754cc423b652a5edd6d2c">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/build-push-action` from 7.2.0 to 7.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.3.0</h2>
<ul>
<li>Preserve names in esbuild bundle by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/build-push-action/pull/1567">docker/build-push-action#1567</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.90.0 to 0.92.0 in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1545">docker/build-push-action#1545</a>
<a
href="https://redirect.github.com/docker/build-push-action/pull/1572">docker/build-push-action#1572</a></li>
<li>Bump <code>@​sigstore/core</code> from 3.1.0 to 3.2.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1568">docker/build-push-action#1568</a></li>
<li>Bump js-yaml from 4.1.1 to 4.3.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1566">docker/build-push-action#1566</a></li>
<li>Bump tmp from 0.2.5 to 0.2.7 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1547">docker/build-push-action#1547</a></li>
<li>Bump undici from 6.24.1 to 6.27.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1564">docker/build-push-action#1564</a></li>
<li>Bump vite from 7.3.2 to 7.3.6 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1563">docker/build-push-action#1563</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.2.0...v7.3.0">https://github.com/docker/build-push-action/compare/v7.2.0...v7.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/build-push-action/commit/53b7df96c91f9c12dcc8a07bcb9ccacbed38856a"><code>53b7df9</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1572">#1572</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/154298c1ca89be1c0e019084f0611ddca621aafc"><code>154298c</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/cb1238b9c9eb453d106b4e4142a5bd9cde710040"><code>cb1238b</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.91.0 to
0.92.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/24f845d5cbe75d2d350a984fd0e18cb7a3f29c1c"><code>24f845d</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1566">#1566</a>
from docker/dependabot/npm_and_yarn/js-yaml-4.2.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/9c6973007b52c322651c38915d5e8824cea95c50"><code>9c69730</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/bc3a3a5f72a6dca16c2c2468d1dfc55ee66d2193"><code>bc3a3a5</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1574">#1574</a>
from docker/dependabot/github_actions/aws-actions/co...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/a82c504a2387bb8bedc50072f9c554ae2a7dab5d"><code>a82c504</code></a>
chore(deps): Bump js-yaml from 4.1.1 to 4.3.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/0285a75190c039d6dac52b7711abcef3f5d8f6f6"><code>0285a75</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1573">#1573</a>
from docker/dependabot/github_actions/actions/cache-...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/c6ad2a3f9644680619de938b97c8a10a87b2a88d"><code>c6ad2a3</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1575">#1575</a>
from docker/dependabot/github_actions/actions/checko...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/d37484fb9737c5442a257e2f0ae5a8d756ed7d92"><code>d37484f</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1564">#1564</a>
from docker/dependabot/npm_and_yarn/undici-6.27.0</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/build-push-action/compare/f9f3042f7e2789586610d6e8b85c8f03e5195baf...53b7df96c91f9c12dcc8a07bcb9ccacbed38856a">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 8.2.0 to 8.3.2
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/11f9893b081a58869d3b5fccaea48c9e9e46f990"><code>11f9893</code></a>
chore: roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/948">#948</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f79855603231e1609d02bec6956bd0e05cbc46b5"><code>f798556</code></a>
docs: update version references to v8.3.1 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/946">#946</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e80544d808267c93733c3fd1e2c8c65e0c8707d6"><code>e80544d</code></a>
chore: update known checksums for 0.11.28 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/947">#947</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f98e06938123ccabd21905ea5d0069192241f9f1"><code>f98e069</code></a>
Change update-docs PR labels from 'update-docs' to 'documentation' (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/945">#945</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cd462639a967553a16241af35461402a96978d48"><code>cd46263</code></a>
chore: update known checksums for 0.11.27 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/944">#944</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/11245c7e122cd1c2297e8115d1e43fe1570f6270"><code>11245c7</code></a>
docs: update version references to v8.3.0 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/939">#939</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/d31148d669074a8d0a63714ba94f3201e7020bc3"><code>d31148d</code></a>
Strip environment markers from detected uv dependency pins (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/938">#938</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/17c398959b4611a88929fabb5c563a8e43a0ff60"><code>17c3989</code></a>
Fix cache keys for Python version ranges (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/937">#937</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/3cc3c11fdf511cab39136b7c946d973d4ad0df20"><code>3cc3c11</code></a>
chore(deps): roll up Dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/936">#936</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/9225f843d7a9f80a757cf25ef48901fda69ba4bc"><code>9225f84</code></a>
chore(deps): bump release-drafter/release-drafter from 7.3.1 to 7.4.0
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/924">#924</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/fac544c07dec837d0ccb6301d7b5580bf5edae39...11f9893b081a58869d3b5fccaea48c9e9e46f990">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-node` from 6.4.0 to 7.0.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Add cache-primary-key and cache-matched-key as outputs by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1577">actions/setup-node#1577</a></li>
<li>Migrate to ESM and upgrade dependencies by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1574">actions/setup-node#1574</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Remove dummy NODE_AUTH_TOKEN export by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1558">actions/setup-node#1558</a></li>
<li>Only use <code>mirrorToken</code> in <code>getManifest</code> if
it's provided by <a
href="https://github.com/deiga"><code>@​deiga</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
</ul>
<h3>Documentation updates:</h3>
<ul>
<li>Add documentation for publishing to npm with Trusted Publisher
(OIDC) by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li>docs: Update restore-only cache documentation by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1550">actions/setup-node#1550</a></li>
<li>docs: Update caching recommendations to mitigate cache poisoning
risks by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1567">actions/setup-node#1567</a></li>
</ul>
<h3>Dependency update:</h3>
<ul>
<li>Upgrade <code>@​actions/cache</code> to 5.1.0, log cache write
denied by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li><a href="https://github.com/deiga"><code>@​deiga</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
<li><a href="https://github.com/jasongin"><code>@​jasongin</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v7.0.0">https://github.com/actions/setup-node/compare/v6...v7.0.0</a></p>
<h2>v6.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@​actions/cache</code> to 5.1.0 and add security
overrides for undici and fast-xml-parser by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1579">actions/setup-node#1579</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0">https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/820762786026740c76f36085b0efc47a31fe5020"><code>8207627</code></a>
Migrate to ESM and upgrade dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1574">#1574</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/04be95cf3511ea51ebf9f224ddfb99cc7ab87cd4"><code>04be95c</code></a>
Add cache-primary-key and cache-matched-key as outputs (<a
href="https://redirect.github.com/actions/setup-node/issues/1577">#1577</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/7c2c68d20d402ed6a201ada70a81341941093140"><code>7c2c68d</code></a>
docs: Update caching recommendations to mitigate cache poisoning risks
(<a
href="https://redirect.github.com/actions/setup-node/issues/1567">#1567</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/6a61c0375d66246de94630495909f12cf8dac84d"><code>6a61c03</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/setup-node/issues/1569">#1569</a>
from jasongin/update-actions-cache-5.1.0</li>
<li><a
href="https://github.com/actions/setup-node/commit/30eb73b41ded577900c1ebf968ef95cdf8f7434f"><code>30eb73b</code></a>
Resolve high-severity audit issues</li>
<li><a
href="https://github.com/actions/setup-node/commit/4e1a87a501d0302f99e30e2748568adcb388d09f"><code>4e1a87a</code></a>
Update dist</li>
<li><a
href="https://github.com/actions/setup-node/commit/360237f0c01778d0c17291f75c56d6feae4f7574"><code>360237f</code></a>
Strict equality</li>
<li><a
href="https://github.com/actions/setup-node/commit/4f8aac5beb2f0854bc79651567a18c67eb0b9de3"><code>4f8aac5</code></a>
Bump <code>@​actions/cache</code> to 5.1.0, log cache write denied</li>
<li><a
href="https://github.com/actions/setup-node/commit/f4a67bbeca970f103397d3d2b9462cf787cd2980"><code>f4a67bb</code></a>
Only use <code>mirrorToken</code> in <code>getManifest</code> if it's
provided (<a
href="https://redirect.github.com/actions/setup-node/issues/1548">#1548</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/0355742c943ddb13ca8a6b700f824231caa91e75"><code>0355742</code></a>
Remove dummy NODE_AUTH_TOKEN export (<a
href="https://redirect.github.com/actions/setup-node/issues/1558">#1558</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e...820762786026740c76f36085b0efc47a31fe5020">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/init` from 4.36.2 to 4.37.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/init's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.0</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>v4.36.3</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/init's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>4.35.5 - 15 May 2026</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
<h2>4.35.4 - 07 May 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/99df26d4f13ea111d4ec1a7dddef6063f76b97e9"><code>99df26d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3996">#3996</a>
from github/update-v4.37.0-c7c896d71</li>
<li><a
href="https://github.com/github/codeql-action/commit/31c27074fda95256cda077009907f8a6022dd7c0"><code>31c2707</code></a>
Add changenote for <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/72df2181aac054d1f4b44264399d2aac12cf11c6"><code>72df218</code></a>
Update changelog for v4.37.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/c7c896d71b3055d36f2aff93b16bcc6c69923b91"><code>c7c896d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3995">#3995</a>
from github/update-bundle/codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/3f34ff0ea3f5153c96071437b7cbf71ea3757146"><code>3f34ff0</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/43bec09f1dc368b430cab4b5d69799bc904079d1"><code>43bec09</code></a>
Update default bundle to codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/f58f0d11ebf5dedd870fab2f999275f7602cfa46"><code>f58f0d1</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a>
from github/mbg/repo-props/config-file-shorthands</li>
<li><a
href="https://github.com/github/codeql-action/commit/7dc37cbb5b3e37f0e1cd1f18b61e0ea849898fb8"><code>7dc37cb</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/repo-props/config-file-sh...</li>
<li><a
href="https://github.com/github/codeql-action/commit/8e22350a7e28c34c82a5a499fc241923301c2c4f"><code>8e22350</code></a>
Thread <code>ActionState</code> to <code>initConfig</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/69c9e8c7d918cf2fee13b8b72fdde15883ff155b"><code>69c9e8c</code></a>
Mark some <code>status-report</code> imports as <code>type</code>-only
to avoid circular dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/autobuild` from 4.36.2 to 4.37.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/autobuild's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.0</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>v4.36.3</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/autobuild's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>4.35.5 - 15 May 2026</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
<h2>4.35.4 - 07 May 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/99df26d4f13ea111d4ec1a7dddef6063f76b97e9"><code>99df26d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3996">#3996</a>
from github/update-v4.37.0-c7c896d71</li>
<li><a
href="https://github.com/github/codeql-action/commit/31c27074fda95256cda077009907f8a6022dd7c0"><code>31c2707</code></a>
Add changenote for <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/72df2181aac054d1f4b44264399d2aac12cf11c6"><code>72df218</code></a>
Update changelog for v4.37.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/c7c896d71b3055d36f2aff93b16bcc6c69923b91"><code>c7c896d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3995">#3995</a>
from github/update-bundle/codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/3f34ff0ea3f5153c96071437b7cbf71ea3757146"><code>3f34ff0</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/43bec09f1dc368b430cab4b5d69799bc904079d1"><code>43bec09</code></a>
Update default bundle to codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/f58f0d11ebf5dedd870fab2f999275f7602cfa46"><code>f58f0d1</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a>
from github/mbg/repo-props/config-file-shorthands</li>
<li><a
href="https://github.com/github/codeql-action/commit/7dc37cbb5b3e37f0e1cd1f18b61e0ea849898fb8"><code>7dc37cb</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/repo-props/config-file-sh...</li>
<li><a
href="https://github.com/github/codeql-action/commit/8e22350a7e28c34c82a5a499fc241923301c2c4f"><code>8e22350</code></a>
Thread <code>ActionState</code> to <code>initConfig</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/69c9e8c7d918cf2fee13b8b72fdde15883ff155b"><code>69c9e8c</code></a>
Mark some <code>status-report</code> imports as <code>type</code>-only
to avoid circular dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action/analyze` from 4.36.2 to 4.37.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action/analyze's
releases</a>.</em></p>
<blockquote>
<h2>v4.37.0</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>v4.36.3</h2>
<p>No user facing changes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action/analyze's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.37.1 - 16 Jul 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.20.6 and earlier. These versions of
CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise
Server 3.16, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3956">#3956</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.1">2.26.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/4019">#4019</a></li>
</ul>
<h2>4.37.0 - 08 Jul 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.0">2.26.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3995">#3995</a></li>
<li>In addition to the existing input format, the
<code>config-file</code> input for the <code>codeql-action/init</code>
step will soon support a new <code>[owner/]repo[@ref][:path]</code>
format. All components except the repository name are optional. If
omitted, <code>owner</code> defaults to the same owner as the repository
the analysis is running for, <code>ref</code> to <code>main</code>, and
<code>path</code> to <code>.github/codeql-action.yaml</code>. Support
for this format ships in this version of the CodeQL Action, but will
only be enabled over the coming weeks. <a
href="https://redirect.github.com/github/codeql-action/pull/3973">#3973</a></li>
</ul>
<h2>4.36.3 - 01 Jul 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>4.35.5 - 15 May 2026</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
<h2>4.35.4 - 07 May 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/99df26d4f13ea111d4ec1a7dddef6063f76b97e9"><code>99df26d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3996">#3996</a>
from github/update-v4.37.0-c7c896d71</li>
<li><a
href="https://github.com/github/codeql-action/commit/31c27074fda95256cda077009907f8a6022dd7c0"><code>31c2707</code></a>
Add changenote for <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a></li>
<li><a
href="https://github.com/github/codeql-action/commit/72df2181aac054d1f4b44264399d2aac12cf11c6"><code>72df218</code></a>
Update changelog for v4.37.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/c7c896d71b3055d36f2aff93b16bcc6c69923b91"><code>c7c896d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3995">#3995</a>
from github/update-bundle/codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/3f34ff0ea3f5153c96071437b7cbf71ea3757146"><code>3f34ff0</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/43bec09f1dc368b430cab4b5d69799bc904079d1"><code>43bec09</code></a>
Update default bundle to codeql-bundle-v2.26.0</li>
<li><a
href="https://github.com/github/codeql-action/commit/f58f0d11ebf5dedd870fab2f999275f7602cfa46"><code>f58f0d1</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3973">#3973</a>
from github/mbg/repo-props/config-file-shorthands</li>
<li><a
href="https://github.com/github/codeql-action/commit/7dc37cbb5b3e37f0e1cd1f18b61e0ea849898fb8"><code>7dc37cb</code></a>
Merge remote-tracking branch 'origin/main' into
mbg/repo-props/config-file-sh...</li>
<li><a
href="https://github.com/github/codeql-action/commit/8e22350a7e28c34c82a5a499fc241923301c2c4f"><code>8e22350</code></a>
Thread <code>ActionState</code> to <code>initConfig</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/69c9e8c7d918cf2fee13b8b72fdde15883ff155b"><code>69c9e8c</code></a>
Mark some <code>status-report</code> imports as <code>type</code>-only
to avoid circular dependencies</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9">compare
view</a></li>
</ul>
</details>
<br />

Updates `dorny/paths-filter` from 4.0.1 to 4.0.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/releases">dorny/paths-filter's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>fix warning message by <a
href="https://github.com/cgundy"><code>@​cgundy</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/282">dorny/paths-filter#282</a></li>
<li>chore: fix GitHub spelling in logs by <a
href="https://github.com/squat"><code>@​squat</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/278">dorny/paths-filter#278</a></li>
<li>fix: use rev-parse instead of branch --show-current for older git
compat by <a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/303">dorny/paths-filter#303</a></li>
<li>fix: work around git dubious ownership errors in container jobs by
<a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/317">dorny/paths-filter#317</a></li>
<li>docs: update changelog for v4.0.2 by <a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/318">dorny/paths-filter#318</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/cgundy"><code>@​cgundy</code></a> made
their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/282">dorny/paths-filter#282</a></li>
<li><a href="https://github.com/squat"><code>@​squat</code></a> made
their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/278">dorny/paths-filter#278</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v4.0.1...v4.0.2">https://github.com/dorny/paths-filter/compare/v4.0.1...v4.0.2</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md">dorny/paths-filter's
changelog</a>.</em></p>
<blockquote>
<h2>v4.0.2</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/317">Work
around git dubious ownership errors in container jobs</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/303">Use
rev-parse instead of branch --show-current for older git compat</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/282">Fix
warning message</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/dorny/paths-filter/commit/7b450fff21473bca461d4b92ce414b9d0420d706"><code>7b450ff</code></a>
docs: update changelog for v4.0.2 (<a
href="https://redirect.github.com/dorny/paths-filter/issues/318">#318</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/928037783a71f24983ea250c6e55290c1b2de54f"><code>9280377</code></a>
fix: work around git dubious ownership errors in container jobs (<a
href="https://redirect.github.com/dorny/paths-filter/issues/317">#317</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/f3ceefdc7ef57bc2d8560787d4b6c33e44044cec"><code>f3ceefd</code></a>
fix: use rev-parse instead of branch --show-current for older git compat
(<a
href="https://redirect.github.com/dorny/paths-filter/issues/303">#303</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/61f87a10cd2c304679af17bb73ef192addf33c1c"><code>61f87a1</code></a>
chore: fix GitHub spelling in logs (<a
href="https://redirect.github.com/dorny/paths-filter/issues/278">#278</a>)</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/b82ff81ffbe6fb4b636bb5b47e37fd8d12b32632"><code>b82ff81</code></a>
fix warning message (<a
href="https://redirect.github.com/dorny/paths-filter/issues/282">#282</a>)</li>
<li>See full diff in <a
href="https://github.com/dorny/paths-filter/compare/v4.0.1...v4.0.2">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-19 02:51:53 -04:00
dependabot[bot] ceaccfd29f Bump prek from 0.4.8 to 0.4.9 in the python-deps group (#1116)
Bumps the python-deps group with 1 update:
[prek](https://github.com/j178/prek).

Updates `prek` from 0.4.8 to 0.4.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.9</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-11.</p>
<p>Note: This release changes the repository identity schema stored in
cached hook environments. Existing
hook environments will be invalidated, and prek will reinstall them
automatically when needed.</p>
<h3>Enhancements</h3>
<ul>
<li>Preserve additional dependency order (<a
href="https://redirect.github.com/j178/prek/pull/2311">#2311</a>)</li>
<li>Remove parallel Ruby gem installation (<a
href="https://redirect.github.com/j178/prek/pull/2307">#2307</a>)</li>
<li>Warn for missing update repositories (<a
href="https://redirect.github.com/j178/prek/pull/2316">#2316</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix mixed workspace selectors (<a
href="https://redirect.github.com/j178/prek/pull/2306">#2306</a>)</li>
<li>Fix try-repo local path resolution (<a
href="https://redirect.github.com/j178/prek/pull/2310">#2310</a>)</li>
<li>Use resolved gem executable (<a
href="https://redirect.github.com/j178/prek/pull/2308">#2308</a>)</li>
<li>Validate complete XML documents in check-xml (<a
href="https://redirect.github.com/j178/prek/pull/2312">#2312</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.9</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.9/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.9/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.4.9</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.9/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.9/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.9</h2>
<p>Released on 2026-07-11.</p>
<p>Note: This release changes the repository identity schema stored in
cached hook environments. Existing
hook environments will be invalidated, and prek will reinstall them
automatically when needed.</p>
<h3>Enhancements</h3>
<ul>
<li>Preserve additional dependency order (<a
href="https://redirect.github.com/j178/prek/pull/2311">#2311</a>)</li>
<li>Remove parallel Ruby gem installation (<a
href="https://redirect.github.com/j178/prek/pull/2307">#2307</a>)</li>
<li>Warn for missing update repositories (<a
href="https://redirect.github.com/j178/prek/pull/2316">#2316</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix mixed workspace selectors (<a
href="https://redirect.github.com/j178/prek/pull/2306">#2306</a>)</li>
<li>Fix try-repo local path resolution (<a
href="https://redirect.github.com/j178/prek/pull/2310">#2310</a>)</li>
<li>Use resolved gem executable (<a
href="https://redirect.github.com/j178/prek/pull/2308">#2308</a>)</li>
<li>Validate complete XML documents in check-xml (<a
href="https://redirect.github.com/j178/prek/pull/2312">#2312</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/42b79a57f275ffe3e7fc3ad32fdf2754416779d5"><code>42b79a5</code></a>
Bump version to 0.4.9 (<a
href="https://redirect.github.com/j178/prek/issues/2318">#2318</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ecbd9dabab540d1d964a66276f70ff084c5aa14d"><code>ecbd9da</code></a>
Extract executable helpers (<a
href="https://redirect.github.com/j178/prek/issues/2317">#2317</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/25ee3c2d16086291673fed03dcc9beff09b1e03a"><code>25ee3c2</code></a>
Validate complete XML documents in check-xml (<a
href="https://redirect.github.com/j178/prek/issues/2312">#2312</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/876f7610dcc6f50dd6b85842cc5f01b36e7dc93f"><code>876f761</code></a>
Warn for missing update repositories (<a
href="https://redirect.github.com/j178/prek/issues/2316">#2316</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/61cbcbf91b0c6478afcc16a2de8fb51269c94d52"><code>61cbcbf</code></a>
Preserve additional dependency order (<a
href="https://redirect.github.com/j178/prek/issues/2311">#2311</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/4b006eba7adf4515f686647060fa852fd994359d"><code>4b006eb</code></a>
Update Rust to 1.97 (<a
href="https://redirect.github.com/j178/prek/issues/2313">#2313</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/40f6609fd824151af0cb85ca994a1cd2f6ea5d87"><code>40f6609</code></a>
Fix try-repo local path resolution (<a
href="https://redirect.github.com/j178/prek/issues/2310">#2310</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3795e9964883a2e57ed9b783345ac1cf654160a3"><code>3795e99</code></a>
Use resolved gem executable (<a
href="https://redirect.github.com/j178/prek/issues/2308">#2308</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/de7ac64173f48f91ad746e1ebe7e8b4cd1a99d11"><code>de7ac64</code></a>
Remove parallel Ruby gem installation (<a
href="https://redirect.github.com/j178/prek/issues/2307">#2307</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/434e791453272d9badef7c5c6295342d541496ac"><code>434e791</code></a>
Fix mixed workspace selectors (<a
href="https://redirect.github.com/j178/prek/issues/2306">#2306</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.8...v0.4.9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prek&package-manager=uv&previous-version=0.4.8&new-version=0.4.9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-15 10:28:00 -04:00
CaliBrain 6bab9989ab fix: fetch tracker .torrent links once per add and surface fetch failures (#1115)
## Summary

Fixes Prowlarr torrent downloads that fail with `Could not determine
torrent hash
from URL` when the result has no magnet link and no infohash (e.g.
MyAnonaMouse),
where fetching the .torrent from Prowlarr's proxy download link is the
only path.

Two problems compounded here:

1. **Every add attempt fetched the download link twice.**
`find_existing()`
prefetched the .torrent to compute a dedup hash, discarded the result,
and
`add_download()` fetched the same URL again seconds later. Private
tracker
links behind Prowlarr's proxy can be slow, rate-limited, or effectively
single-use, so the second hit could fail even when the link itself was
valid —
   which is why the reporter's manual fetch of the same URL succeeded.
2. **The real failure reason was invisible.** When the fetch failed
(e.g.
Prowlarr returning HTTP 500 because the tracker rejected the request —
see the
2026-07-07 MAM report on #476, which turned out to be a MAM IP-settings
problem), the reason was logged at DEBUG only and the user saw the
misleading
   generic hash error.

## What changed

- `extract_torrent_info()` now reuses a recent successful fetch of the
same URL
(short-TTL in-memory cache, successes only), so one add attempt hits the
tracker download link exactly once across `find_existing()` +
`add_download()`.
All four torrent clients (qBittorrent, Deluge, Transmission, rTorrent)
share
  this path and benefit. Failures are never cached, so retries refetch.
- `TorrentInfo` gains a `fetch_error` field. qBittorrent and rTorrent
append it
to the hash error (`... (torrent file fetch failed: 500 Server Error
...)`),
Deluge to its "Failed to fetch torrent file" error. The enriched message
still
contains the exact substring the #1109 expired-link refresh hook matches
on,
  so the refresh-and-retry path keeps working.
- Torrent fetch failures are logged at WARNING instead of DEBUG, so
non-debug
  logs show the cause.

## Validation

- `uv run pytest tests/prowlarr tests/download -q` — 498 passed
- `uv run pytest tests/newznab tests/audiobookbay -q` — 147 passed
- `uv run ruff check` / `ruff format --check` on all changed files
- New tests: fetch-cache reuse, failure-not-cached + reason capture,
expected-hash fallback on failed/hashless fetches, TTL expiry,
magnet-redirect
  reuse, and the enriched qBittorrent error message.

Fixes #1111
2026-07-14 16:21:31 -04:00
Aidan AbbottandAidan Abbott f8d3f990ca fix: Prowlarr expired download link refresh (#1109)
## Summary

Fixes Prowlarr downloads that fail after a queued torrent result’s
tracker download link expires.

Prowlarr torrent results can expose a `downloadUrl` that is only a
short-lived proxy to the upstream tracker. Some trackers, including MAM,
include expiring credentials in that URL. Shelfmark was persisting that
URL as retry data and later treating it as durable. If the in-memory
Prowlarr cache was gone, or if qBittorrent tried to add a stale URL,
Shelfmark could fail with a misleading torrent-hash error instead of
refreshing the release.

## What changed

- Stop persisting Prowlarr `downloadUrl` values as durable retry data.
- Persist only source context needed to refresh the release later.
- On a Prowlarr cache miss, re-query Prowlarr using the queued task
context.
- Accept refreshed results only when the stable identity matches the
original release:
  - `guid == task.task_id`
  - or `infoUrl == task.task_id`
- Cache the fresh raw Prowlarr result and build the download request
from its current `downloadUrl` / `magnetUrl`.
- If qBittorrent add fails with `Could not determine torrent hash from
URL`, remove the stale cached Prowlarr result, refresh once, and retry
with the fresh URL.
- Preserve existing magnet handling: torrent results continue to use
`magnetUrl` first, so the refresh path only targets Prowlarr proxy
`downloadUrl` values that can expire.
- Improve the user-facing failure when refresh cannot find the same
release:
`The indexer download link expired and the release could not be
refreshed. Search again for a fresh result.`

## Why this approach

The important constraint is avoiding accidental downloads of a different
edition or format after the original tracker link expires. Re-running a
search by title can return many plausible results, so the refresh path
deliberately requires an exact stable identity match before using any
new URL.

This treats Prowlarr `downloadUrl` as a short-lived hint, while still
allowing retries to recover when Prowlarr can find the same release
again. The one-shot retry after qBittorrent add failure handles the case
where Shelfmark still has a cached Prowlarr result, but that cached
result contains an expired proxy URL.

The refresh hook is source-specific and defaults to no-op for other
external download handlers, so Newznab and other sources keep their
existing retry behavior.

## Bug

Fixes #1012

Context:
https://github.com/calibrain/shelfmark/issues/1012#issuecomment-4917148398

## Validation

- `uv run pytest tests/prowlarr -q`
- `uv run pytest tests/download/test_orchestrator_user_output_mode.py
-q`
- `uv run pytest tests/newznab/test_handler.py
tests/audiobookbay/test_handler.py -q`
- `uv run ruff check shelfmark/core/models.py
shelfmark/download/orchestrator.py
shelfmark/download/clients/base_handler.py
shelfmark/release_sources/prowlarr/handler.py
tests/prowlarr/test_handler.py
tests/prowlarr/test_integration_handler.py
tests/prowlarr/test_failure_scenarios.py tests/prowlarr/test_source.py
tests/download/test_orchestrator_user_output_mode.py`
- after resolving conflicts with latest `main`: `uv run pytest
tests/prowlarr -q`
- after resolving conflicts with latest `main`: `uv run ruff check
shelfmark/release_sources/prowlarr/handler.py`
- after resolving conflicts with latest `main`: `uv run pytest
tests/prowlarr/test_handler.py tests/prowlarr/test_source.py -q`

Co-authored-by: Aidan Abbott <aidanabbott@Aidans-MacBook-Pro.local>
2026-07-14 14:22:29 -04:00
dependabot[bot] 30d7f228be Bump the python-deps group with 5 updates (#1114)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-14 14:07:49 -04:00
adman234 b291df5cc9 fix(prowlarr): prevent silent loss of indexer seed limits on transient Prowlarr API failures (#1110)
# fix(prowlarr): prevent silent loss of indexer seed limits

Related to #795, though not a fix for that specific (closed) report —
see note below.

## Problem

With "Use Prowlarr seed preferences" enabled, ~5–10% of torrent grabs
are added to the download client without their configured share limits
and seed indefinitely (∞ ETA in qBittorrent).

Seed limits are resolved once at search time.
`get_indexer_seed_settings()` builds on `get_indexers()`, which swallows
all API errors and returns `[]`. A transient failure of the
`/api/v1/indexer` call therefore produces an empty settings dict that is
indistinguishable from "no limits configured", while the search itself
(separate HTTP calls) still succeeds. Every result from that search is
cached without `configuredSeedTimeMinutes`; grabbing one sends the
torrent to the client with no limits.

Compounding factors: `cache_release()` is last-write-wins by GUID, so
one degraded search can strip enrichment from a previously good cache
entry; and the retry fields persisted at queue time snapshot the same
missing values, so retries reproduce the failure.

## Changes

- **`api.py`** — `get_indexers()` / `get_enabled_indexers_detailed()`
gain a keyword-only `raise_on_error` (default `False`, existing behavior
unchanged). `get_indexer_seed_settings()` uses it, so fetch failures now
propagate and an empty dict strictly means "nothing configured".
- **`source.py`** — searches fetch settings via
`_fetch_indexer_seed_settings()`, which maintains a module-level
last-known-good copy (merged on each success) and falls back to it with
a warning when the fetch fails. After one successful fetch, results can
no longer be cached un-enriched.
- **`handler.py`** — grab-time safety net in `_resolve_download()`: if
seed preferences are enabled, the release is a torrent, and no
configured limits are present in the cached result, the handler
re-resolves the limits from Prowlarr for that indexer
(`restrict_to=[indexerId]`) before adding to the client. If limits still
can't be resolved, a warning is logged so the condition is visible
instead of silent.
- **Tests** — regression coverage: last-known-good fallback (success
updates cache, failure falls back, failure with no history returns
empty, fallback copy is mutation-safe) and grab-time fallback (used when
enrichment is missing, tolerates Prowlarr being down, skipped when
enrichment is present). Existing test stubs for
`get_enabled_indexers_detailed` updated to accept the new kwarg.

## Testing

- `uv run pytest tests/prowlarr/test_handler.py
tests/prowlarr/test_source.py
tests/prowlarr/test_integration_handler.py` — 93 passed, 2 skipped
(Python 3.14.4)
- Full `tests/prowlarr` run has 11 pre-existing failures on this
environment (Windows path-separator assertions in the
qBittorrent/NZBGet/SABnzbd/Transmission client tests, e.g.
`/downloads/x` vs `\downloads\x`); confirmed these also fail on
unpatched `main` and are unrelated to this change
- `uv run ruff check` / `ruff format --check` — clean on touched files
- `uv run basedpyright` — 0 errors on touched files

No behavior change when `PROWLARR_USE_SEED_PREFERENCES` is disabled; the
fallback path only activates when the preference is on and enrichment is
missing for a torrent.

---

**Note on #795:** this PR references #795 for background context on the
seed-limits feature, but it does not fix that report — #795 was about
seed limits not being converted/applied at all (a units mismatch), and
was already fixed by #946 / #959. This PR fixes a separate,
still-present bug: `get_indexers()` silently swallowing transient API
errors, which intermittently drops seed limits even when the feature is
otherwise working correctly.
2026-07-09 23:25:29 -04:00
CaliBrain 9b1d4322b7 fix: resolve remaining "Could not determine torrent hash from URL" failures (#1012) (#1108) 2026-07-08 14:20:31 -04:00
dependabot[bot] d7a21ea248 Bump the python-deps group with 2 updates (#1107)
Bumps the python-deps group with 2 updates:
[apprise](https://github.com/caronc/apprise) and
[prek](https://github.com/j178/prek).

Updates `apprise` from 1.11.0 to 1.12.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/caronc/apprise/releases">apprise's
releases</a>.</em></p>
<blockquote>
<h2>Release v1.12.0</h2>
<h2>What's Changed</h2>
<p>Apprise now supports more than 150 services! HTML -&gt; Markdown
Support now built into Apprise. But otherwise this is just a monthly
release bundling all of the bugfixes, enhancments and new services that
have accumulated since the last. <a
href="https://appriseit.com">https://appriseit.com</a> under went a few
renovations of it's own; new icons; a much improved and more useful <a
href="https://appriseit.com/url-builder/">URL Builder</a> and and
improved the search functionality on <a
href="https://appriseit.com/services/">Service List section</a>.</p>
<h3>📣 New Notification Services:</h3>
<ul>
<li>Added Stackfield support in <a
href="https://redirect.github.com/caronc/apprise/pull/1651">caronc/apprise#1651</a></li>
<li>Added PushWard Support by <a
href="https://github.com/mac-lucky"><code>@​mac-lucky</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1643">caronc/apprise#1643</a></li>
<li>MailerSend Support added in <a
href="https://redirect.github.com/caronc/apprise/pull/1646">caronc/apprise#1646</a></li>
<li>Added Notifyer Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1648">caronc/apprise#1648</a></li>
<li>Added support for 800.com in <a
href="https://redirect.github.com/caronc/apprise/pull/1647">caronc/apprise#1647</a></li>
<li>Added Kook Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1654">caronc/apprise#1654</a></li>
<li>Serwer SMS Support Added in <a
href="https://redirect.github.com/caronc/apprise/pull/1657">caronc/apprise#1657</a></li>
<li>Added SMSC Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1658">caronc/apprise#1658</a></li>
<li>Add Flowtriq notification service for DDoS alerting by <a
href="https://github.com/jacob-masse"><code>@​jacob-masse</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1644">caronc/apprise#1644</a></li>
</ul>
<h3>🐞  Bugfixes</h3>
<ul>
<li>Fix Slack webhook botname/default identity behavior by <a
href="https://github.com/vgopalakPrgs"><code>@​vgopalakPrgs</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1634">caronc/apprise#1634</a></li>
<li>Fix OneSignal url() doubling @/# target prefixes on reload by <a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1649">caronc/apprise#1649</a></li>
<li>Verify SMTP TLS certificates for SMTPS and STARTTLS connections by
<a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1640">caronc/apprise#1640</a></li>
<li>name= support fixed on http:// attachments in <a
href="https://redirect.github.com/caronc/apprise/pull/1645">caronc/apprise#1645</a></li>
</ul>
<h3>💡 Features</h3>
<ul>
<li>🔥 HTML to Markdown support in <a
href="https://redirect.github.com/caronc/apprise/pull/1638">caronc/apprise#1638</a></li>
<li>regex improvements to token parsing in <a
href="https://redirect.github.com/caronc/apprise/pull/1650">caronc/apprise#1650</a></li>
<li>Discord templating support added in <a
href="https://redirect.github.com/caronc/apprise/pull/1653">caronc/apprise#1653</a></li>
<li>support multi-attachments in single in discord message in <a
href="https://redirect.github.com/caronc/apprise/pull/1655">caronc/apprise#1655</a></li>
<li>Added RFC 2387 inline attachments to email:// in <a
href="https://redirect.github.com/caronc/apprise/pull/1659">caronc/apprise#1659</a></li>
<li>Support same-level yaml indented URL configuration entries in <a
href="https://redirect.github.com/caronc/apprise/pull/1636">caronc/apprise#1636</a></li>
<li>XMPP SASL improvments and CLI Debug output added in <a
href="https://redirect.github.com/caronc/apprise/pull/1637">caronc/apprise#1637</a></li>
<li>Support MS Teams user mentions by <a
href="https://github.com/caronc"><code>@​caronc</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1660">caronc/apprise#1660</a></li>
</ul>
<h3>❤️ Life-Cycle Support</h3>
<ul>
<li>removed popcorn notify plugin (no longer in service) in <a
href="https://redirect.github.com/caronc/apprise/pull/1656">caronc/apprise#1656</a></li>
<li>Update README.md to correct typo by <a
href="https://github.com/aherbert"><code>@​aherbert</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1642">caronc/apprise#1642</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aherbert"><code>@​aherbert</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1642">caronc/apprise#1642</a></li>
<li><a
href="https://github.com/jacob-masse"><code>@​jacob-masse</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1644">caronc/apprise#1644</a></li>
<li><a href="https://github.com/mac-lucky"><code>@​mac-lucky</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1643">caronc/apprise#1643</a></li>
<li><a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1640">caronc/apprise#1640</a></li>
<li><a
href="https://github.com/vgopalakPrgs"><code>@​vgopalakPrgs</code></a>
made their first contribution in <a
href="https://redirect.github.com/caronc/apprise/pull/1634">caronc/apprise#1634</a></li>
</ul>
<h2>Installation</h2>
<p>Apprise is available <a href="https://pypi.org/project/apprise/">on
PyPI</a> through <em>pip</em>:</p>
<pre lang="bash"><code># Install Apprise v1.12.0 from PyPI
pip install apprise==1.12.0
</code></pre>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/caronc/apprise/compare/v1.11.0...v1.12.0">https://github.com/caronc/apprise/compare/v1.11.0...v1.12.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/caronc/apprise/commit/c067047a3d18a81af88c7ec90d38cb1aa0fb7564"><code>c067047</code></a>
bumped version to v1.12.0</li>
<li><a
href="https://github.com/caronc/apprise/commit/183ca0c9a2f74c1c05881900409a579fa8e74a76"><code>183ca0c</code></a>
Support MS Teams user mentions (<a
href="https://redirect.github.com/caronc/apprise/issues/1660">#1660</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/493e72eada5bce551ea12aab87403d2a5c435a9b"><code>493e72e</code></a>
Added RFC 2387 inline attachments to email:// (<a
href="https://redirect.github.com/caronc/apprise/issues/1659">#1659</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/44c7ce6937385647c429cfd06bf5a441c1de6625"><code>44c7ce6</code></a>
Added SMSC Support (<a
href="https://redirect.github.com/caronc/apprise/issues/1658">#1658</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/356e0fbc58c9383e3cbe481cae8f841257ee7366"><code>356e0fb</code></a>
Serwer SMS Support Added (<a
href="https://redirect.github.com/caronc/apprise/issues/1657">#1657</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/2053e6afcd4e16ecdffce1423acf9227ba4a6b80"><code>2053e6a</code></a>
improved debug logging when upstream json response is bad</li>
<li><a
href="https://github.com/caronc/apprise/commit/8c4ecb0b8ee68b29ed2915551dccec982162b22f"><code>8c4ecb0</code></a>
Added Kook Support (<a
href="https://redirect.github.com/caronc/apprise/issues/1654">#1654</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/c98567efbc3f31cfc7281d10cc31d2fc64de4fa0"><code>c98567e</code></a>
support multi-attachments in single in discord message (<a
href="https://redirect.github.com/caronc/apprise/issues/1655">#1655</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/23782c1bff299e218d5d32bfc387ff63080e8989"><code>23782c1</code></a>
removed popcorn notify plugin (no longer in service) (<a
href="https://redirect.github.com/caronc/apprise/issues/1656">#1656</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/713a745230235161d5cf372c02d21e762f0c8def"><code>713a745</code></a>
Discord templating support added (<a
href="https://redirect.github.com/caronc/apprise/issues/1653">#1653</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/caronc/apprise/compare/v1.11.0...v1.12.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.6 to 0.4.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.8</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-04.</p>
<h3>Enhancements</h3>
<ul>
<li>Add default_env configuration (<a
href="https://redirect.github.com/j178/prek/pull/2288">#2288</a>)</li>
<li>Rename <code>auto-update</code> to <code>update</code> (<a
href="https://redirect.github.com/j178/prek/pull/2286">#2286</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix progress collapse ordering (<a
href="https://redirect.github.com/j178/prek/pull/2291">#2291</a>)</li>
<li>Fix progress insertion after collapsed rows (<a
href="https://redirect.github.com/j178/prek/pull/2292">#2292</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.8</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.8/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.8/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.4.8</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-x86_64-apple-darwin.tar.gz">prek-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-pc-windows-msvc.zip">prek-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-i686-pc-windows-msvc.zip">prek-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-x86_64-pc-windows-msvc.zip">prek-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-unknown-linux-gnu.tar.gz">prek-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-i686-unknown-linux-gnu.tar.gz">prek-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.4.8/prek-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.8</h2>
<p>Released on 2026-07-04.</p>
<h3>Enhancements</h3>
<ul>
<li>Add default_env configuration (<a
href="https://redirect.github.com/j178/prek/pull/2288">#2288</a>)</li>
<li>Rename <code>auto-update</code> to <code>update</code> (<a
href="https://redirect.github.com/j178/prek/pull/2286">#2286</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix progress collapse ordering (<a
href="https://redirect.github.com/j178/prek/pull/2291">#2291</a>)</li>
<li>Fix progress insertion after collapsed rows (<a
href="https://redirect.github.com/j178/prek/pull/2292">#2292</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/cccc61bef9310b818a27aaeed1c25ef9917b09f5"><code>cccc61b</code></a>
Bump version to 0.4.8</li>
<li><a
href="https://github.com/j178/prek/commit/1ff8e408d7024d14a7892d233a22f9ee0dc893e9"><code>1ff8e40</code></a>
Bump version to 0.4.7 (<a
href="https://redirect.github.com/j178/prek/issues/2294">#2294</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/29bfccef3e12389f00e9836c1a43b31c07787bdd"><code>29bfcce</code></a>
Add default_env configuration (<a
href="https://redirect.github.com/j178/prek/issues/2288">#2288</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/5f0e654a0ef044f6a6d8f50b075abb919818fb41"><code>5f0e654</code></a>
Fix progress insertion after collapsed rows (<a
href="https://redirect.github.com/j178/prek/issues/2292">#2292</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ce4363d33e6ade4f3f8a46902193703204ad91f8"><code>ce4363d</code></a>
Fix progress collapse ordering (<a
href="https://redirect.github.com/j178/prek/issues/2291">#2291</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3f41d4c21593f3983dd479d21e0308e5cd602b26"><code>3f41d4c</code></a>
Remove Goldziher/kreuzberg from README (<a
href="https://redirect.github.com/j178/prek/issues/2290">#2290</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/57493f93a0eb51d2a87d334c97952d1182975a6d"><code>57493f9</code></a>
Delete <code>.github/copilot-instructions.md</code> (<a
href="https://redirect.github.com/j178/prek/issues/2287">#2287</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ec18e36cf57318d9400d56701609f0df28f106d6"><code>ec18e36</code></a>
Rename <code>auto-update</code> to <code>update</code> (<a
href="https://redirect.github.com/j178/prek/issues/2286">#2286</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3c0e172d114e653ec67ee4b16b8e5c1b999f1428"><code>3c0e172</code></a>
Migrate to tombi for TOML formatting (<a
href="https://redirect.github.com/j178/prek/issues/2285">#2285</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/a40cd329457bc489735a34619c65c9f0bbc10fcf"><code>a40cd32</code></a>
ci: rely on setup-node npm for npm publishing (<a
href="https://redirect.github.com/j178/prek/issues/2284">#2284</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.6...v0.4.8">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-08 02:00:54 -04:00
dependabot[bot] c487c6c483 Bump seleniumbase from 4.50.4 to 4.50.5 in the python-deps group (#1106)
Bumps the python-deps group with 1 update:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `seleniumbase` from 4.50.4 to 4.50.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.50.5 - Fix Brave and Opera automation</h2>
<h2>Fix Brave and Opera automation</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c41948eab2d4e8a981e783042bf2f49ef4079de7">Fix
Brave Browser automation</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2632525f3b16313cc00cd6c068cf22dfbbce7be6">Fix
Opera Browser automation</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/308e71fca644ea7a896f17e4b65d77e4c807a0f6">Refresh
Python dependencies</a></li>
</ul>
<h3>More info:</h3>
<ul>
<li>The <code>--test-type</code> arg started breaking Brave on version
150. It's no longer used if Brave is set.</li>
<li>Brave with regular Chromedriver stopped worked. Since it works with
UC, that mode is forced.</li>
<li>Opera Browser now needs specific versions of Chromedriver and UC.
(Those versions are set.)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Fix Brave and Opera automation by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4418">seleniumbase/SeleniumBase#4418</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.4...v4.50.5">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.4...v4.50.5</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4de63c89d1815c146f675efe1ceab5f5922f7ae9"><code>4de63c8</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4418">#4418</a>
from seleniumbase/fix-brave-and-opera</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f4353ef73c5ef1de18e48f6f3380c2c777b38049"><code>f4353ef</code></a>
Version 4.50.5</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/308e71fca644ea7a896f17e4b65d77e4c807a0f6"><code>308e71f</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2632525f3b16313cc00cd6c068cf22dfbbce7be6"><code>2632525</code></a>
Fix Opera Browser automation</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c41948eab2d4e8a981e783042bf2f49ef4079de7"><code>c41948e</code></a>
Fix Brave Browser automation</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.4...v4.50.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=seleniumbase&package-manager=uv&previous-version=4.50.4&new-version=4.50.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 00:54:08 -04:00
CaliBrain 404e8cc5c5 path timeouts (#1103)
- Add configurable completed-path wait for external clients : - Add a
configurable Advanced setting, DOWNLOAD_CLIENT_COMPLETED_PATH_TIMEOUT,
for how long Shelfmark waits after a torrent or usenet client reports
completion before treating the completed path as missing. - Keep the
default at the existing 60-second grace period, with a maximum of 3600
seconds
- Add e2e testing
- Add e2e testing

Should fix #861
2026-07-06 01:51:58 -04:00
Alex SchittkoandCaliBrain 40d6a179b7 feat: native WireGuard VPN egress mode (USING_WIREGUARD) (#1097)
Add an opt-in WireGuard egress path alongside the existing Tor mode

---------

Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-07-06 01:51:18 -04:00
CaliBrain 02a45c1a12 fix: pin chromium to 149.0.7827.196 — Debian's 150 breaks the CDP bypasser (#1105) 2026-07-06 01:33:10 -04:00
dependabot[bot] 4c78a2f3a0 Bump the python-deps group with 2 updates (#1104)
Bumps the python-deps group with 2 updates:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[prek](https://github.com/j178/prek).

Updates `seleniumbase` from 4.50.3 to 4.50.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.50.4 - Updates for SOCKS5h support and PDF downloads</h2>
<h2>Updates for SOCKS5h support and PDF downloads</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0125a8dfa4cf8187377a68cb094bd1aa400244c0">Add
support for &quot;socks5h&quot; proxies without auth</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7c937ed4a760522ca0d546ae859c016f1e098343">Update
how PDF downloads are handled</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9ac19fbb520957429e062d952b8863210469dd3a">Update
console scripts</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0a5c44d1b6026b115c2ef257004465a21a9d6ea7">Refresh
optional Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a022ada3f823bd6058074ef99da47f12fd218202">Update
documentation and comments</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0b076173e998697661b8d57abaa95ee52c1b6760">Update
examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Updates for SOCKS5h support and PDF downloads by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4415">seleniumbase/SeleniumBase#4415</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.3...v4.50.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.3...v4.50.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e6a60b8f15771117811226e85920542d33bfa519"><code>e6a60b8</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4415">#4415</a>
from seleniumbase/socks5h-and-pdf-download-updates</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/17d71ef57a31a4306d2e117278e8988c47a42783"><code>17d71ef</code></a>
Version 4.50.4</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0b076173e998697661b8d57abaa95ee52c1b6760"><code>0b07617</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a022ada3f823bd6058074ef99da47f12fd218202"><code>a022ada</code></a>
Update documentation and comments</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0a5c44d1b6026b115c2ef257004465a21a9d6ea7"><code>0a5c44d</code></a>
Refresh optional Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9ac19fbb520957429e062d952b8863210469dd3a"><code>9ac19fb</code></a>
Update console scripts</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7c937ed4a760522ca0d546ae859c016f1e098343"><code>7c937ed</code></a>
Update how PDF downloads are handled</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0125a8dfa4cf8187377a68cb094bd1aa400244c0"><code>0125a8d</code></a>
Add support for &quot;socks5h&quot; proxies without auth</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.3...v4.50.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.5 to 0.4.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.6</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-01.</p>
<h3>Enhancements</h3>
<ul>
<li>Verify managed toolchain downloads before installation (<a
href="https://redirect.github.com/j178/prek/pull/2229">#2229</a>)</li>
<li>Add <code>PREK_DOCKER_NO_INIT</code> to opt-out Docker
<code>--init</code> (<a
href="https://redirect.github.com/j178/prek/pull/2242">#2242</a>)</li>
<li>Improve subprocess error messages (<a
href="https://redirect.github.com/j178/prek/pull/2257">#2257</a>)</li>
<li>Split run concurrency knobs: <code>PREK_CONCURRENT_HOOKS</code> and
<code>PREK_CONCURRENT_BATCHES</code> (<a
href="https://redirect.github.com/j178/prek/pull/2276">#2276</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid allocating markdown extensions per file (<a
href="https://redirect.github.com/j178/prek/pull/2245">#2245</a>)</li>
<li>Avoid unchanged config tracking writes (<a
href="https://redirect.github.com/j178/prek/pull/2247">#2247</a>)</li>
<li>Delay trailing whitespace output buffer (<a
href="https://redirect.github.com/j178/prek/pull/2244">#2244</a>)</li>
<li>Prefilter VCS permalink lines (<a
href="https://redirect.github.com/j178/prek/pull/2253">#2253</a>)</li>
<li>Skip unnecessary submodule updates during hook repo clone (<a
href="https://redirect.github.com/j178/prek/pull/2255">#2255</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document <code>language_version</code> inferring for Python and Go
(<a
href="https://redirect.github.com/j178/prek/pull/2241">#2241</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Refactor env var handling (<a
href="https://redirect.github.com/j178/prek/pull/2277">#2277</a>)</li>
<li>Use <code>serde-saphyr</code> for YAML string quoting (<a
href="https://redirect.github.com/j178/prek/pull/2228">#2228</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/shaanmajid"><code>@​shaanmajid</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.6</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.4.6/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.4.6/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.6</h2>
<p>Released on 2026-07-01.</p>
<h3>Enhancements</h3>
<ul>
<li>Verify managed toolchain downloads before installation (<a
href="https://redirect.github.com/j178/prek/pull/2229">#2229</a>)</li>
<li>Add <code>PREK_DOCKER_NO_INIT</code> to opt-out Docker
<code>--init</code> (<a
href="https://redirect.github.com/j178/prek/pull/2242">#2242</a>)</li>
<li>Improve subprocess error messages (<a
href="https://redirect.github.com/j178/prek/pull/2257">#2257</a>)</li>
<li>Split run concurrency knobs: <code>PREK_CONCURRENT_HOOKS</code> and
<code>PREK_CONCURRENT_BATCHES</code> (<a
href="https://redirect.github.com/j178/prek/pull/2276">#2276</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid allocating markdown extensions per file (<a
href="https://redirect.github.com/j178/prek/pull/2245">#2245</a>)</li>
<li>Avoid unchanged config tracking writes (<a
href="https://redirect.github.com/j178/prek/pull/2247">#2247</a>)</li>
<li>Delay trailing whitespace output buffer (<a
href="https://redirect.github.com/j178/prek/pull/2244">#2244</a>)</li>
<li>Prefilter VCS permalink lines (<a
href="https://redirect.github.com/j178/prek/pull/2253">#2253</a>)</li>
<li>Skip unnecessary submodule updates during hook repo clone (<a
href="https://redirect.github.com/j178/prek/pull/2255">#2255</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document <code>language_version</code> inferring for Python and Go
(<a
href="https://redirect.github.com/j178/prek/pull/2241">#2241</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Refactor env var handling (<a
href="https://redirect.github.com/j178/prek/pull/2277">#2277</a>)</li>
<li>Use <code>serde-saphyr</code> for YAML string quoting (<a
href="https://redirect.github.com/j178/prek/pull/2228">#2228</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/shaanmajid"><code>@​shaanmajid</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/643fba48aac2bdff4993e4d0b58c765a49df3188"><code>643fba4</code></a>
Bump version to 0.4.6 (<a
href="https://redirect.github.com/j178/prek/issues/2280">#2280</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/b0f92611f3b26c1436b98ba95678b1c95e2ac749"><code>b0f9261</code></a>
Refactor env var handling (<a
href="https://redirect.github.com/j178/prek/issues/2277">#2277</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/8494d1663e2c330e03ac0944bd6f81e8028f7a8a"><code>8494d16</code></a>
Split run concurrency knobs (<a
href="https://redirect.github.com/j178/prek/issues/2276">#2276</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f20bbaaedaf95ebcdda053de1548b2c24e20eb55"><code>f20bbaa</code></a>
Update sample config for <code>.pre-commit-config.yaml</code> (<a
href="https://redirect.github.com/j178/prek/issues/2275">#2275</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/5485289875b75170fce1ef3ed6c8964bd48fe91c"><code>5485289</code></a>
Pin pre-commit repos to commit hash (<a
href="https://redirect.github.com/j178/prek/issues/2274">#2274</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/d418ab322bb05539409c6a90a6c898c46a6b96a1"><code>d418ab3</code></a>
Improve nix shebang parsing (<a
href="https://redirect.github.com/j178/prek/issues/2271">#2271</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/cc261c13a0a9d7e10e6a713a9d9fe81594073f75"><code>cc261c1</code></a>
Update actions/checkout action to v7 (<a
href="https://redirect.github.com/j178/prek/issues/2267">#2267</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/8d2dbba355f8cca46c6a1f2386f1505db13d6053"><code>8d2dbba</code></a>
Update Rust crate itertools to 0.15.0 (<a
href="https://redirect.github.com/j178/prek/issues/2265">#2265</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/51db86cd2ae4dd496e7a7f5ea94c5013d4e5ac1f"><code>51db86c</code></a>
Update Rust crate phf to 0.14.0 (<a
href="https://redirect.github.com/j178/prek/issues/2266">#2266</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1aa7d389e8e9d782e11bb08a7223858557e56875"><code>1aa7d38</code></a>
Update dependency uv to v0.11.23 (<a
href="https://redirect.github.com/j178/prek/issues/2262">#2262</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.5...v0.4.6">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 00:32:57 -04:00
Alex Schittko 8b4230ee9f fix(bypass): resolve Xlib namespace collision breaking CDP browser startup (#1099)
## Problem

The full (browser) image ships two conflicting distributions that both
own the top-level `Xlib/` namespace:

- **`python-xlib` 0.33** (2022) — pulled by the `browser` extra
- **`python3-xlib` 0.15** (2014) — pulled transitively via `pyautogui` →
`mouseinfo`

Both install into the same `Xlib/` directory, so install order decides
which files survive. When the 2014 `python3-xlib` lands last, `Xlib.X`
is missing the `FamilyServerInterpreted` attribute that the SeleniumBase
Pure-CDP driver references during browser startup. Every bypass attempt
then fails with:

```
Pure CDP browser startup failed: module 'Xlib.X' has no attribute 'FamilyServerInterpreted'
Bypasser error: RuntimeError: Pure CDP browser startup failed: module 'Xlib.X' has no attribute 'FamilyServerInterpreted'
```

Result: **all Cloudflare / DDoS-Guard protected downloads fail** on
affected builds.

## Fix

After the browser stack is installed, uninstall the stale `python3-xlib`
and force-reinstall `python-xlib==0.33` so it deterministically owns the
namespace. A build-time assertion checks
`Xlib.X.FamilyServerInterpreted` exists so the image fails fast if the
collision ever returns.

`pyautogui` operates correctly against `python-xlib` 0.33 (superset
API), so nothing else regresses.

## Testing

- Reproduced live: a build where `python3-xlib` won produced the exact
`FamilyServerInterpreted` error on every CDP browser start; removing it
and reinstating `python-xlib==0.33` immediately restored `Chrome browser
ready (Pure CDP)` and successful `_bypass_method_cdp_solve`.
- The new build-time assertion prints `Xlib namespace OK: (0, 33)` and
exits non-zero if the attribute is ever missing.
2026-07-04 09:50:33 -04:00
dependabot[bot] b57925c39d Bump the python-deps group across 1 directory with 3 updates (#1098)
Bumps the python-deps group with 3 updates in the / directory:
[qbittorrent-api](https://github.com/rmartin16/qbittorrent-api),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[basedpyright](https://github.com/detachhead/basedpyright).

Updates `qbittorrent-api` from 2026.6.0 to 2026.6.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/releases">qbittorrent-api's
releases</a>.</em></p>
<blockquote>
<h2>release-2026.6.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump the github-actions group with 4 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/629">rmartin16/qbittorrent-api#629</a></li>
<li>fix: correct copy-paste docstring error in rss_move_item by <a
href="https://github.com/AmSach"><code>@​AmSach</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/628">rmartin16/qbittorrent-api#628</a></li>
<li>Bump starlette from 1.2.1 to 1.3.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/630">rmartin16/qbittorrent-api#630</a></li>
<li>Bump cryptography from 48.0.0 to 48.0.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/631">rmartin16/qbittorrent-api#631</a></li>
<li>qBittorrent 5.2.2 support by <a
href="https://github.com/agrenott"><code>@​agrenott</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/632">rmartin16/qbittorrent-api#632</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/agrenott"><code>@​agrenott</code></a>
made their first contribution in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/632">rmartin16/qbittorrent-api#632</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.6.0...v2026.6.1">https://github.com/rmartin16/qbittorrent-api/compare/v2026.6.0...v2026.6.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md">qbittorrent-api's
changelog</a>.</em></p>
<blockquote>
<h3>v2026.6.1 (26 jun 2026)</h3>
<ul>
<li>Advertise support for qBittorrent v5.2.2</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/5985973705f7b0c4df4c5d1f7decba792973a2d5"><code>5985973</code></a>
bump to v2026.6.1</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/89c1206bcf115343d2548e5a2e61e5445c2d35bd"><code>89c1206</code></a>
qBittorrent 5.2.2 support (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/632">#632</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/491cc3003f648e6ba5e617c974fa97ce4c1316a8"><code>491cc30</code></a>
Bump cryptography from 48.0.0 to 48.0.1 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/631">#631</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/605814a55478a5f6f7b1631986787fd818a85057"><code>605814a</code></a>
Bump starlette from 1.2.1 to 1.3.1 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/630">#630</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/d1ed4487f66fe122bd8e885633d03f80892e2977"><code>d1ed448</code></a>
fix: correct copy-paste docstring error in rss_move_item (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/628">#628</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/56f3d2981d95db3323ab68edcdbe8d71e85412d9"><code>56f3d29</code></a>
Bump the github-actions group with 4 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/629">#629</a>)</li>
<li>See full diff in <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.6.0...v2026.6.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.50.2 to 4.50.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.50.3 - CDP Mode: Patch 118</h2>
<h2>CDP Mode: Patch 118</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cc9050e60e1f57d7178e216182f1f6e02bdc2b16">Update
CDP Mode</a>
-- Simplifies <code>--use-chromium</code> to just
<code>--chromium</code> in command-line options
-- Use the mock-keychain when setting a custom Chromium binary location
-- Adjusts the DataDome Slider CAPTCHA-solving algorithm</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7e168b767efb81ff645a38d17097ce7c174bd6a2">Update
CDP Mode examples</a>
-- Use <code>asyncio.run()</code> instead of
<code>loop.run_until_complete()</code> as needed</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 118 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4412">seleniumbase/SeleniumBase#4412</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.2...v4.50.3">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.2...v4.50.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d2e98d47d0f3ee72464a4bb9bba0d6347ea9e34e"><code>d2e98d4</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4412">#4412</a>
from seleniumbase/cdp-mode-patch-118</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/092b0f475fb7d19ae9a5d3de16b81a0cf886adcf"><code>092b0f4</code></a>
Version 4.50.3</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f57e0662a5fd8601c75e9ab1b5eb2a51e9947c78"><code>f57e066</code></a>
Update the documentation</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7e168b767efb81ff645a38d17097ce7c174bd6a2"><code>7e168b7</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cc9050e60e1f57d7178e216182f1f6e02bdc2b16"><code>cc9050e</code></a>
Update CDP Mode</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.2...v4.50.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.8 to 1.39.9
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/2802042079937529ad9f343d00a035c24e767065"><code>2802042</code></a>
fix <code>pnpm view</code> command and simplify the outcome check</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f6e62d3550648052ebce7ccfe75e90072c2fa44a"><code>f6e62d3</code></a>
fix crash during publish</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/816614ebb5fb21303ba6df0edc299b0235e9ebf6"><code>816614e</code></a>
1.39.9</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/c79697f782786d759d2848be3994b72561863191"><code>c79697f</code></a>
remove more webpack remnants</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/2921109c27b043cda1af67521fd6b2a37373a6f6"><code>2921109</code></a>
<a
href="https://redirect.github.com/microsoft/vscode-vsce/issues/421">microsoft/vscode-vsce#421</a></li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/58120740bf2b100672830d031f23dd171b10be19"><code>5812074</code></a>
fix new test from upstream. that representation of a paramspec is wrong,
espe...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/eaaaf62a90dce1a7c275304835f5c103cd50b4c8"><code>eaaaf62</code></a>
prettier ignore new files from upstream</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/8baf13e358c905ab1a2e0395dfec40b030889e84"><code>8baf13e</code></a>
switch to pnpm because npm is the worst package manager ever made.</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f228a802fd022367201207e062610b44bc33fd21"><code>f228a80</code></a>
fixes from merge</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/21702747ca61358441bef00e50b39451af37537d"><code>2170274</code></a>
Merge tag '1.1.411' into merge-1.1.411</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.8...v1.39.9">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 09:47:15 -04:00
dependabot[bot] b6efed95ab Bump the gh-actions group with 2 updates (#1102)
Bumps the gh-actions group with 2 updates:
[actions/attest-build-provenance](https://github.com/actions/attest-build-provenance)
and [dorny/paths-filter](https://github.com/dorny/paths-filter).

Updates `actions/attest-build-provenance` from 4.1.0 to 4.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/attest-build-provenance/releases">actions/attest-build-provenance's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.1</h2>
<blockquote>
<p>[!NOTE]
As of version 4, <code>actions/attest-build-provenance</code> is simply
a wrapper on top of <a
href="https://github.com/actions/attest"><code>actions/attest</code></a>.</p>
<p>Existing applications may continue to use the
<code>attest-build-provenance</code> action, but new implementations
should use <code>actions/attest</code> instead.</p>
</blockquote>
<h2>What's Changed</h2>
<ul>
<li>Update actions/attest to v4.1.1 by <a
href="https://github.com/bdehamer"><code>@​bdehamer</code></a> in <a
href="https://redirect.github.com/actions/attest-build-provenance/pull/858">actions/attest-build-provenance#858</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/attest-build-provenance/compare/v4.1.0...v4.1.1">https://github.com/actions/attest-build-provenance/compare/v4.1.0...v4.1.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/0f67c3f4856b2e3261c31976d6725780e5e4c373"><code>0f67c3f</code></a>
Bump actions/checkout from 6.0.3 to 7.0.0 (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/857">#857</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/21b787db45d5d4b6fc776b99a247a6493082d1fd"><code>21b787d</code></a>
Update actions/attest to v4.1.1 (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/858">#858</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/f14352a605c57b0a66e0d49bba5825967f1dbedf"><code>f14352a</code></a>
add dependabot cooldown (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/851">#851</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/2c04a00460b64b4dfd062384e60ea87fa18e1728"><code>2c04a00</code></a>
Bump actions/checkout from 6.0.2 to 6.0.3 in the actions-minor group (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/850">#850</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/10334b5f1e684784025c3fc0a277c88c19089275"><code>10334b5</code></a>
remove badges from README (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/840">#840</a>)</li>
<li><a
href="https://github.com/actions/attest-build-provenance/commit/c5efebd311e9a809e832398ca2b73bb429ff3508"><code>c5efebd</code></a>
remove prober workflows (<a
href="https://redirect.github.com/actions/attest-build-provenance/issues/837">#837</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/attest-build-provenance/compare/a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32...0f67c3f4856b2e3261c31976d6725780e5e4c373">compare
view</a></li>
</ul>
</details>
<br />

Updates `dorny/paths-filter` from 4 to 4.0.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/releases">dorny/paths-filter's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Support merge queue by <a
href="https://github.com/masaru-iritani"><code>@​masaru-iritani</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/255">dorny/paths-filter#255</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/masaru-iritani"><code>@​masaru-iritani</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/255">dorny/paths-filter#255</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v4.0.0...v4.0.1">https://github.com/dorny/paths-filter/compare/v4.0.0...v4.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md">dorny/paths-filter's
changelog</a>.</em></p>
<blockquote>
<h2>v4.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/255">Support
merge queue</a></li>
</ul>
<h2>v4.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/294">Update
action runtime to node24</a></li>
</ul>
<h2>v3.0.3</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/279">Add
missing predicate-quantifier</a></li>
</ul>
<h2>v3.0.2</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/224">Add
config parameter for predicate quantifier</a></li>
</ul>
<h2>v3.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/133">Compare
base and ref when token is empty</a></li>
</ul>
<h2>v3.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/210">Update to
Node.js 20</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/215">Update
all dependencies</a></li>
</ul>
<h2>v2.11.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/167">Update
@​actions/core to v1.10.0 - Fixes warning about deprecated
set-output</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/168">Document
need for pull-requests: read permission</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/164">Updating
to actions/checkout@v3</a></li>
</ul>
<h2>v2.11.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/157">Set
list-files input parameter as not required</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/161">Update
Node.js</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/162">Fix
incorrect handling of Unicode characters in exec()</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/163">Use
Octokit pagination</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/160">Updates
real world links</a></li>
</ul>
<h2>v2.10.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/91">Fix
getLocalRef() returns wrong ref</a></li>
</ul>
<h2>v2.10.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/85">Improve
robustness of change detection</a></li>
</ul>
<h2>v2.10.0</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/82">Add
ref input parameter</a></li>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/83">Fix
change detection in PR when pullRequest.changed_files is
incorrect</a></li>
</ul>
<h2>v2.9.3</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/78">Fix
change detection when base is a tag</a></li>
</ul>
<h2>v2.9.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/75">Fix
fetching git history</a></li>
</ul>
<h2>v2.9.1</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/74">Fix
fetching git history + fallback to unshallow repo</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/dorny/paths-filter/commit/3c49e64ca26115121162fb767bc6af9e8d059f1a"><code>3c49e64</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/210">#210</a>
from dorny/use-nodejs-20</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/8ec7be473424d724f09d3c51b7962ae5f2ffcbab"><code>8ec7be4</code></a>
Update to nodejs 20</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/100a1198b209450115509c0565d407ac269190dc"><code>100a119</code></a>
Revert back to node16</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/96be2b61c476f7b821cc2ed4eb7cbe4d96d30f60"><code>96be2b6</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/206">#206</a>
from danielhjacobs/patch-1</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/f5071954e88595af02cdf15a1cb0c0c22fc8ca08"><code>f507195</code></a>
Update Node.js to version 20</li>
<li>See full diff in <a
href="https://github.com/dorny/paths-filter/compare/v4...v4.0.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 09:47:01 -04:00
dependabot[bot] 44a261e857 Bump the npm-deps group in /src/frontend with 9 updates (#1101)
Bumps the npm-deps group in /src/frontend with 9 updates:

| Package | From | To |
| --- | --- | --- |
|
[@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)
| `4.3.1` | `4.3.2` |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.18.0` | `7.18.1` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `26.0.0` | `26.0.1` |
|
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
| `6.0.2` | `6.0.3` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.18.0` | `6.23.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.56.0` | `0.57.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.71.0` | `1.72.0` |
|
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
| `4.3.1` | `4.3.2` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.0.16` | `8.1.0` |

Updates `@tailwindcss/vite` from 4.3.1 to 4.3.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">@​tailwindcss/vite's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.2</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">@​tailwindcss/vite's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.2] - 2026-06-26</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/056a1550721d4bf79ff732d5ab9414fa83f7064f"><code>056a155</code></a>
4.3.2 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/20281">#20281</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/bb6a10937c7e1434db39919fbb4df4a8982dba7f"><code>bb6a109</code></a>
use <code>.ts</code> instead of <code>.css</code></li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.2/packages/@tailwindcss-vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-router-dom` from 7.18.0 to 7.18.1
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/react-router-dom@7.18.1/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.18.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>Fix incorrect <code>package.json</code> <code>main</code> field for
CommonJS builds (<a
href="https://redirect.github.com/remix-run/react-router/pull/15238">#15238</a>)</li>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.18.1"><code>react-router@7.18.1</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/afdf85d3c15448a41017514caca2aca038d3e9ca"><code>afdf85d</code></a>
Release v7.18.1 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15253">#15253</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/2ecaa1ddbbcd583999dda46dd5413e907e8a46f3"><code>2ecaa1d</code></a>
Fix react-router-dom main entry metadata (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15238">#15238</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.18.1/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 26.0.0 to 26.0.1
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.0.2 to 6.0.3
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.0.3 (2026-06-23)</h2>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/640fd358a0e82393acfce4e92e19a6ac6e1641a7"><code>640fd35</code></a>
release: plugin-react@6.0.3</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/889efb02cdc4ec978a5e177a37e0213cfded38a4"><code>889efb0</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1249">#1249</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/6c57dd4c5d71075b48039df2532804e72880da21"><code>6c57dd4</code></a>
fix(plugin-react): use '/' base in bundledDev preamble to fix non-root
base p...</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/3cc33a703636b558a1c1c99e787ddc6bd64aab2d"><code>3cc33a7</code></a>
fix(deps): update react-related dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1245">#1245</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/c0f7c7ff709dc9d88bc1f29f1b27c1b3e2bfcfca"><code>c0f7c7f</code></a>
docs: mention the Biome rule in the &quot;Consistent components
exports&quot; section (...</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/cd80f0f7b2b750f6e8f719f9c3dbe4f22ddd94db"><code>cd80f0f</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1241">#1241</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/e38accafea0c7c84f7fc72fd69d9cec731fa7600"><code>e38acca</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1227">#1227</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/9a9bb26c23b966dceed47ff9ec257faeb0e777d9"><code>9a9bb26</code></a>
perf(react): improve react compiler preset so that slightly more modules
are ...</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.3/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.18.0 to 6.23.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.23.0</h2>
<ul>
<li>feat: add customCss to Starlight plugin (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1828">#1828</a>)
(f85d96f84a47f10c34df95a5246ee1ddefd95db5) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>fix: enable vite and vitest plugins when vite-plus is found (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1830">#1830</a>)
(62e97538fca8dff3d152326b114ffc4b7241a0d2) - thanks <a
href="https://github.com/ghostdevv"><code>@​ghostdevv</code></a>!</li>
<li>feat: add support for <code>@​astrojs/markdoc</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1829">#1829</a>)
(94e2863308947f19f5e759cc12666952c8f683d7) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>Support nub (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1831">#1831</a>)
(8a6050e6a92da81d4875f730f852fb7d9252a018)</li>
<li>Don't report optimizeDeps and dedupe deps as unlisted (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1832">#1832</a>)
(849b5ac230e7a8c103b6e1b1e2ddb333d2da3ca0)</li>
</ul>
<h2>Release 6.22.0</h2>
<ul>
<li>Support XO v1+ (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1819">#1819</a>)
(1dffe368b5c336d190e358ab4c2e2240e3d50e26) - thanks <a
href="https://github.com/patrik-csak"><code>@​patrik-csak</code></a>!</li>
<li>feat: detect execaNode scripts in execa visitor (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1824">#1824</a>)
(5095ae1ccd0ceb083d4434e827443f03ba19a1ff) - thanks <a
href="https://github.com/gwagjiug"><code>@​gwagjiug</code></a>!</li>
<li>Skip optional peerDeps referenced only via a host (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1823">#1823</a>)
(7759a9894f2ac1d9425cf682e1e3c400f0976080)</li>
<li>docs: update npmjs.com links to npmx.dev (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1826">#1826</a>)
(11fe8bd248c839c6eeb95b06c8204c25294e0adb) - thanks <a
href="https://github.com/serhalp"><code>@​serhalp</code></a>!</li>
<li>docs: fix semi-broken link to DEVELOPMENT.md in CONTRIBUTING.md (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1827">#1827</a>)
(a5302b2466be1294633b1f40e86ca81a00605293) - thanks <a
href="https://github.com/serhalp"><code>@​serhalp</code></a>!</li>
<li>feat: add support for Lunaria (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1825">#1825</a>)
(3e1b8212086dfae26fa7f368f245285ec82af14d) - thanks <a
href="https://github.com/trueberryless"><code>@​trueberryless</code></a>!</li>
<li>Fix lint issues (76c92e2328a94257afead6ae497a747a9e2944ea)</li>
</ul>
<h2>Release 6.21.0</h2>
<ul>
<li>Detect Vite config dependencies (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1721">#1721</a>)
(8754c43368112922c6f80d1f8d1d8ddb6cb29f25)</li>
<li>fix: Update timerifyMethods to include resolveFromAST (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1814">#1814</a>)
(3c8deac3b856def31c16372f85525bf867105132) - thanks <a
href="https://github.com/gwagjiug"><code>@​gwagjiug</code></a>!</li>
<li>Fix crash on null root export in package.json (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1815">#1815</a>)
(9b8af2b343e1aacae46fedcb155252f56f9bae61)</li>
<li>Fix unresolved subpath imports with a colon prefix (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1816">#1816</a>)
(f89db4192ff7ff6c873828ed19fe40d379566b49)</li>
<li>Detect Next.js entry files in subdirectory (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1817">#1817</a>)
(f32c6ea215dde54a59af7b91fd8bdd2177cc2881)</li>
</ul>
<h2>Release 6.20.0</h2>
<ul>
<li>Add raw transfer opt-out (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1813">#1813</a>)
(6f08c680ac4acd6edf0806ba3c1c5c8f7bca24cd)</li>
<li>Fix cached plugin config cycles (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1811">#1811</a>)
(2bc2f2420ca71db1ae70846626c6152896d270ee)</li>
</ul>
<h2>Release 6.19.0</h2>
<ul>
<li>feat: support new optional sveltekit config pattern via vite config
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1810">#1810</a>)
(3fee8bf608e0862d7bcdd1377cfb859a9185f17d) - thanks <a
href="https://github.com/fubits1"><code>@​fubits1</code></a>!</li>
<li>Optimize hot path string scanning
(e30cfe796423e3ecd9adff42291f3c4de6604d2b)</li>
<li>Update astro snapshot
(71e71a71b888a1b8034d4438635e94831d62b330)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/a802601072b0e3c98a20b6aaea4a4c555fbd6a55"><code>a802601</code></a>
Release knip@6.23.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/849b5ac230e7a8c103b6e1b1e2ddb333d2da3ca0"><code>849b5ac</code></a>
Don't report optimizeDeps and dedupe deps as unlisted (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1832">#1832</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/8a6050e6a92da81d4875f730f852fb7d9252a018"><code>8a6050e</code></a>
Support nub (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1831">#1831</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/94e2863308947f19f5e759cc12666952c8f683d7"><code>94e2863</code></a>
feat: add support for <code>@​astrojs/markdoc</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1829">#1829</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/62e97538fca8dff3d152326b114ffc4b7241a0d2"><code>62e9753</code></a>
fix: enable vite and vitest plugins when vite-plus is found (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1830">#1830</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f85d96f84a47f10c34df95a5246ee1ddefd95db5"><code>f85d96f</code></a>
feat: add customCss to Starlight plugin (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1828">#1828</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c0537556aa6a99ae0fa48cf743798f02dde239eb"><code>c053755</code></a>
Release knip@6.22.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/76c92e2328a94257afead6ae497a747a9e2944ea"><code>76c92e2</code></a>
Fix lint issues</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/3e1b8212086dfae26fa7f368f245285ec82af14d"><code>3e1b821</code></a>
feat: add support for Lunaria (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1825">#1825</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/11fe8bd248c839c6eeb95b06c8204c25294e0adb"><code>11fe8bd</code></a>
docs: update npmjs.com links to npmx.dev (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1826">#1826</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.23.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.56.0 to 0.57.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/5306f24d9e82ae36ad9c3c964f33075bc589c799"><code>5306f24</code></a>
release(apps): oxlint v1.72.0 &amp;&amp; oxfmt v0.57.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/23935">#23935</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.57.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.71.0 to 1.72.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.72.0] - 2026-06-29</h2>
<h3>🚀 Features</h3>
<ul>
<li>1c8f50c linter: Add schema for
<code>eslint/no-restricted-import</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23642">#23642</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>742be36 refactor/node/handle-callback-err: Reject invalid regex
config (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23740">#23740</a>)
(camc314)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/5306f24d9e82ae36ad9c3c964f33075bc589c799"><code>5306f24</code></a>
release(apps): oxlint v1.72.0 &amp;&amp; oxfmt v0.57.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23935">#23935</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/742be3616fc8df27053b09bdf9ff166e16761838"><code>742be36</code></a>
fix(refactor/node/handle-callback-err): reject invalid regex config (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23740">#23740</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/1c8f50c67ff636b9d8193d3d7be1511a7960f25d"><code>1c8f50c</code></a>
feat(linter): add schema for <code>eslint/no-restricted-import</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23642">#23642</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.72.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `tailwindcss` from 4.3.1 to 4.3.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.2</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">tailwindcss's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.2] - 2026-06-26</h2>
<h3>Fixed</h3>
<ul>
<li>Support bare spacing values for <code>auto-rows-*</code> and
<code>auto-cols-*</code> utilities (e.g. <code>auto-rows-12</code> and
<code>auto-cols-16</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20229">#20229</a>)</li>
<li>Prevent <code>@tailwindcss/cli</code> in <code>--watch</code> mode
from crashing on Windows when <code>@source</code> points to a directory
that doesn't exist (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20242">#20242</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing in Deno v2.8.x
when <code>context.parentURL</code> is not a valid URL (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20245">#20245</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
rebuilds when the input CSS file changes in an ignored directory (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20246">#20246</a>)</li>
<li>Allow <code>@variant</code> rules used in <code>addBase(…)</code> to
use custom variants defined later (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20247">#20247</a>)</li>
<li>Prevent <code>@tailwindcss/vite</code> from crashing during HMR when
scanned files or directories are deleted (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20259">#20259</a>)</li>
<li>Generate <code>font-size</code> instead of <code>color</code>
declarations for <code>text-[--spacing(…)]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20260">#20260</a>)</li>
<li>Prevent <code>@source</code> patterns from scanning unrelated
sibling files and folders (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20263">#20263</a>)</li>
<li>Extract class candidates adjacent to Template Toolkit delimiters
like <code>%]…[%</code> in <code>.tt</code>, <code>.tt2</code>, and
<code>.tx</code> files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Extract class candidates from conditional Maud syntax like
<code>p.text-black[condition]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20269">#20269</a>)</li>
<li>Prevent <code>@position-try</code> rules from triggering unknown
at-rule warnings when optimizing CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20277">#20277</a>)</li>
<li>Support class suggestions for named opacity modifiers from
<code>--opacity</code> theme values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20287">#20287</a>)</li>
<li>Prevent type errors in <code>@tailwindcss/postcss</code> when used
with newer PostCSS patch releases (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20289">#20289</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/056a1550721d4bf79ff732d5ab9414fa83f7064f"><code>056a155</code></a>
4.3.2 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20281">#20281</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c8b081d96376871acb0157923e894b7a929cad5b"><code>c8b081d</code></a>
Add suggestions for named opacity modifiers (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20287">#20287</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c46f654fa0039ad4741c6ecefbe4e2a208a665c3"><code>c46f654</code></a>
Ensure <code>--alpha(…)</code> is seen as a <code>color</code>, and
<code>--spacing(…)</code> is seen as a `le...</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/5e9f66e4284164c62e80d74e69e0cbd8d9c645cc"><code>5e9f66e</code></a>
Ensure <code>@variant</code> can be used in JS based APIs (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20252">#20252</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/707c23b955bdfa7854a03195e503b95dd730b3d2"><code>707c23b</code></a>
Ensure custom variants can be used via <code>@variant</code> in
<code>addBase</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20247">#20247</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/127d17033a0518701dac8332667b12e0980870ec"><code>127d170</code></a>
Add bare value support for <code>auto-rows-*</code> and
<code>auto-cols-*</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20229">#20229</a>)</li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.2/packages/tailwindcss">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.0.16 to 8.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>create-vite@8.1.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@8.1.0/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>plugin-legacy@8.1.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/plugin-legacy@8.1.0/packages/plugin-legacy/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.1.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.0/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>plugin-legacy@8.1.0-beta.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/plugin-legacy@8.1.0-beta.0/packages/plugin-legacy/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.1.0-beta.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.1.0-beta.0/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/vitejs/vite/compare/v8.1.0-beta.0...v8.1.0">8.1.0</a>
(2026-06-23)</h2>
<h3>Features</h3>
<ul>
<li>extend <code>server.fs.deny</code> list with common files (<a
href="https://redirect.github.com/vitejs/vite/issues/22707">#22707</a>)
(<a
href="https://github.com/vitejs/vite/commit/61ba8fdc6500e8aa668021833ae5e6ebd200466d">61ba8fd</a>)</li>
<li>update rolldown to 1.1.2 (<a
href="https://redirect.github.com/vitejs/vite/issues/22695">#22695</a>)
(<a
href="https://github.com/vitejs/vite/commit/4f008a6213014fe5e898f42561bdc621e103903e">4f008a6</a>)</li>
<li>use <code>~</code> for Rolldown (<a
href="https://redirect.github.com/vitejs/vite/issues/22693">#22693</a>)
(<a
href="https://github.com/vitejs/vite/commit/9928722f7d08de27907c48b65ddc071244166e05">9928722</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>bundled-dev:</strong> errors should be kept when incremental
build fails (<a
href="https://redirect.github.com/vitejs/vite/issues/22617">#22617</a>)
(<a
href="https://github.com/vitejs/vite/commit/9a0dd481ac2160078b8173879e0fa86e5e6af05d">9a0dd48</a>)</li>
<li>cache falsy values in perEnvironmentState (<a
href="https://redirect.github.com/vitejs/vite/issues/22715">#22715</a>)
(<a
href="https://github.com/vitejs/vite/commit/0e91e79841b501d29dc86a6b7c0313660781196a">0e91e79</a>)</li>
<li><strong>glob:</strong> respect caseSensitive option in hmr matcher
(<a
href="https://redirect.github.com/vitejs/vite/issues/22711">#22711</a>)
(<a
href="https://github.com/vitejs/vite/commit/65f525e643ba31faeaeafbc5d888b61465e6b48d">65f525e</a>)</li>
<li><strong>html:</strong> omit nonce on import map when cspNonce is
unset (<a
href="https://redirect.github.com/vitejs/vite/issues/22713">#22713</a>)
(<a
href="https://github.com/vitejs/vite/commit/8340bb51cab703427a13d5df40b0005352c1b676">8340bb5</a>)</li>
<li><strong>optimizer:</strong> skip null-valued exports in
expandGlobIds glob resolution (<a
href="https://redirect.github.com/vitejs/vite/issues/22611">#22611</a>)
(<a
href="https://github.com/vitejs/vite/commit/8b9f5cd9f19f6002e1323b10155ab943219e86aa">8b9f5cd</a>)</li>
<li>resolved build options should be kept as a getter (<a
href="https://redirect.github.com/vitejs/vite/issues/22691">#22691</a>)
(<a
href="https://github.com/vitejs/vite/commit/3527191cad6c935a3d129506cc9a893c84009037">3527191</a>)</li>
<li><strong>server:</strong> handle malformed URI in memory files
middleware (<a
href="https://redirect.github.com/vitejs/vite/issues/22714">#22714</a>)
(<a
href="https://github.com/vitejs/vite/commit/df9e0a589ff64e09c32beca9494bff4757d4ea37">df9e0a5</a>)</li>
<li>use literal envPrefix queries for Vite Task (<a
href="https://redirect.github.com/vitejs/vite/issues/22706">#22706</a>)
(<a
href="https://github.com/vitejs/vite/commit/da727337b13ac6144e523eb06852b2a52c377f22">da72733</a>)</li>
<li>warn on deprecated envFile (<a
href="https://redirect.github.com/vitejs/vite/issues/22555">#22555</a>)
(<a
href="https://github.com/vitejs/vite/commit/ed7b28352e347dc7c95d590d2e696c3e5bd1e3d7">ed7b283</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li><strong>client:</strong> inline dev-id value in CSS selector (<a
href="https://redirect.github.com/vitejs/vite/issues/22736">#22736</a>)
(<a
href="https://github.com/vitejs/vite/commit/57f59bc843dd527a81c503684b7f408872edaef3">57f59bc</a>)</li>
<li>remove unused removeRawQuery util (<a
href="https://redirect.github.com/vitejs/vite/issues/22724">#22724</a>)
(<a
href="https://github.com/vitejs/vite/commit/403cc608e4e8633b0335f5e8221c83dfca4994f8">403cc60</a>)</li>
<li>use <code>rolldownOptions</code> property for chunkImportMap (<a
href="https://redirect.github.com/vitejs/vite/issues/22692">#22692</a>)
(<a
href="https://github.com/vitejs/vite/commit/8e8816ca9fa249d210150c5590bac06af3560aa7">8e8816c</a>)</li>
</ul>
<h2><a
href="https://github.com/vitejs/vite/compare/v8.0.16...v8.1.0-beta.0">8.1.0-beta.0</a>
(2026-06-15)</h2>
<h3>Features</h3>
<ul>
<li><code>import.meta.glob</code> support <code>caseSensitive</code>
option (<a
href="https://redirect.github.com/vitejs/vite/issues/21707">#21707</a>)
(<a
href="https://github.com/vitejs/vite/commit/2ad6737a838cc23ebb9b2766682d28b11078dab5">2ad6737</a>)</li>
<li>add warning to discourage Vite with yarn pnp (<a
href="https://redirect.github.com/vitejs/vite/issues/21906">#21906</a>)
(<a
href="https://github.com/vitejs/vite/commit/3fbb55add62a1b94a2b47b7da70db4ae99a7c943">3fbb55a</a>)</li>
<li><strong>build:</strong> chunk importmap (<a
href="https://redirect.github.com/vitejs/vite/issues/21580">#21580</a>)
(<a
href="https://github.com/vitejs/vite/commit/e1803128e5698202e22c6e5e17dc9ebd83d4f3f5">e180312</a>)</li>
<li><strong>css:</strong> support lightningcss plugin dependency (<a
href="https://redirect.github.com/vitejs/vite/issues/21748">#21748</a>)
(<a
href="https://github.com/vitejs/vite/commit/0b7aaedc98cacb00e6db33f5f79a70192da38304">0b7aaed</a>)</li>
<li><strong>deps:</strong> bump <code>@​vitejs/devtools</code> peer
dependency version (<a
href="https://redirect.github.com/vitejs/vite/issues/22542">#22542</a>)
(<a
href="https://github.com/vitejs/vite/commit/d2c2bc090bab9bb9508e5060accb5179b6310257">d2c2bc0</a>)</li>
<li><strong>html:</strong> add <code>html.additionalAssetSources</code>
option (<a
href="https://redirect.github.com/vitejs/vite/issues/21412">#21412</a>)
(<a
href="https://github.com/vitejs/vite/commit/a41404b8894d4de729ed49fb51e0b6230d6cb511">a41404b</a>)</li>
<li>integrate with Vite Task for zero-config build caching (<a
href="https://redirect.github.com/vitejs/vite/issues/22453">#22453</a>)
(<a
href="https://github.com/vitejs/vite/commit/f8d75f7723aeb635126c8dc0e0c33266c72d24c0">f8d75f7</a>)</li>
<li>rename <code>server.hmr</code> options to <code>server.ws</code>
options (<a
href="https://redirect.github.com/vitejs/vite/issues/21357">#21357</a>)
(<a
href="https://github.com/vitejs/vite/commit/9ce3036d31d4e56b8ef3730a39a7f0e54baa951f">9ce3036</a>)</li>
<li><strong>server:</strong> support multiple hosts in
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS (<a
href="https://redirect.github.com/vitejs/vite/issues/21501">#21501</a>)
(<a
href="https://github.com/vitejs/vite/commit/735f9a19a9d0e313c865c87daad677aaf358406b">735f9a1</a>)</li>
<li>track dependencies when loading config with native (<a
href="https://redirect.github.com/vitejs/vite/issues/22602">#22602</a>)
(<a
href="https://github.com/vitejs/vite/commit/a7e2da8cdb306cfdf1660aa4b1fe24873a8dd873">a7e2da8</a>)</li>
<li><strong>types:</strong> add more precise typing for known
<code>query</code> types to match known <code>as</code> types (<a
href="https://redirect.github.com/vitejs/vite/issues/21863">#21863</a>)
(<a
href="https://github.com/vitejs/vite/commit/cc39e55401d559b771fa3e029d90c419a364b805">cc39e55</a>)</li>
<li>update rolldown to 1.1.1 (<a
href="https://redirect.github.com/vitejs/vite/issues/22593">#22593</a>)
(<a
href="https://github.com/vitejs/vite/commit/8a13d6337eea3e74d6a7abaaa7e1d378f5b9bc49">8a13d63</a>)</li>
<li><strong>wasm:</strong> direct .wasm imports (WASM ESM Integration)
(<a
href="https://redirect.github.com/vitejs/vite/issues/21779">#21779</a>)
(<a
href="https://github.com/vitejs/vite/commit/c23d85b9654685d7217cfc33817d2953b77744f8">c23d85b</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>apply correct fs restrictions for pnpm gvs (<a
href="https://redirect.github.com/vitejs/vite/issues/22415">#22415</a>)
(<a
href="https://github.com/vitejs/vite/commit/092320bfe115e4d9952a7d172bc40cd3ec14a4c3">092320b</a>)</li>
<li><strong>css:</strong> support external CSS with lightningcss (<a
href="https://redirect.github.com/vitejs/vite/issues/18389">#18389</a>)
(<a
href="https://github.com/vitejs/vite/commit/d64a1a5557b3caea9469e70b647ff2c9d9def809">d64a1a5</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22637">#22637</a>)
(<a
href="https://github.com/vitejs/vite/commit/44bb9d95a246011a2fba9a19cadeac4181bef1b4">44bb9d9</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22681">#22681</a>)
(<a
href="https://github.com/vitejs/vite/commit/f4f063382dde0d67b2158374c56443d0bf5c9501">f4f0633</a>)</li>
<li><strong>html:</strong> insert import map before modulepreload that
is not self-close tag (<a
href="https://redirect.github.com/vitejs/vite/issues/21409">#21409</a>)
(<a
href="https://github.com/vitejs/vite/commit/e399c89a7decff73ff42a4a01679ecc235ce6845">e399c89</a>)</li>
<li><strong>optimizer:</strong> preserve sourcemaps for transformed
optimized deps with follow-up transforms (<a
href="https://redirect.github.com/vitejs/vite/issues/22428">#22428</a>)
(<a
href="https://github.com/vitejs/vite/commit/1298951ebc5e5a94164c21f142fe748ca37eea68">1298951</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/5909efd8fbfd1bf1eab65427aea0613124b2797a"><code>5909efd</code></a>
fix: allow multiple <code>bindCLIShortcuts</code> calls with shortcut
merging (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21103">#21103</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/39a0a15fd24ed37257c48b795097a3794e54d255"><code>39a0a15</code></a>
chore(deps): update rolldown-related dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21095">#21095</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/6a34ac3422686e7cf7cc9a25d299cb8e5a8d92a0"><code>6a34ac3</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21096">#21096</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/02ceaec45e17bef19159188a28d9196fed1761be"><code>02ceaec</code></a>
chore(deps): update dependency <code>@​rollup/plugin-commonjs</code> to
v29 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21099">#21099</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/572aaca4594ed2377a4f63443a449e4bf3c0468c"><code>572aaca</code></a>
release: v7.2.2</li>
<li><a
href="https://github.com/vitejs/vite/commit/728c8eeebc0ad7ba48e680f46bbdb55020b2e152"><code>728c8ee</code></a>
fix: revert &quot;refactor: use fs.cpSync (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21019">#21019</a>)&quot;
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21081">#21081</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/a532e68c6b7ed82ae7569d2d3380eb6417e9267d"><code>a532e68</code></a>
release: v7.2.1</li>
<li><a
href="https://github.com/vitejs/vite/commit/82d2d6ccf5a69c3d67e44e3704a0c3eb34db2236"><code>82d2d6c</code></a>
fix(worker): some worker asset was missing (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21074">#21074</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/f83264f5d97caa8ba80276a9ee9e82cb0e69c4ca"><code>f83264f</code></a>
refactor(build): rename <code>indexOfMatchInSlice</code> to
<code>findPreloadMarker</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/21054">#21054</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/8293de0e17af8a876d49761ed6651bd38b709174"><code>8293de0</code></a>
release: v7.2.0</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/create-vite@8.1.0/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 09:46:54 -04:00
dependabot[bot] 14bd50bfd1 Bump python from 63a4c7f to b877e50 (#1100)
Bumps python from `63a4c7f` to `b877e50`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.6-slim&new-version=3.14.6-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 09:46:45 -04:00
dependabot[bot]andCaliBrain 4f123977ff Bump the npm-deps group in /src/frontend with 4 updates (#1091)
Bumps the npm-deps group in /src/frontend with 4 updates:
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom),
[knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip),
[oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) and
[oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint).

Updates `react-router-dom` from 7.17.0 to 7.18.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/react-router-dom@7.18.0/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.18.0</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.18.0"><code>react-router@7.18.0</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/6fb1e79f8304eddd8b78759edea83cb32389ebf5"><code>6fb1e79</code></a>
Release v7.18.0 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15187">#15187</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.18.0/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.17.0 to 6.18.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.18.0</h2>
<ul>
<li>Update dependencies (pin oxc-resolver)
(7dda4eccc65c6d61ef2546442eb752b2a73edab9)</li>
<li>Resolve tsconfig paths for non-TS importers independent of oxc
ownership (3b71565e72107d43cbd6d2ddec7ab2fbbf65c001)</li>
<li>Format (64865f8247b8956def52f1a387234562fbddd667)</li>
<li>Fix false positive for Vitest mocks (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1802">#1802</a>)
(ec93e2013deb53902b406463b30fa6386445f9c9) - thanks <a
href="https://github.com/remcohaszing"><code>@​remcohaszing</code></a>!</li>
<li>Mark npx-run binaries optional unless --no-install (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1803">#1803</a>)
(203c31e1b2bd77eb9c94f82121f353fbf0671c67)</li>
<li>Ignore pnpm [WARN] lines in ecosystem snapshots
(392835a39b9429a3d85d712025da4c6531b8ece6)</li>
<li>Update slonik snapshot
(62d802bf8d53d7790f6322f481a290e09812cbcc)</li>
<li>Update Jest entry patterns for Jest 30 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1808">#1808</a>)
(d2caeddf32ba99ca12e5c26e891b7974392f981a) - thanks <a
href="https://github.com/gwagjiug"><code>@​gwagjiug</code></a>!</li>
<li>Report stale workspaces configuration keys as configuration hints
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1807">#1807</a>)
(9083c16b3313fbebf5cb3cd11cadf45ac773bc3d) - thanks <a
href="https://github.com/WooWan"><code>@​WooWan</code></a>!</li>
</ul>
<h2>Release 6.17.2</h2>
<ul>
<li>Fix up jest plugin (63dbd653b6e1be08a36401f5f728b351ab69e81b)</li>
<li>Detect coverage provider from bare <code>vitest --coverage</code>
flag (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1800">#1800</a>)
(dc11d9fc5458e6e1f734013eb82403eab07af2c1) - thanks <a
href="https://github.com/WooWan"><code>@​WooWan</code></a>!</li>
<li>Don't disable configuration hints in workspace-scoped runs (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1791">#1791</a>)
(8ce1ec8160a786dad90903e43c3ef646ffba9464) - thanks <a
href="https://github.com/WooWan"><code>@​WooWan</code></a>!</li>
<li>Detect react-email v6 packages from non-numeric version ranges
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1798">#1798</a>)
(27a1caeb1bff6abcccd7140c7e92e4a57197ad47)</li>
<li>Discover workspaces included after a negated pattern (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1797">#1797</a>)
(630e152f6f687d9404cc25ffa01f0d49737d9229)</li>
</ul>
<h2>Release 6.17.1</h2>
<ul>
<li>Remove ignoreBinaries w/ tar
(b13d0ca1ce0a201b7e66f725039d9f346b4d424e)</li>
<li>Wrap up docs/refs (29f3e46cc765a70643bcf2ef96e940ff371f39c6)</li>
<li>Update dependencies (7b2f3458176110900204fa49e50650ac50d1f4db)</li>
<li>Fix up vscode-languageclient imports
(820c2335ca63f329f862eb8ec5c264bd8d5f09eb)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/7bfd556b0217f3ee09fd953132bdef860417c44c"><code>7bfd556</code></a>
Release knip@6.18.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/9083c16b3313fbebf5cb3cd11cadf45ac773bc3d"><code>9083c16</code></a>
Report stale workspaces configuration keys as configuration hints (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1807">#1807</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/d2caeddf32ba99ca12e5c26e891b7974392f981a"><code>d2caedd</code></a>
Update Jest entry patterns for Jest 30 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1808">#1808</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/203c31e1b2bd77eb9c94f82121f353fbf0671c67"><code>203c31e</code></a>
Mark npx-run binaries optional unless --no-install (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1803">#1803</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/ec93e2013deb53902b406463b30fa6386445f9c9"><code>ec93e20</code></a>
Fix false positive for Vitest mocks (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1802">#1802</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/64865f8247b8956def52f1a387234562fbddd667"><code>64865f8</code></a>
Format</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/3b71565e72107d43cbd6d2ddec7ab2fbbf65c001"><code>3b71565</code></a>
Resolve tsconfig paths for non-TS importers independent of oxc
ownership</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/7dda4eccc65c6d61ef2546442eb752b2a73edab9"><code>7dda4ec</code></a>
Update dependencies (pin oxc-resolver)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/419805396c10579b51a2576fe70971910ad58b55"><code>4198053</code></a>
Release knip@6.17.2</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/630e152f6f687d9404cc25ffa01f0d49737d9229"><code>630e152</code></a>
Discover workspaces included after a negated pattern (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1797">#1797</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.18.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.55.0 to 0.56.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this package will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0">Keep a Changelog</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/c4be770f24adc4026efa96fb82182f743c55e423"><code>c4be770</code></a>
release(apps): oxlint v1.71.0 &amp;&amp; oxfmt v0.56.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/23707">#23707</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.56.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.70.0 to 1.71.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.71.0] - 2026-06-22</h2>
<h3>🚀 Features</h3>
<ul>
<li>0dc2405 linter: Add schema for
<code>eslint/no-restricted-properties</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23619">#23619</a>)
(Sysix)</li>
<li>b638d0e linter: Add schema for <code>node/callback-return</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23615">#23615</a>)
(Sysix)</li>
<li>eb8bedc linter: Add schema for <code>import/extensions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23557">#23557</a>)
(WaterWhisperer)</li>
<li>46f3625 linter: Implement node/no-sync rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23589">#23589</a>)
(fujitani sora)</li>
<li>b01739a linter: Add schema for
<code>unicorn/numeric-separators-style</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23554">#23554</a>)
(Mikhail Baev)</li>
<li>68afd2a linter/node: Implement <code>no-mixed-requires</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23539">#23539</a>)
(fujitani sora)</li>
<li>a421215 linter: Add schema for
<code>eslint/prefer-destructuring</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23410">#23410</a>)
(WaterWhisperer)</li>
<li>84438be linter/jsdoc: Added missing options to
<code>require-param-description</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23416">#23416</a>)
(kapobajza)</li>
<li>51910df linter/jsdoc: Add missing options to
<code>require-param-type</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23418">#23418</a>)
(kapobajza)</li>
<li>e90925f linter/unicorn: Implement prefer-number-coercion rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23497">#23497</a>)
(Shekhu☺️)</li>
<li>dd1c866 linter/vue: Implement no-async-in-computed-properties rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23493">#23493</a>)
(bab)</li>
<li>b02444e linter: Add schema for <code>react/jsx-no-script-url</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23475">#23475</a>)
(WaterWhisperer)</li>
<li>a8dce46 linter/unicorn: Implement <code>max-nested-calls</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23461">#23461</a>)
(arieleli01212)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>a303c23 linter/jsx-a11y: Align <code>anchor-is-valid</code> config
with upstream (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23446">#23446</a>)
(camc314)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>b50bf4d linter: Remove manually written options doc for
<code>eslint/arrow-body-style</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23490">#23490</a>)
(Mikhail Baev)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/c4be770f24adc4026efa96fb82182f743c55e423"><code>c4be770</code></a>
release(apps): oxlint v1.71.0 &amp;&amp; oxfmt v0.56.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23707">#23707</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/0dc24054119b22247c6a7b9bdb20cc6e589f267a"><code>0dc2405</code></a>
feat(linter): add schema for
<code>eslint/no-restricted-properties</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23619">#23619</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/b638d0ee1df63487e7c04e031b4b71ab10d592ce"><code>b638d0e</code></a>
feat(linter): add schema for <code>node/callback-return</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23615">#23615</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6d355ab8b3644505c4491da5fc4ec88695de50f7"><code>6d355ab</code></a>
refactor(linter): remove <code>number_as_object_schema</code> helper (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23614">#23614</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/eb8bedc2fba9cead8632a75bb7936205fae7dcf0"><code>eb8bedc</code></a>
feat(linter): add schema for <code>import/extensions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23557">#23557</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/46f362530da1c2c5e868613e339999314b9f3a72"><code>46f3625</code></a>
feat(linter): implement node/no-sync rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23589">#23589</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/953c7b3f1c9e2c80ee1b782f1540d277cc22ed99"><code>953c7b3</code></a>
refactor(linter): make <code>unicorn/numeric-separators-style</code>
options <code>u32</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23558">#23558</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/b01739ade376a9862fdb325ac9ef7023f504baf3"><code>b01739a</code></a>
feat(linter): add schema for
<code>unicorn/numeric-separators-style</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23554">#23554</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/68afd2a1f7c8d624b17c0e24880f684d3c7db3c5"><code>68afd2a</code></a>
feat(linter/node): implement <code>no-mixed-requires</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23539">#23539</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/b08e9f5b9e9d948f873d199fb6317997cd296e11"><code>b08e9f5</code></a>
refactor(linter): re-enable schema for
`jsx_a11y/no-noninteractive-element-in...</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.71.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-29 12:23:35 -04:00
dependabot[bot] e3b05d6030 Bump the python-deps group with 3 updates (#1094)
Bumps the python-deps group with 3 updates:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase),
[pytest](https://github.com/pytest-dev/pytest) and
[ruff](https://github.com/astral-sh/ruff).

Updates `seleniumbase` from 4.50.1 to 4.50.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.50.2 - CDP Mode: Patch 117</h2>
<h2>CDP Mode: Patch 117</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/89858eaffdabcacec77b5357a60418b7a8e59c5e">Optimize
CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e32858d3b6f0262570ffc81c13a387bd5f74865c">Update
Dashboard layout</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/12450caa378317d2673a8b375474c11959f21682">Update
CDP Mode examples</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f2e9878ca10ba849221b0905023ed373990cfaf1">Refresh
Python dependencies</a></li>
</ul>
<p>This includes several improvements to CDP Mode:</p>
<ul>
<li>Fixes a bug where temporary user_data_dirs wasn't getting cleaned up
properly.</li>
<li>Fewer asyncio event loops used for browser processes. (Same one for
startup and usage.)</li>
<li>The painted <code>flash()</code> dot is no longer used everywhere
automatically. (Anti-bots started detecting it.)</li>
</ul>
<p>Other updates include:</p>
<ul>
<li>Refreshed Python dependencies.</li>
<li>A small change to Dashboard layout.</li>
<li>Updated examples due to website changes.</li>
</ul>
<p>Special thanks to <a
href="https://github.com/montovaneli"><code>@​montovaneli</code></a>.
(<a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4408">seleniumbase/SeleniumBase#4408</a>)</p>
<p>Changes are expected in version <code>4.50.2</code>.</p>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 117 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4409">seleniumbase/SeleniumBase#4409</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.1...v4.50.2">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.1...v4.50.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/08a5e1b3bb7869425285453263e286a505111206"><code>08a5e1b</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4409">#4409</a>
from seleniumbase/cdp-mode-patch-117</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e2fd3edce00bf7f38ef6ce0ce85322fe114ef5f6"><code>e2fd3ed</code></a>
Version 4.50.2</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f2e9878ca10ba849221b0905023ed373990cfaf1"><code>f2e9878</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/12450caa378317d2673a8b375474c11959f21682"><code>12450ca</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e32858d3b6f0262570ffc81c13a387bd5f74865c"><code>e32858d</code></a>
Update Dashboard layout</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/89858eaffdabcacec77b5357a60418b7a8e59c5e"><code>89858ea</code></a>
Optimize CDP Mode</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.1...v4.50.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `pytest` from 9.1.0 to 9.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.1.1</h2>
<h1>pytest 9.1.1 (2026-06-19)</h1>
<h2>Bug fixes</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14220">#14220</a>:
Fixed a logic bug in <code>pytest.RaisesGroup</code> which would might
cause it to display incorrect &quot;It matches <!-- raw HTML omitted
-->FooError()<!-- raw HTML omitted --> which was paired with <!-- raw
HTML omitted -->BarError<!-- raw HTML omitted -->&quot; messages.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14591">#14591</a>:
Fixed a regression in pytest 9.1.0 which caused overriding a
parametrized fixture with an indirect <!-- raw HTML omitted --><a
href="https://github.com/pytest"><code>@​pytest</code></a>.mark.parametrize<!--
raw HTML omitted --> to fail with &quot;duplicate parametrization of
'&lt;fixture name&gt;'&quot;.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14606">#14606</a>:
Fixed <code>list-item</code> typing errors from mypy in
<code>@pytest.mark.parametrize &lt;pytest.mark.parametrize
ref&gt;</code> <code>argvalues</code> parameter.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14608">#14608</a>:
Fixed a regression in pytest 9.1.0 where <code>conftest.py</code> files
located in <code>&lt;invocation dir&gt;/test*</code> were no longer
loaded as initial conftests when invoked without arguments.
This could cause certain hooks (like <code>pytest_addoption</code>) in
these files to not fire.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pytest-dev/pytest/commit/cf470ec0bf7eb89cd97dd56df4859eae5db46447"><code>cf470ec</code></a>
Prepare release version 9.1.1</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/e0c8ce6cc5db1f08363be6f152c32e6838df2690"><code>e0c8ce6</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14625">#14625</a>
from pytest-dev/patchback/backports/9.1.x/a07c31a97...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/1b82d1694fce22385ee7a4287917fbafbaf2e757"><code>1b82d16</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14624">#14624</a>
from pytest-dev/patchback/backports/9.1.x/b375b79ec...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/501c4bc784da3b08bfcaa64858eba5d15dc59e53"><code>501c4bc</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14596">#14596</a>
from bluetech/doc-classmethod</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/b61f588e36e9377c3d1d3f06bece1da0fc31d9ca"><code>b61f588</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14622">#14622</a>
from chrisburr/fix-14608-initial-conftest-test-subdir</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/9a567e009f4d2da3ce1721c6db3109cb5744d40a"><code>9a567e0</code></a>
[automated] Update plugin list (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14617">#14617</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14618">#14618</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/ef8b2993e5b48639e4a3d97d0525df9760781384"><code>ef8b299</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14620">#14620</a>
from pytest-dev/patchback/backports/9.1.x/680f9f3ed...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/66abd0784d4cb7c1ba44ab9a8896506cd4985acc"><code>66abd07</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14220">#14220</a>
from bysiber/fix-stale-iexp-raisesgroup</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/79fbf93b666cac5f27c9dad047943d47b766c8d5"><code>79fbf93</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14612">#14612</a>
from pytest-dev/patchback/backports/9.1.x/974ed48b6...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/0d312eb876177e9f1c04262b54060a41034ebf5c"><code>0d312eb</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14611">#14611</a>
from bluetech/parametrize-argvalues-typing</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/9.1.0...9.1.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.18 to 0.15.20
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.20</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-25.</p>
<h3>Preview features</h3>
<ul>
<li>Allow human-readable names in rule selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25887">#25887</a>)</li>
<li>Emit a warning instead of an error for unknown rule selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26113">#26113</a>)</li>
<li>Match <code>noqa</code> shebang handling in <code>ruff:ignore</code>
comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26286">#26286</a>)</li>
<li>[<code>ruff</code>] Remove <code>pytest-fixture-autouse</code>
(<code>RUF076</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26240">#26240</a>,
<a
href="https://redirect.github.com/astral-sh/ruff/pull/26371">#26371</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add versioning sections to custom crate READMEs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26317">#26317</a>)</li>
<li>Update <code>ruff_python_parser</code> README for crates.io (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26315">#26315</a>)</li>
<li>[<code>perflint</code>] Clarify that <code>PERF402</code> applies to
any iterable (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26242">#26242</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/dhruvmanila"><code>@​dhruvmanila</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/trilamsr"><code>@​trilamsr</code></a></li>
</ul>
<h2>Install ruff 0.15.20</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-installer.ps1
| iex&quot;
</code></pre>
<h2>Download ruff 0.15.20</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-pc-windows-msvc.zip">ruff-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-unknown-linux-gnu.tar.gz">ruff-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-unknown-linux-gnu.tar.gz">ruff-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.20/ruff-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.20</h2>
<p>Released on 2026-06-25.</p>
<h3>Preview features</h3>
<ul>
<li>Allow human-readable names in rule selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25887">#25887</a>)</li>
<li>Emit a warning instead of an error for unknown rule selectors (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26113">#26113</a>)</li>
<li>Match <code>noqa</code> shebang handling in <code>ruff:ignore</code>
comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26286">#26286</a>)</li>
<li>[<code>ruff</code>] Remove <code>pytest-fixture-autouse</code>
(<code>RUF076</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26240">#26240</a>,
<a
href="https://redirect.github.com/astral-sh/ruff/pull/26371">#26371</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add versioning sections to custom crate READMEs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26317">#26317</a>)</li>
<li>Update <code>ruff_python_parser</code> README for crates.io (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26315">#26315</a>)</li>
<li>[<code>perflint</code>] Clarify that <code>PERF402</code> applies to
any iterable (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26242">#26242</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/dhruvmanila"><code>@​dhruvmanila</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/trilamsr"><code>@​trilamsr</code></a></li>
</ul>
<h2>0.15.19</h2>
<p>Released on 2026-06-23.</p>
<h3>Preview features</h3>
<ul>
<li>Support human-readable names when hovering suppression comments and
in code actions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26114">#26114</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fall back to default settings when editor-only settings are invalid
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/26244">#26244</a>)</li>
<li>Fix panic when inserting text at a notebook cell boundary (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26111">#26111</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Update fix suggestions for
<code>__floor__</code>, <code>__trunc__</code>,
<code>__length_hint__</code>, and <code>__matmul__</code> variants
(<code>PLC2801</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26239">#26239</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid allocating when parsing single string literals (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26200">#26200</a>)</li>
<li>Avoid reallocating singleton call arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26223">#26223</a>)</li>
<li>Lazily create source files for lint diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26226">#26226</a>)</li>
<li>Optimize formatter text width and indentation (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26236">#26236</a>)</li>
<li>Reserve capacity for builtin bindings (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26229">#26229</a>)</li>
<li>Skip repeated-key checks for singleton dictionaries (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26228">#26228</a>)</li>
<li>Use ArrayVec for qualified name segments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26224">#26224</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/f82a36b6baf8c0547a17bbde6c0d927ccd45d938"><code>f82a36b</code></a>
Bump 0.15.20 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26376">#26376</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/af329438b55d5aa8ca28725f17abbae63b5c815d"><code>af32943</code></a>
Improve the summarise-ecosystem-results skill (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26378">#26378</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/485ebab5de692aad34720898cd80245b6092ba86"><code>485ebab</code></a>
Remove <code>RUF076</code> name from schema (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26371">#26371</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ef81835ce3da615346584dc446de0fe26bfc154b"><code>ef81835</code></a>
[ty] Implement rust-analyzer's &quot;Click for full compiler
diagnostic&quot; feature (...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/572b31e2377a701a7365f069f6ef87002962cb2b"><code>572b31e</code></a>
[<code>ruff</code>] Remove <code>pytest-fixture-autouse</code>
(<code>RUF076</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26240">#26240</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f703f219d7fddd1a4abba9fa81e34773c185a4b9"><code>f703f21</code></a>
Allow human-readable names in rule selectors (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25887">#25887</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/0d726b28ee35413926145ffef4ac1143cae9ea1e"><code>0d726b2</code></a>
[ty] Reuse equality semantics for membership compatibility (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25955">#25955</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/dbe6e9848c3f78fdaf543cfc000939ebc73b5f00"><code>dbe6e98</code></a>
[ty] Infer definite equality comparison results (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26337">#26337</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e700ea357a2196d76b58eb89b2031ddb5ca896e0"><code>e700ea3</code></a>
[ty] Prove TypedDict structural patterns exhaustive (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26285">#26285</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6a0d2ec93959d966430b8c39d4de5c3e8a88e911"><code>6a0d2ec</code></a>
[ty] Widen inferred class-valued instance attributes (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26338">#26338</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.18...0.15.20">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 12:23:19 -04:00
dependabot[bot] 995d8d6631 Bump @types/node from 25.9.3 to 26.0.0 in /src/frontend (#1092)
Bumps
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
from 25.9.3 to 26.0.0.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=25.9.3&new-version=26.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 14:54:15 -04:00
dependabot[bot] 9a27334d9c Bump the gh-actions group with 2 updates (#1093)
Bumps the gh-actions group with 2 updates:
[actions/checkout](https://github.com/actions/checkout) and
[dorny/paths-filter](https://github.com/dorny/paths-filter).

Updates `actions/checkout` from 4 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
<h2>v6.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID
is set by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.1">https://github.com/actions/checkout/compare/v6...v6.0.1</a></p>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"><code>9c091bb</code></a>
update error wording (<a
href="https://redirect.github.com/actions/checkout/issues/2467">#2467</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/1044a6dea927916f2c38ba5aeffbc0a847b1221a"><code>1044a6d</code></a>
getting ready for checkout v7 release (<a
href="https://redirect.github.com/actions/checkout/issues/2464">#2464</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f0282184c7ce73ab54c7e4ab5a617122602e575f"><code>f028218</code></a>
Bump the minor-npm-dependencies group across 1 directory with 3 updates
(<a
href="https://redirect.github.com/actions/checkout/issues/2462">#2462</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/d914b262ffc244530a203ab40decab34c3abf34d"><code>d914b26</code></a>
upgrade module to esm and update dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2463">#2463</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/537c7ef99cef6e5ddb5e7ff5d16d14510503801d"><code>537c7ef</code></a>
Bump <code>@​actions/core</code> and <code>@​actions/tool-cache</code>
and Remove uuid (<a
href="https://redirect.github.com/actions/checkout/issues/2459">#2459</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/130a169078a413d3a5246a393625e8e742f387f6"><code>130a169</code></a>
Bump js-yaml from 4.1.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2461">#2461</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/7d09575332117a40b46e5e020664df234cd416f3"><code>7d09575</code></a>
Bump flatted from 3.3.1 to 3.4.2 (<a
href="https://redirect.github.com/actions/checkout/issues/2460">#2460</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/0f9f3aa320cb53abeb534aeb54048075d9697a0e"><code>0f9f3aa</code></a>
Bump actions/publish-immutable-action (<a
href="https://redirect.github.com/actions/checkout/issues/2458">#2458</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f9e715a95fcd1f9253f77dd28f11e88d2d6460c7"><code>f9e715a</code></a>
block checking out fork pr for pull_request_target and workflow_run (<a
href="https://redirect.github.com/actions/checkout/issues/2454">#2454</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/df4cb1c069e1874edd31b4311f1884172cec0e10"><code>df4cb1c</code></a>
Update changelog for v6.0.3 (<a
href="https://redirect.github.com/actions/checkout/issues/2446">#2446</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `dorny/paths-filter` from 3 to 4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/releases">dorny/paths-filter's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: update action runtime to node24 by <a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
in <a
href="https://redirect.github.com/dorny/paths-filter/pull/294">dorny/paths-filter#294</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/saschabratton"><code>@​saschabratton</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/294">dorny/paths-filter#294</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3.0.3...v4.0.0">https://github.com/dorny/paths-filter/compare/v3.0.3...v4.0.0</a></p>
<h2>v3.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Add missing predicate-quantifier by <a
href="https://github.com/wardpeet"><code>@​wardpeet</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/279">dorny/paths-filter#279</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/wardpeet"><code>@​wardpeet</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/279">dorny/paths-filter#279</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3...v3.0.3">https://github.com/dorny/paths-filter/compare/v3...v3.0.3</a></p>
<h2>v3.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: add config parameter for predicate quantifier by <a
href="https://github.com/petermetz"><code>@​petermetz</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/224">dorny/paths-filter#224</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/petermetz"><code>@​petermetz</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/224">dorny/paths-filter#224</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3...v3.0.2">https://github.com/dorny/paths-filter/compare/v3...v3.0.2</a></p>
<h2>v3.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Compare base and ref when token is empty by <a
href="https://github.com/frouioui"><code>@​frouioui</code></a> in <a
href="https://redirect.github.com/dorny/paths-filter/pull/133">dorny/paths-filter#133</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/frouioui"><code>@​frouioui</code></a>
made their first contribution in <a
href="https://redirect.github.com/dorny/paths-filter/pull/133">dorny/paths-filter#133</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dorny/paths-filter/compare/v3...v3.0.1">https://github.com/dorny/paths-filter/compare/v3...v3.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md">dorny/paths-filter's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v4.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/294">Update
action runtime to node24</a></li>
</ul>
<h2>v3.0.3</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/279">Add
missing predicate-quantifier</a></li>
</ul>
<h2>v3.0.2</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/224">Add
config parameter for predicate quantifier</a></li>
</ul>
<h2>v3.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/133">Compare
base and ref when token is empty</a></li>
</ul>
<h2>v3.0.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/210">Update to
Node.js 20</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/215">Update
all dependencies</a></li>
</ul>
<h2>v2.11.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/167">Update
@​actions/core to v1.10.0 - Fixes warning about deprecated
set-output</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/168">Document
need for pull-requests: read permission</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/164">Updating
to actions/checkout@v3</a></li>
</ul>
<h2>v2.11.0</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/157">Set
list-files input parameter as not required</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/161">Update
Node.js</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/162">Fix
incorrect handling of Unicode characters in exec()</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/163">Use
Octokit pagination</a></li>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/160">Updates
real world links</a></li>
</ul>
<h2>v2.10.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/91">Fix
getLocalRef() returns wrong ref</a></li>
</ul>
<h2>v2.10.1</h2>
<ul>
<li><a
href="https://redirect.github.com/dorny/paths-filter/pull/85">Improve
robustness of change detection</a></li>
</ul>
<h2>v2.10.0</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/82">Add
ref input parameter</a></li>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/83">Fix
change detection in PR when pullRequest.changed_files is
incorrect</a></li>
</ul>
<h2>v2.9.3</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/78">Fix
change detection when base is a tag</a></li>
</ul>
<h2>v2.9.2</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/75">Fix
fetching git history</a></li>
</ul>
<h2>v2.9.1</h2>
<ul>
<li><a href="https://redirect.github.com/dorny/paths-filter/pull/74">Fix
fetching git history + fallback to unshallow repo</a></li>
</ul>
<h2>v2.9.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/dorny/paths-filter/commit/fbd0ab8f3e69293af611ebaee6363fc25e6d187d"><code>fbd0ab8</code></a>
feat: add merge_group event support</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/efb1da7ce8d89bbc261191e5a2dc1453c3837339"><code>efb1da7</code></a>
feat: add dist/ freshness check to PR workflow</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/d8f7b061b24c30a325ff314b76c37adb05b041ce"><code>d8f7b06</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/302">#302</a>
from dorny/issue-299</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/addbc147a95845176e1bc013a012fbf1d366389a"><code>addbc14</code></a>
Update README for v4</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/9d7afb8d214ad99e78fbd4247752c4caed2b6e4c"><code>9d7afb8</code></a>
Update CHANGELOG for v4.0.0</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/782470c5d953cae2693d643172b14e01bacb71f3"><code>782470c</code></a>
Merge branch 'releases/v3'</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/ce10459c8b92cd8901166c0a222fbb033ef39365"><code>ce10459</code></a>
Merge pull request <a
href="https://redirect.github.com/dorny/paths-filter/issues/294">#294</a>
from saschabratton/master</li>
<li><a
href="https://github.com/dorny/paths-filter/commit/5f40380c5482e806c81cec080f5192e7234d8fe9"><code>5f40380</code></a>
feat: update action runtime to node24</li>
<li>See full diff in <a
href="https://github.com/dorny/paths-filter/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 14:54:07 -04:00
dependabot[bot] 76c55a488c Bump node from 156b55f to a0b9bf0 in the docker-base-image-digests group (#1089)
Bumps the docker-base-image-digests group with 1 update: node.

Updates `node` from `156b55f` to `a0b9bf0`


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=node&package-manager=docker&previous-version=24-alpine&new-version=24-alpine)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 14:53:45 -04:00
dependabot[bot] 08d0a04cf2 Bump python from 44dd044 to 63a4c7f (#1090)
Bumps python from `44dd044` to `63a4c7f`.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.6-slim&new-version=3.14.6-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 14:53:28 -04:00
CaliBrain 36f9a52987 Annotate both the per-platform manifests and the multi-arch image index (#1088)
Fixes #1087
2026-06-24 11:56:57 -04:00
CaliBrain 1536b91a46 Fix e2e scipts (#1086) 2026-06-24 00:09:06 -04:00
CaliBrain fea63269e3 the e2e platform test profiles live in an env/ dir and must be tracked (#1085) 2026-06-23 21:28:25 -04:00
CaliBrain 7886ba7038 fix astral-sh-setup-uv (#1084) 2026-06-23 17:43:59 -04:00
CaliBrain 1c19326bd0 e2e testing 2 (#1083) 2026-06-23 16:58:24 -04:00
CaliBrain 2f70ed36e4 e2e testing (#1082) 2026-06-23 15:38:46 -04:00
dependabot[bot] 8d54cff383 Bump the python-deps group with 3 updates (#1081)
Bumps the python-deps group with 3 updates:
[tqdm](https://github.com/tqdm/tqdm),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[ruff](https://github.com/astral-sh/ruff).

Updates `tqdm` from 4.68.2 to 4.68.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.68.3 stable</h2>
<ul>
<li><code>utils</code>: delay <code>os.get_terminal_size</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1763">#1763</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a>)</li>
<li><code>autonotebook</code>: support QtConsole, Spyder, JupyterLite
(<a href="https://redirect.github.com/tqdm/tqdm/issues/1763">#1763</a>,
<a href="https://redirect.github.com/tqdm/tqdm/issues/1628">#1628</a>,
<a href="https://redirect.github.com/tqdm/tqdm/issues/1559">#1559</a>
&lt;- <a
href="https://redirect.github.com/tqdm/tqdm/issues/1283">#1283</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1098">#1098</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/512">#512</a>)</li>
<li>minor docs updates
<ul>
<li>fix typo (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1762">#1762</a>)</li>
<li>use <code>git-fame</code></li>
</ul>
</li>
<li>misc minor framework updates
<ul>
<li>fix &amp; update CI build</li>
<li>pre-commit: add docs &amp; metadata generation</li>
<li>move <code>tox.ini</code> -&gt; <code>pyproject.toml</code>, move
<code>tox-gh-actions</code> -&gt; <code>tox-gh</code></li>
<li>add Python 3.14, drop 3.7 support</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/9aff6090b6fa98c88a2dbff8bd9e2a68d9a99c1b"><code>9aff609</code></a>
bump version, merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1763">#1763</a> from
tqdm/jupyterlite</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/9872f80e0d9ceb8377b45c714ec8f6ae66bf9ef9"><code>9872f80</code></a>
drop date from snap version str to fix pydantic</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/b82933405f6dc19dd8f667be57fd2058a00f75c7"><code>b829334</code></a>
support QtConsole, Spyder, JupyterLite</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/6fa4867b27dd4852204aa13f73300db41791cd46"><code>6fa4867</code></a>
delay os.get_terminal_size</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/748e107287c9a66e3a366cd5366bd9a8bcbe33ae"><code>748e107</code></a>
lint</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/e6e29eb7a191d366d21b93817c6de3857b664367"><code>e6e29eb</code></a>
move tox.ini -&gt; pyproject.toml</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/617e4faf67d6cc59d42e3b2665b0c1199a665db4"><code>617e4fa</code></a>
tox-gh-actions -&gt; tox-gh</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/c49c50d83124e514d2b6bb549661ff1e2fa44504"><code>c49c50d</code></a>
add python 3.14, drop python 3.7 support</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/fa2bcdb4ad68d4e95bd49460d8d590451cf478ba"><code>fa2bcdb</code></a>
pre-commit: tqdm.1</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/1ec798811a960294d74d42d35b6614e3273e9fe3"><code>1ec7988</code></a>
auto git-fame</li>
<li>Additional commits viewable in <a
href="https://github.com/tqdm/tqdm/compare/v4.68.2...v4.68.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.49.14 to 4.50.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.50.1 - Fix Layout in Recorder App</h2>
<h2>Fix Layout in Recorder App</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/77cb1e267c04f60c8329ae6a00eb581d003d22fc">Fix
the layout of the SeleniumBase Recorder App</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Fix Layout in Recorder App by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4405">seleniumbase/SeleniumBase#4405</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.50.0...v4.50.1">https://github.com/seleniumbase/SeleniumBase/compare/v4.50.0...v4.50.1</a></p>
<h2>4.50.0 - Improve Recorder and Fix Bugs</h2>
<h2>Improve Recorder and Fix Bugs</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/04acb5e8dc1c3621fe8e36529023a4fae8eebc7f">Improve
the desktop Recorder App and Recorder Mode</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4403">seleniumbase/SeleniumBase#4403</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8a9a8eb8dbfa6f90166564769fea5244eafaa32f">Fix
sb.solve_captcha() on Windows for Slider CAPTCHAs</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4399">seleniumbase/SeleniumBase#4399</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8a39a469f0b09b7aff6e7b3e2dc0a7608dbdb027">Prevent
cleanup warnings on Windows</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4400">seleniumbase/SeleniumBase#4400</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d72f80972432117bb23e9a37f2f1e6c8cdbac365">Fix
issue with get_title() failing at random</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4401">seleniumbase/SeleniumBase#4401</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/13796feaaab122cfa8678644d95644d50cd5485f">Update
the docs</a>
-- It's mostly around the updated Recorder</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/221adbf8349cf0632290be5ec8fd1c135c4b9dac">Refresh
Python dependencies</a>
-- <code>selenium</code> and <code>certifi</code></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Improved Recorder App and Bug Fixes by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4404">seleniumbase/SeleniumBase#4404</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.14...v4.50.0">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.14...v4.50.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/93bf553426926a512457dc9e64a5a936e723041a"><code>93bf553</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4405">#4405</a>
from seleniumbase/fix-recorder-app-layout</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fd8a6965f102f87f548ca2ca07a143ad90e9bd50"><code>fd8a696</code></a>
Version 4.50.1</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/18ee81c21f2a899ca17891c1cee6168ec146a54e"><code>18ee81c</code></a>
Update Recorder App image in a ReadMe</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/77cb1e267c04f60c8329ae6a00eb581d003d22fc"><code>77cb1e2</code></a>
Fix the layout of the SeleniumBase Recorder App</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0c5867d71a4d8b966e61b18b33ac90c9b28ae130"><code>0c5867d</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4404">#4404</a>
from seleniumbase/improved-recorder-app-and-bug-fixes</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a5ac4e8d5b8ae02a591d84c73494e4caaca2c83f"><code>a5ac4e8</code></a>
Version 4.50.0</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/221adbf8349cf0632290be5ec8fd1c135c4b9dac"><code>221adbf</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/27b2fb0a38cdfb5d90aea74235cae8e655c2df1a"><code>27b2fb0</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/13796feaaab122cfa8678644d95644d50cd5485f"><code>13796fe</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d72f80972432117bb23e9a37f2f1e6c8cdbac365"><code>d72f809</code></a>
Fix issue with <code>get_title()</code> failing at random</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.14...v4.50.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.17 to 0.15.18
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.18</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-18.</p>
<h3>Preview features</h3>
<ul>
<li>Handle nested <code>ruff:ignore</code> comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25791">#25791</a>)</li>
<li>Stop displaying severity in output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26050">#26050</a>)</li>
<li>Use human-readable names in CLI output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25937">#25937</a>)</li>
<li>Use human-readable names in LSP and playground diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26058">#26058</a>)</li>
<li>[<code>pydocstyle</code>] Prevent property docstrings starting with
verbs (<code>D421</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23775">#23775</a>)</li>
<li>[<code>flake8-pyi</code>] Extend <code>PYI033</code> to Python files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/26129">#26129</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Detect equivalent numeric mapping keys (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26009">#26009</a>)</li>
<li>Detect mapping keys equivalent to booleans (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25982">#25982</a>)</li>
<li>Detect repeated signed and complex dictionary keys (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26007">#26007</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Rename <code>PYI033</code> to
<code>legacy-type-comment</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26131">#26131</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Use <code>ThinVec</code> for call keywords (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25999">#25999</a>)</li>
<li>Inline parser recovery context checks (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26038">#26038</a>)</li>
<li>Match parser keywords as bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26037">#26037</a>)</li>
<li>Move value parsing out of lexing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25360">#25360</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Render subdiagnostics and secondary annotations as related
information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26011">#26011</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Update fix availability for always-fixable rules (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26091">#26091</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Add fix safety section
(<code>TID252</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/17491">#17491</a>)</li>
</ul>
<h3>Parser</h3>
<ul>
<li>Reject <code>__debug__</code> lambda parameters (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26022">#26022</a>)</li>
<li>Reject <code>_</code> as a match-pattern target (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25977">#25977</a>)</li>
<li>Reject multiple starred names in sequence patterns (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25976">#25976</a>)</li>
<li>Reject parenthesized star imports (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26021">#26021</a>)</li>
<li>Reject starred comprehension targets (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26023">#26023</a>)</li>
<li>Reject unparenthesized generator expressions in class bases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25978">#25978</a>)</li>
<li>Reject <code>yield</code> expressions after commas (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26024">#26024</a>)</li>
<li>Validate function type parameter default order (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25981">#25981</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.18</h2>
<p>Released on 2026-06-18.</p>
<h3>Preview features</h3>
<ul>
<li>Handle nested <code>ruff:ignore</code> comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25791">#25791</a>)</li>
<li>Stop displaying severity in output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26050">#26050</a>)</li>
<li>Use human-readable names in CLI output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25937">#25937</a>)</li>
<li>Use human-readable names in LSP and playground diagnostics (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26058">#26058</a>)</li>
<li>[<code>pydocstyle</code>] Prevent property docstrings starting with
verbs (<code>D421</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23775">#23775</a>)</li>
<li>[<code>flake8-pyi</code>] Extend <code>PYI033</code> to Python files
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/26129">#26129</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Detect equivalent numeric mapping keys (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26009">#26009</a>)</li>
<li>Detect mapping keys equivalent to booleans (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25982">#25982</a>)</li>
<li>Detect repeated signed and complex dictionary keys (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26007">#26007</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pyi</code>] Rename <code>PYI033</code> to
<code>legacy-type-comment</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26131">#26131</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Use <code>ThinVec</code> for call keywords (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25999">#25999</a>)</li>
<li>Inline parser recovery context checks (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26038">#26038</a>)</li>
<li>Match parser keywords as bytes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26037">#26037</a>)</li>
<li>Move value parsing out of lexing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25360">#25360</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Render subdiagnostics and secondary annotations as related
information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26011">#26011</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Update fix availability for always-fixable rules (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26091">#26091</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Add fix safety section
(<code>TID252</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/17491">#17491</a>)</li>
</ul>
<h3>Parser</h3>
<ul>
<li>Reject <code>__debug__</code> lambda parameters (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26022">#26022</a>)</li>
<li>Reject <code>_</code> as a match-pattern target (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25977">#25977</a>)</li>
<li>Reject multiple starred names in sequence patterns (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25976">#25976</a>)</li>
<li>Reject parenthesized star imports (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26021">#26021</a>)</li>
<li>Reject starred comprehension targets (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26023">#26023</a>)</li>
<li>Reject unparenthesized generator expressions in class bases (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25978">#25978</a>)</li>
<li>Reject <code>yield</code> expressions after commas (<a
href="https://redirect.github.com/astral-sh/ruff/pull/26024">#26024</a>)</li>
<li>Validate function type parameter default order (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25981">#25981</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/6686f63404207bfdffe8ab0acb25da72c3432190"><code>6686f63</code></a>
Bump 0.15.18 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26135">#26135</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/efbb7325ff5bb92b0a0c0a0efa0ac94e439ee367"><code>efbb732</code></a>
[ty] Suggest keyword-only arguments between variadic parameters (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26134">#26134</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c256d5f573e66612556061bfd0af527136a23c30"><code>c256d5f</code></a>
[ty] Support <code>Annotated[Any, ...]</code> as a class base (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26133">#26133</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/19a4bea1af5b252798d85696f2f397dae91d303d"><code>19a4bea</code></a>
[flake8-pyi] Rename PYI033 to legacy-type-comment (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26131">#26131</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/1d9866cbd673dc68153ad162465e979c47e62a96"><code>1d9866c</code></a>
Bump ecosystem-analyzer commit (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26130">#26130</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/8656c731dded1e91c0e2713405e43bb2c4eb53bf"><code>8656c73</code></a>
[ty] Compact indexed AST node storage (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25998">#25998</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/c17c8d9a060f839c0f9b69c69b85d3802ec5dfdf"><code>c17c8d9</code></a>
[ty] Garbage-collect cached constraint sets (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26116">#26116</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ef0fb8fa264035974e57fda59e2baf196ec1fb9e"><code>ef0fb8f</code></a>
[ty] Fix bound TypeVar default cycle recovery (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26124">#26124</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b83c02489df8bccda7313a2cdd8369c9b5d1b002"><code>b83c024</code></a>
[flake8-pyi] Extend PYI033 to Python files in preview (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26129">#26129</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e8a5e38858558a68e94397152fd735cacb6ea3b4"><code>e8a5e38</code></a>
Update Rust crate zip to v8 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/26078">#26078</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.17...0.15.18">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 13:36:49 -04:00
dependabot[bot]andCaliBrain 63fa6213da Bump the npm-deps group in /src/frontend with 6 updates (#1077)
Bumps the npm-deps group in /src/frontend with 6 updates:

| Package | From | To |
| --- | --- | --- |
|
[@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)
| `4.3.0` | `4.3.1` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.16.1` | `6.17.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.54.0` | `0.55.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.69.0` | `1.70.0` |
|
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
| `4.3.0` | `4.3.1` |
|
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
| `4.1.8` | `4.1.9` |

Updates `@tailwindcss/vite` from 4.3.0 to 4.3.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">@​tailwindcss/vite's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.1</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Generate <code>0</code> instead of <code>calc(var(--spacing) *
0)</code> for spacing utilities like <code>m-0</code> and
<code>left-0</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
<li>Generate <code>var(--spacing)</code> instead of
<code>calc(var(--spacing) * 1)</code> for spacing utilities like
<code>m-1</code> and <code>left-1</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">@​tailwindcss/vite's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.1] - 2026-06-12</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Generate <code>0</code> instead of <code>calc(var(--spacing) *
0)</code> for spacing utilities like <code>m-0</code> and
<code>left-0</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
<li>Generate <code>var(--spacing)</code> instead of
<code>calc(var(--spacing) * 1)</code> for spacing utilities like
<code>m-1</code> and <code>left-1</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/8a14a710102cae195f6811e8578bef9477bc6be9"><code>8a14a71</code></a>
4.3.1 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/20226">#20226</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/73983e1cf5bc0ae721f4568cc24a5b5067b6b90b"><code>73983e1</code></a>
Fix 'Sourcemap is likely to be incorrect' warnings when using
`@tailwindcss/v...</li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.16.1 to 6.17.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.17.0</h2>
<ul>
<li>chore(mcp): add package metadata links (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1783">#1783</a>)
(e3d93b930) - thanks <a
href="https://github.com/sh962214-hub"><code>@​sh962214-hub</code></a>!</li>
<li>fix(capacitor): detect iOS platform with Swift Package Manager (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1787">#1787</a>)
(e6cc533a8) - thanks <a
href="https://github.com/jthrilly"><code>@​jthrilly</code></a>!</li>
<li>Support ignoreIssues per workspace (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1782">#1782</a>)
(15a329a05)</li>
<li>Add commitlint.config.mts (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1784">#1784</a>)
(fa8eb6da8)</li>
<li>Treat scoped and tilde SCSS imports as packages (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1786">#1786</a>)
(98aa9623e)</li>
<li>Add followCursor setting for Imports/Exports views (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1788">#1788</a>)
(67a0be89f)</li>
<li>Flag undeclared sibling imports in published workspaces (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1792">#1792</a>)
(aeabff789)</li>
<li>Fix type-check errors in vscode-knip (12f266e94)</li>
<li>Note Markdown formatting with pnpm remark (bdffeec0d)</li>
<li>Bump some doc-related dependencies (333419303)</li>
<li>Update vscode-knip tool descriptions (be341788c)</li>
<li>Overhaul docs (55e3f3bda)</li>
<li>Improve mcp guidance (67483f0ac)</li>
<li>Fix repeated --fix-type arg (9bb0512ca)</li>
<li>Resolve module paths from selected tsconfig (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1794">#1794</a>)
(1c2f39833)</li>
<li>Update sanity snapshot (4ebce9c50)</li>
<li>Add tar to globally ignored binaries (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1796">#1796</a>)
(8c028e5fb)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/dd0c682f9c41cfcd428458ece2cd32553824a550"><code>dd0c682</code></a>
Release knip@6.17.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/8c028e5fb25e989591689805c335ffd80a651bfd"><code>8c028e5</code></a>
Add tar to globally ignored binaries (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1796">#1796</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/1c2f398331fddc9beddfc438ac5ce529ec9e070c"><code>1c2f398</code></a>
Resolve module paths from selected tsconfig (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1794">#1794</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/9bb0512ca0e06f61117076fb8bfa806dfe3f7fb1"><code>9bb0512</code></a>
Fix repeated --fix-type arg</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/67483f0ac6ea6845631ffdef0425de6b41092e26"><code>67483f0</code></a>
Improve mcp guidance</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/aeabff789071e7451ed88744ac70621d6d29249f"><code>aeabff7</code></a>
Flag undeclared sibling imports in published workspaces (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1792">#1792</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/98aa9623e3794b6fe783e0ce2c11a0e4acf2b8c2"><code>98aa962</code></a>
Treat scoped and tilde SCSS imports as packages (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1786">#1786</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/fa8eb6da81066f835fbca05d640348bd9b2b8eda"><code>fa8eb6d</code></a>
Add commitlint.config.mts (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1784">#1784</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/15a329a0555b3496fe4018a39cb5cb734fbb9eba"><code>15a329a</code></a>
Support ignoreIssues per workspace (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1782">#1782</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e6cc533a8772cdc4aba93cac376d214fb2fb5a58"><code>e6cc533</code></a>
fix(capacitor): detect iOS platform with Swift Package Manager (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1787">#1787</a>)</li>
<li>See full diff in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.17.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.54.0 to 0.55.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.55.0] - 2026-06-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>9a2788b linter/unicorn: Implement <code>prefer-export-from</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22935">#22935</a>)
(AliceLanniste)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/aa79b5be9915068f60bc361febf2e7496b92fc24"><code>aa79b5b</code></a>
release(apps): oxlint v1.70.0 &amp;&amp; oxfmt v0.55.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/23442">#23442</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/9a2788b3ae60c033a969fbba63733748f8c6130a"><code>9a2788b</code></a>
feat(linter/unicorn): implement <code>prefer-export-from</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22935">#22935</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.55.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.69.0 to 1.70.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.70.0] - 2026-06-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>2e8bda4 linter/vue: Implement no-dupe-keys rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23350">#23350</a>)
(bab)</li>
<li>1490a0a linter/react: Implement react-compiler rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23202">#23202</a>)
(Boshen)</li>
<li>dd560ae linter/unicorn: Implement
<code>no-array-fill-with-reference-type</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23397">#23397</a>)
(Mikhail Baev)</li>
<li>af36c2f linter: Add schema for
<code>react/jsx-curly-brace-presence</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23400">#23400</a>)
(WaterWhisperer)</li>
<li>47d34a3 linter: Add schema for <code>react/jsx-handler-names</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23393">#23393</a>)
(WaterWhisperer)</li>
<li>f4250d0 linter: Add schema for <code>unicorn/import-style</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23386">#23386</a>)
(WaterWhisperer)</li>
<li>30c74ce linter: Add schema for
<code>jsx_a11y/no-noninteractive-element-to-interactive-role</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23384">#23384</a>)
(Sysix)</li>
<li>cfbe8dc linter: Add schema for
<code>jsx_a11y/no-interactive-element-to-noninteractive-role</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23382">#23382</a>)
(WaterWhisperer)</li>
<li>d15b7ff linter: Add schema for
<code>typescript/no-restricted-types</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23381">#23381</a>)
(WaterWhisperer)</li>
<li>028a811 linter: Add schema for
<code>jsx-a11y/media-has-caption</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23377">#23377</a>)
(Sysix)</li>
<li>b3b1038 linter: Add schema for
<code>jsx-a11y/label-has-associated-control</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23376">#23376</a>)
(Sysix)</li>
<li>7ada6b2 linter: Add schema for
<code>jsx_a11y/no-distracting-elements</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23379">#23379</a>)
(WaterWhisperer)</li>
<li>ee3dd49 linter: Add schema for
<code>jsx-a11y/img-redundant-alt</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23374">#23374</a>)
(Sysix)</li>
<li>df5f8dd linter: Add short descriptions to most lint rules. (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23365">#23365</a>)
(Connor Shea)</li>
<li>e3fd735 linter: Add schema for <code>jsx_a11y/alt-text</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23369">#23369</a>)
(Sysix)</li>
<li>0f2fff4 linter: Add schema for <code>react/exhaustive-deps</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23372">#23372</a>)
(Mikhail Baev)</li>
<li>e3e4e10 linter: Add schema for
<code>react_perf/jsx-no-new-object-as-prop</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23368">#23368</a>)
(Mikhail Baev)</li>
<li>9366d44 linter: Add schema for <code>unicorn/prefer-at</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23366">#23366</a>)
(WaterWhisperer)</li>
<li>f57b55d linter: Add schema for <code>typescript/array-type</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23355">#23355</a>)
(Sysix)</li>
<li>0dcf912 linter: Add schema for
<code>typescript/ban-ts-comment</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23354">#23354</a>)
(Sysix)</li>
<li>51fa83e linter: Add schema for
<code>react/no-did-update-set-state</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23357">#23357</a>)
(Mikhail Baev)</li>
<li>59db0bd linter: Add schema for
<code>consistent-generic-constructors</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23353">#23353</a>)
(Sysix)</li>
<li>c4775c0 linter: Add schema for
<code>typescript/consistent-type-assertions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23349">#23349</a>)
(Sysix)</li>
<li>6e516f7 linter: Add schema for
<code>typescript/consistent-type-imports</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23348">#23348</a>)
(Sysix)</li>
<li>012134d linter: Add schema for
<code>react/jsx-no-target-blank</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23345">#23345</a>)
(WaterWhisperer)</li>
<li>0806aae linter: Add schema for
<code>jsx_a11y/no-noninteractive-tabindex</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23337">#23337</a>)
(Mikhail Baev)</li>
<li>0708b5a linter: Add schema for
<code>react/jsx-filename-extension</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23315">#23315</a>)
(Mikhail Baev)</li>
<li>150bce1 linter: Add schema for
<code>typescript/no-empty-object-type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23309">#23309</a>)
(Sysix)</li>
<li>f9e36f1 linter: Add schema for
<code>typescript/no-duplicate-type-constituents</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23308">#23308</a>)
(Sysix)</li>
<li>937accf linter: Add schema for
<code>typescript/no-invalid-void-type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23307">#23307</a>)
(Sysix)</li>
<li>3e042b9 linter: Add schema for
<code>typescript/no-misused-promises</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23306">#23306</a>)
(Sysix)</li>
<li>da212d1 linter: Add schema for
<code>typescript/no-unnecessary-condition</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23305">#23305</a>)
(Sysix)</li>
<li>f8f0d38 linter: Add schema for
<code>typescript/parameter-properties</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23304">#23304</a>)
(Sysix)</li>
<li>2275fc7 linter: Add schema for
<code>typescript/prefer-nullish-coalescing</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23302">#23302</a>)
(Sysix)</li>
<li>d353858 linter: Add schema for
<code>typescript/prefer-string-starts-ends-with</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23301">#23301</a>)
(Sysix)</li>
<li>03060f5 linter: Add schema for
<code>typescript/triple-slash-reference</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23300">#23300</a>)
(Sysix)</li>
<li>6619cee linter: Add schema for <code>promise/param-names</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23298">#23298</a>)
(Sysix)</li>
<li>8bf108e linter: Add schema for <code>promise/catch-or-return</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23297">#23297</a>)
(Sysix)</li>
<li>48158d0 linter: Add schema for
<code>vitest/consistent-each-for</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23294">#23294</a>)
(Sysix)</li>
<li>7e74c98 linter: Add schema for
<code>vitest/consistent-test-filename</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23293">#23293</a>)
(Sysix)</li>
<li>ff94d4a linter: Add schema for
<code>vitest/consistent-vitest-vi</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23292">#23292</a>)
(Sysix)</li>
<li>2409a10 linter: Add schema for
<code>vitest/prefer-import-in-mock</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23291">#23291</a>)
(Sysix)</li>
<li>3d782b7 linter: Add schema for
<code>react/no-unstable-nested-components</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23287">#23287</a>)
(Mikhail Baev)</li>
<li>0a0bc2f linter/jsx-a11y: Add <code>allowedRedundantRoles</code>
option to <code>no-redundant-roles</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22820">#22820</a>)
(bab)</li>
<li>80758a5 linter/vue: Implement no-side-effects-in-computed-properties
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23282">#23282</a>)
(bab)</li>
<li>e3869ac linter: Add schema for
<code>react/no-object-type-as-default-prop</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23279">#23279</a>)
(Mikhail Baev)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/aa79b5be9915068f60bc361febf2e7496b92fc24"><code>aa79b5b</code></a>
release(apps): oxlint v1.70.0 &amp;&amp; oxfmt v0.55.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23442">#23442</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/5cb8d1bcf0c63b34ba91e9f9c36e7a84c76cb496"><code>5cb8d1b</code></a>
fix(linter/jsx-a11y/control-has-associated-label): reject excessive
label dep...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/f682e253892e8e77d7700d1053234e7a53c0dbca"><code>f682e25</code></a>
docs(linter): remove manually written options doc for
`eslint/prefer-arrow-ca...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/2e8bda49991cfef9cb9182d37e9f304372f53839"><code>2e8bda4</code></a>
feat(linter/vue): implement no-dupe-keys rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23350">#23350</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/64c942cffe0e8829293d1d9f2f046b496759609a"><code>64c942c</code></a>
docs(linter): remove manually written options doc for
<code>eslint/no-sequences</code> (...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/1490a0a0691908df0ff6659750ca2f3a29396c1a"><code>1490a0a</code></a>
feat(linter/react): implement react-compiler rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23202">#23202</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/965358e6132e84b1828b82e0e8b17f8ac2dec54b"><code>965358e</code></a>
refactor(linter): reuse <code>RuleNoConfig</code> reference for rule
schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23390">#23390</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/dd560ae213490fb208fdaa278562cf9169777f86"><code>dd560ae</code></a>
feat(linter/unicorn): implement
<code>no-array-fill-with-reference-type</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23">#23</a>...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/af36c2f9cd497c2f233de1902fc96b88804a2d3c"><code>af36c2f</code></a>
feat(linter): add schema for <code>react/jsx-curly-brace-presence</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23400">#23400</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/47d34a304c83f9a34d78d2895c3616206f5888a1"><code>47d34a3</code></a>
feat(linter): add schema for <code>react/jsx-handler-names</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23393">#23393</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.70.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `tailwindcss` from 4.3.0 to 4.3.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.1</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Generate <code>0</code> instead of <code>calc(var(--spacing) *
0)</code> for spacing utilities like <code>m-0</code> and
<code>left-0</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
<li>Generate <code>var(--spacing)</code> instead of
<code>calc(var(--spacing) * 1)</code> for spacing utilities like
<code>m-1</code> and <code>left-1</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">tailwindcss's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.1] - 2026-06-12</h2>
<h3>Added</h3>
<ul>
<li>Add <code>--silent</code> option to suppress output in
<code>@tailwindcss/cli</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20100">#20100</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Remove deprecation warnings by using
<code>Module#registerHooks</code> instead of
<code>Module#register</code> on Node 26+ (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20028">#20028</a>)</li>
<li>Canonicalization: don't crash when plugin utilities throw for
unsupported values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20052">#20052</a>)</li>
<li>Allow <code>@apply</code> to be used with CSS mixins (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19427">#19427</a>)</li>
<li>Ensure <code>not-*</code> correctly negates <code>@container</code>
queries, including <code>style(…)</code> queries (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20059">#20059</a>)</li>
<li>Ensure <code>drop-shadow-*</code> color utilities work with custom
shadow values containing <code>calc(…)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20080">#20080</a>)</li>
<li>Fix 'Sourcemap is likely to be incorrect' warnings when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20103">#20103</a>)</li>
<li>Ensure <code>@tailwindcss/webpack</code> can be installed in Rspack
projects without requiring <code>webpack</code> as a peer dependency (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20027">#20027</a>)</li>
<li>Canonicalization: don't suggest invalid <code>calc(…)</code>
expressions (e.g. <code>px-[calc(1rem+0px)]</code> →
<code>px-[calc(1rem+0)]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20127">#20127</a>)</li>
<li>Canonicalization: avoid suggesting large spacing-scale values for
arbitrary lengths (e.g. <code>left-[99999px]</code> →
<code>left-[99999px]</code>, not <code>left-24999.75</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20130">#20130</a>)</li>
<li>Ensure <code>@tailwindcss/cli</code> in <code>--watch</code> mode
recovers when a tracked dependency is deleted and restored (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20137">#20137</a>)</li>
<li>Ensure standalone <code>@tailwindcss/cli</code> binaries are ignored
when scanning for class candidates (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20139">#20139</a>)</li>
<li>Ensure class candidates are extracted from Twig
<code>addClass(…)</code> and <code>removeClass(…)</code> calls (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20198">#20198</a>)</li>
<li>Don't crash in the Ruby or Vue preprocessors when scanning files
containing invalid UTF-8 bytes (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19588">#19588</a>)</li>
<li>Allow <code>@variant</code> to be used inside <code>addBase</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19480">#19480</a>)</li>
<li>Ensure <code>@source</code> globs with symlinks are preserved (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Ensure later <code>@source</code> rules can re-include files
excluded by earlier <code>@source not</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20203">#20203</a>)</li>
<li>Upgrade: don't migrate empty class rules to invalid
<code>@utility</code> rules (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20205">#20205</a>)</li>
<li>Ensure transitions between <code>inset-shadow-none</code> and other
inset shadows work correctly (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20208">#20208</a>)</li>
<li>Ensure explicitly referenced <code>@source</code> directories are
scanned even when ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20214">#20214</a>)</li>
<li>Ensure <code>@source</code> globs ending in <code>**/*</code>
preserve dynamic path segments to avoid scanning too many files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20217">#20217</a>)</li>
<li>Canonicalization: don't fold <code>calc(…)</code> divisions when the
result would require high precision (e.g.
<code>w-[calc(100%/3.5)]</code> → <code>w-[calc(100%/3.5)]</code>, not
<code>w-[28.571428571428573%]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20221">#20221</a>)</li>
<li>Serve ESM type declarations to ESM importers of
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20228">#20228</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Generate <code>0</code> instead of <code>calc(var(--spacing) *
0)</code> for spacing utilities like <code>m-0</code> and
<code>left-0</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
<li>Generate <code>var(--spacing)</code> instead of
<code>calc(var(--spacing) * 1)</code> for spacing utilities like
<code>m-1</code> and <code>left-1</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20196">#20196</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/8a14a710102cae195f6811e8578bef9477bc6be9"><code>8a14a71</code></a>
4.3.1 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20226">#20226</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/12833aa4b3a8813fd32da74be7a2fd75aa706ab7"><code>12833aa</code></a>
Fix canonicalization bug where we end up with a high precision number
(<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20221">#20221</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/97a5b3abfb75ce9722266cd323a24eee057634fc"><code>97a5b3a</code></a>
docs: fix double word 'to to' in test comment (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20216">#20216</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/d01e103cc4741c29764afaa287d2fb21356f7eea"><code>d01e103</code></a>
Add missing <code>inset</code> keyword for
<code>inset-shadow-none</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20208">#20208</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/ad6693906a321912c90fd13c4a92e2cb26660985"><code>ad66939</code></a>
Allow <code>@variant</code> to be used inside <code>addBase</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19480">#19480</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/efae52c3af50300d5066596a6acbaf87e68ef9e4"><code>efae52c</code></a>
Simplify CSS when using utilities that use a <code>*-0</code> or
<code>*-1</code> value (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20196">#20196</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/6b43b6400a743a508afd712b50a73b2d3feb6444"><code>6b43b64</code></a>
Canonicalization: limit arbitrary to bare values conversion (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20130">#20130</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/d4f24c5f161b553dd99aef294ef6635093d1c440"><code>d4f24c5</code></a>
Fix invalid canonicalization where <code>0\&lt;unit&gt;</code> was
migrated to <code>0</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20127">#20127</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/749c45ef26735c59a446fc5e13e96359b68b9082"><code>749c45e</code></a>
Expose <code>index</code> and <code>siblings</code> on walk context (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20109">#20109</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/8dcdb66e8a58b9df621ed1a9cb59396e0ddb6dd7"><code>8dcdb66</code></a>
Bump dependencies (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/20095">#20095</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss">compare
view</a></li>
</ul>
</details>
<br />

Updates `vitest` from 4.1.8 to 4.1.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.9</h2>
<h3>🐞 Bug Fixes</h3>
<ul>
<li>Fix <code>importOriginal</code> with optimizer and query import
[backport to v4] - by <strong>Hiroshi Ogawa</strong>, <strong>David
Harris</strong>, <strong>Codex</strong>and <strong>Vladimir</strong> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10546">vitest-dev/vitest#10546</a>
<a href="https://github.com/vitest-dev/vitest/commit/a5180190c"><!-- raw
HTML omitted -->(a5180)<!-- raw HTML omitted --></a></li>
<li><strong>browser</strong>:
<ul>
<li>Wait for orchestrator readiness before resolving browser sessions
[backport to v4] - by <strong>Vladimir</strong> and <strong>Séamus
O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10555">vitest-dev/vitest#10555</a>
<a href="https://github.com/vitest-dev/vitest/commit/7fb29651a"><!-- raw
HTML omitted -->(7fb29)<!-- raw HTML omitted --></a></li>
<li>Wait for iframe tester readiness before preparing [backport to v4] -
by <strong>Vladimir</strong> and <strong>Séamus O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10497">vitest-dev/vitest#10497</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10556">vitest-dev/vitest#10556</a>
<a href="https://github.com/vitest-dev/vitest/commit/fbc626c40"><!-- raw
HTML omitted -->(fbc62)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>mocker</strong>:
<ul>
<li>Hoist vi.mock() for vite-plus/test imports [backport to v4] - by
<strong>Hiroshi Ogawa</strong>, <strong>LongYinan</strong>,
<strong>Claude Opus 4.8</strong> and <strong>Vladimir</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10548">vitest-dev/vitest#10548</a>
<a href="https://github.com/vitest-dev/vitest/commit/2c9559c02"><!-- raw
HTML omitted -->(2c955)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>pool</strong>:
<ul>
<li>Prevent test run hang on worker crash [backport to v4] - by
<strong>Ari Perkkiö</strong> and <strong>Jattioui Ismail</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10543">vitest-dev/vitest#10543</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10564">vitest-dev/vitest#10564</a>
<a href="https://github.com/vitest-dev/vitest/commit/934b0f587"><!-- raw
HTML omitted -->(934b0)<!-- raw HTML omitted --></a></li>
</ul>
</li>
</ul>
<h5><a
href="https://github.com/vitest-dev/vitest/compare/v4.1.8...v4.1.9">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitest-dev/vitest/commit/a7a61e78c7d0718f00173cff6800a91a344457d4"><code>a7a61e7</code></a>
chore: release v4.1.9 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10598">#10598</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/934b0f587cb61d8338d83f525295322692a2db40"><code>934b0f5</code></a>
fix(pool): prevent test run hang on worker crash (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10543">#10543</a>)
[backport to v4] (#...</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/7fb29651afbae2a9b0cefe6c031a9308f168ac60"><code>7fb2965</code></a>
fix(browser): wait for orchestrator readiness before resolving browser
sessio...</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/a5180190c1be7089e3705e3dd9e84fea118d09d3"><code>a518019</code></a>
fix: fix <code>importOriginal</code> with optimizer and query import
[backport to v4] (#...</li>
<li>See full diff in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-21 00:58:18 -04:00
CaliBrain 61b3eaf351 Fix internal bypasser using system DNS in subprocess, breaking downloads behind ISP DNS blocks (#1028) (#1080) 2026-06-21 00:42:03 -04:00
dependabot[bot] 7158b79146 Bump the python-deps group with 3 updates (#1074)
Bumps the python-deps group with 3 updates:
[python-socketio](https://github.com/miguelgrinberg/python-socketio),
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[prek](https://github.com/j178/prek).

Updates `python-socketio` from 5.16.2 to 5.16.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/releases">python-socketio's
releases</a>.</em></p>
<blockquote>
<h2>Release 5.16.3</h2>
<p>See <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">CHANGES.md</a>
for release notes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">python-socketio's
changelog</a>.</em></p>
<blockquote>
<h1>python-socketio change log</h1>
<p><strong>Release 5.16.3</strong> - 2026-06-15</p>
<ul>
<li>Catch all exceptions in redis and rabbitmq client managers <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1581">#1581</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/80bb5c9b07e6b53e45f610ec29a24124c539d41b">commit</a>)</li>
</ul>
<p><strong>Release 5.16.2</strong> - 2026-05-21</p>
<ul>
<li>Prevent unnecessary resource allocations <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1574">#1574</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ca140fe44d0ceb3004073645222abec182d8784b">commit</a>)</li>
<li>Add zizmor to CI builds <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1570">#1570</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/664dc27ec6f34179ed1724430eda3520627fc642">commit</a>)</li>
</ul>
<p><strong>Release 5.16.1</strong> - 2026-02-06</p>
<ul>
<li>Use configured JSON module in managers <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1549">#1549</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6229261ae6e8c01e675097242e333ee84587a544">commit</a>)</li>
<li>Admin UI fixes: remove duplicate tasks, report transport upgrades
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1c2eab13a92fac9e43663eb0b5f099eb1c40ea5b">commit</a>)</li>
<li>Switch to Furo documentation template (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/add47d8c7abca697a2804141bbf29bfb095f7d5e">commit</a>)</li>
<li>Add Python free-threading to CI <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1554">#1554</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ccdd2004a038ae4b8171a05120c5d0787332f7ee">commit</a>)</li>
</ul>
<p><strong>Release 5.16.0</strong> - 2025-12-24</p>
<ul>
<li>Address deprecation warnings (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b235699d9b06564753c570b76055997e9d62a938">commit</a>)</li>
<li>Drop Python 3.8 and 3.9 from CI builds (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/d0728d2f74538762dd551fa9cd0cd1fd5aedfa37">commit</a>)</li>
</ul>
<p><strong>Release 5.15.1</strong> - 2025-12-16</p>
<ul>
<li>Restore support multiple arguments via pubsub emits <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1540">#1540</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c279f26bb8c9887c4ca99d4d81ad331c4844438c">commit</a>)</li>
</ul>
<p><strong>Release 5.15.0</strong> - 2025-11-22</p>
<ul>
<li>Retry initial Redis connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1536">#1534</a>
([commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1">#1</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad">https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad</a>)
[commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/2">#2</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d">https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d</a>))</li>
<li>Correctly regenerate RabbitMQ binding after a connection failure <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1516">#1516</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c52e93b4a328d98a968bfbdec0cfd598b73ee913">commit</a>)
(thanks <strong>Gritty_dev</strong>!)</li>
<li>Support <code>ext_type</code> in the <code>MsgPackPacket</code>
class <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1521">#1521</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/208925344a48485d2cd56e40eb74266c3bcb5311">commit</a>)</li>
<li>Support sending <code>bytesarray</code>s when using pub/sub managers
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6c9b9974f72e2efdf62407ecab24ee6995448098">commit</a>)</li>
<li>Fix typos in documentation <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1520">#1520</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/db3f1c2a0105c30cb833ddfca8f05fe4320468fd">commit</a>)
(thanks <strong>Lê Nam Khánh</strong>!)</li>
<li>Improvements to the logging documentation (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b423d0e38eef559b7e81acb7e32059de305f982c">commit</a>)</li>
</ul>
<p><strong>Release 5.14.3</strong> - 2025-10-29</p>
<ul>
<li>Support Python's native <code>ConnectionRefusedError</code>
exception to reject a connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1515">#1515</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f3b18bde3f16437b223491d4c3e440ea37105fe3">commit</a>)</li>
<li>Push binary data to the aiopika client manager <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1514">#1514</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/194e1b7f277b5f72e1de78d3f614e7b8b6c788ac">commit</a>)</li>
</ul>
<p><strong>Release 5.14.2</strong> - 2025-10-15</p>
<ul>
<li>Restore binary message support in message queue setups <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1509">#1509</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/bab4a10f48aaae11d7f832ebe5c30ad3f85d31b3">commit</a>)</li>
<li>Fix formatting of client connection error <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1507">#1507</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f298c9b54d76ab09ff72935937e1b9575bc45ffd">commit</a>)</li>
<li>Add 3.14 and pypy-3.11 CI tasks (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1f4cd3b025c294f25208ec3c05b5f8df6209e403">commit</a>)</li>
<li>Improve documentation of the
<code>BaseManager.get_participants()</code> method (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/33722a0d96036f005188b07b8b46a5ef091fe65f">commit</a>)</li>
</ul>
<p><strong>Release 5.14.1</strong> - 2025-10-02</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/36c550f62415dc9c9c8dd39203b3c59ec7bdcdea"><code>36c550f</code></a>
Release 5.16.3</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/80bb5c9b07e6b53e45f610ec29a24124c539d41b"><code>80bb5c9</code></a>
Catch all exceptionsin redis and rabbitmq managers (Fixes <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1581">#1581</a>)</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/3f1d50903d1034fd9ffeb2110465ee0c1f90ea4c"><code>3f1d509</code></a>
Bump aiohttp from 3.13.4 to 3.14.0 in /examples/server/aiohttp (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1580">#1580</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/c2918c1b43489bde34d9198352bc1a4667021fc0"><code>c2918c1</code></a>
Bump qs and express in /examples/server/javascript (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1579">#1579</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/e19cb7df63e132da3a9b599e5bf948199c6a524f"><code>e19cb7d</code></a>
Bump qs and express in /examples/client/javascript (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1578">#1578</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/f616fb1cb4ba766bac99b05553672e8d3de90b48"><code>f616fb1</code></a>
Bump ws, engine.io, socket.io-adapter and socket.io-client (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1575">#1575</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/5f35b0bf5bb959b0a0b0d5006040a53112b50633"><code>5f35b0b</code></a>
Bump ws, engine.io, socket.io-adapter and socket.io-client (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1576">#1576</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/995f0807e78207ec88872764f7533a115fb9c6ba"><code>995f080</code></a>
Version 5.16.3.dev0</li>
<li>See full diff in <a
href="https://github.com/miguelgrinberg/python-socketio/compare/v5.16.2...v5.16.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.49.13 to 4.49.14
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.14 - Chromium overhaul with CDP Mode updates</h2>
<h2>Chromium overhaul with CDP Mode updates</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cb03afab9f8aeb67273348a8f5641faaf8ed90e7">Fix
issue that caused Chromium 151 to crash at startup</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4393">seleniumbase/SeleniumBase#4393</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/14d688b69f065f51d5b7b5d87059a591ad0a59d2">Add
option for setting the exact Chromium revision to download</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4394">seleniumbase/SeleniumBase#4394</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3c729af379fffaf2365782ea400d57d8f01e75a1">Update
Chromium options</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4395">seleniumbase/SeleniumBase#4395</a>
-- this resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4396">seleniumbase/SeleniumBase#4396</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f01f59153b338246ec6e78e589b00463107542ad">Update
CDP Mode</a></li>
</ul>
<h3>Here's an example of downloading a custom Chromium revision:</h3>
<pre lang="zsh"><code>sbase get chromium --revision=1639046
<p>*** Chromium revision to download = 1639046</p>
<p>Downloading chrome-mac.zip from:
<a
href="https://storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/1639046/chrome-mac.zip">https://storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/1639046/chrome-mac.zip</a>
...
Download Complete!</p>
<p>... [UNZIPPING] ...</p>
<p>Unzip Complete!</p>
<p>Chromium was saved inside:
..../seleniumbase/drivers/chromium_drivers/
chrome-mac
</code></pre></p>
<h2>What's Changed</h2>
<ul>
<li>Chromium overhaul with CDP Mode updates by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4397">seleniumbase/SeleniumBase#4397</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.13...v4.49.14">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.13...v4.49.14</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/dd5454faf2ba9950da5390d4dd121d17bb3b7f2c"><code>dd5454f</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4397">#4397</a>
from seleniumbase/chromium-overhaul-with-cdp-updates</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/520c0b406a784c48be94ed6dbdcc85dbd469c6dd"><code>520c0b4</code></a>
Version 4.49.14</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0e11a764a656f1bfc65998dafa3f7a4eed96104b"><code>0e11a76</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b1901439ba8eb54dadc1a87816216bddf24b9e0e"><code>b190143</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f01f59153b338246ec6e78e589b00463107542ad"><code>f01f591</code></a>
Update CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3c729af379fffaf2365782ea400d57d8f01e75a1"><code>3c729af</code></a>
Update Chromium options</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/14d688b69f065f51d5b7b5d87059a591ad0a59d2"><code>14d688b</code></a>
Add option for setting the exact Chromium revision to download</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cb03afab9f8aeb67273348a8f5641faaf8ed90e7"><code>cb03afa</code></a>
Fix issue that caused Chromium 151 to crash at startup</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d76b2fd98f4c71a930b8b0536235cd9e7118d9f4"><code>d76b2fd</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/09fd1f35d284965ddf8a4b245710d9acee6a6e3e"><code>09fd1f3</code></a>
Add/update examples of DataDome Slider CAPTCHA-bypass</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.13...v4.49.14">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.4.4 to 0.4.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.5</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-15.</p>
<h3>Highlights</h3>
<p>0.4.5 completes <code>prek</code>'s pre-commit language coverage.
With R, Conda, Perl,
and coursier now supported, <code>prek</code> supports every language
available in
pre-commit, plus <code>prek</code>-only modern languages such as Bun and
Deno.</p>
<p>This is full feature parity with pre-commit. The last major
compatibility gap
is closed, and <code>prek</code> is now on the path to 1.0.</p>
<h3>💚 Sponsorship</h3>
<p>If <code>prek</code> saves time for you or your team, please consider
sponsoring the
project on <a href="https://github.com/sponsors/j178">GitHub
Sponsors</a>. It helps keep
new features, performance work, and maintenance moving.</p>
<h3>Enhancements</h3>
<ul>
<li>Add <code>Perl</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2201">#2201</a>)</li>
<li>Add <code>R</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2206">#2206</a>)</li>
<li>Add <code>Conda</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2203">#2203</a>)</li>
<li>Add <code>coursier</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2194">#2194</a>)</li>
<li>Add group filters to list (<a
href="https://redirect.github.com/j178/prek/pull/2152">#2152</a>)</li>
<li>Remove legacy repo path support (<a
href="https://redirect.github.com/j178/prek/pull/2150">#2150</a>)</li>
<li>Skip cloning fully filtered remote repos (<a
href="https://redirect.github.com/j178/prek/pull/2151">#2151</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid building JSON trees in syntax hooks (<a
href="https://redirect.github.com/j178/prek/pull/2156">#2156</a>)</li>
<li>Scan mixed line endings without line vector (<a
href="https://redirect.github.com/j178/prek/pull/2160">#2160</a>)</li>
<li>Skip file scan for always-run no-filename hooks (<a
href="https://redirect.github.com/j178/prek/pull/2155">#2155</a>)</li>
<li>Use fixed buffer for EOF scan (<a
href="https://redirect.github.com/j178/prek/pull/2163">#2163</a>)</li>
<li>Use fixed buffer for private key scan (<a
href="https://redirect.github.com/j178/prek/pull/2164">#2164</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix pretty-format-json CRLF handling (<a
href="https://redirect.github.com/j178/prek/pull/2210">#2210</a>)</li>
<li>Handle missing blobs in diff snapshots (<a
href="https://redirect.github.com/j178/prek/pull/2211">#2211</a>)</li>
<li>Ignore coursier channel from working repo (<a
href="https://redirect.github.com/j178/prek/pull/2202">#2202</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.4.5</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.5</h2>
<p>Released on 2026-06-15.</p>
<h3>Highlights</h3>
<p>0.4.5 completes <code>prek</code>'s pre-commit language coverage.
With R, Conda, Perl,
and coursier now supported, <code>prek</code> supports every language
available in
pre-commit, plus <code>prek</code>-only modern languages such as Bun and
Deno.</p>
<p>This is full feature parity with pre-commit. The last major
compatibility gap
is closed, and <code>prek</code> is now on the path to 1.0.</p>
<h3>💚 Sponsorship</h3>
<p>If <code>prek</code> saves time for you or your team, please consider
sponsoring the
project on <a href="https://github.com/sponsors/j178">GitHub
Sponsors</a>. It helps keep
new features, performance work, and maintenance moving.</p>
<h3>Enhancements</h3>
<ul>
<li>Add <code>Perl</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2201">#2201</a>)</li>
<li>Add <code>R</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2206">#2206</a>)</li>
<li>Add <code>Conda</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2203">#2203</a>)</li>
<li>Add <code>coursier</code> language support (<a
href="https://redirect.github.com/j178/prek/pull/2194">#2194</a>)</li>
<li>Add group filters to list (<a
href="https://redirect.github.com/j178/prek/pull/2152">#2152</a>)</li>
<li>Remove legacy repo path support (<a
href="https://redirect.github.com/j178/prek/pull/2150">#2150</a>)</li>
<li>Skip cloning fully filtered remote repos (<a
href="https://redirect.github.com/j178/prek/pull/2151">#2151</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid building JSON trees in syntax hooks (<a
href="https://redirect.github.com/j178/prek/pull/2156">#2156</a>)</li>
<li>Scan mixed line endings without line vector (<a
href="https://redirect.github.com/j178/prek/pull/2160">#2160</a>)</li>
<li>Skip file scan for always-run no-filename hooks (<a
href="https://redirect.github.com/j178/prek/pull/2155">#2155</a>)</li>
<li>Use fixed buffer for EOF scan (<a
href="https://redirect.github.com/j178/prek/pull/2163">#2163</a>)</li>
<li>Use fixed buffer for private key scan (<a
href="https://redirect.github.com/j178/prek/pull/2164">#2164</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix pretty-format-json CRLF handling (<a
href="https://redirect.github.com/j178/prek/pull/2210">#2210</a>)</li>
<li>Handle missing blobs in diff snapshots (<a
href="https://redirect.github.com/j178/prek/pull/2211">#2211</a>)</li>
<li>Ignore coursier channel from working repo (<a
href="https://redirect.github.com/j178/prek/pull/2202">#2202</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/bb3108283fd4aab0d9eb59f23098e0c05a96cdbe"><code>bb31082</code></a>
Update README.md</li>
<li><a
href="https://github.com/j178/prek/commit/fa4e2dc060eccac3c2521ec7bf4af1272c5d6205"><code>fa4e2dc</code></a>
Bump version to 0.4.5 (<a
href="https://redirect.github.com/j178/prek/issues/2221">#2221</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/e9336fa724b8a99b3a21fd60eb0849cd731153ef"><code>e9336fa</code></a>
Add R language support (<a
href="https://redirect.github.com/j178/prek/issues/2206">#2206</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/97a5a15701d3691287e4f969a2a2f421d1501a46"><code>97a5a15</code></a>
Update Rust crate which to v8.0.3 (<a
href="https://redirect.github.com/j178/prek/issues/2219">#2219</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/20a519aa2aa4add7e70dfbb2ff743cd1f35e25f3"><code>20a519a</code></a>
Update Rust crate ignore to v0.4.26 (<a
href="https://redirect.github.com/j178/prek/issues/2218">#2218</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/88f0e2bd8a7d02be7fb19fcd17e1e8db79b8b0bc"><code>88f0e2b</code></a>
Update dependency uv to v0.11.19 (<a
href="https://redirect.github.com/j178/prek/issues/2214">#2214</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/7bd43000679b33e2b947f453436237dae062af70"><code>7bd4300</code></a>
Update GitHub Actions to v7 (<a
href="https://redirect.github.com/j178/prek/issues/2220">#2220</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/48ed5cc2838066d71278dd887dee595c32085be2"><code>48ed5cc</code></a>
Update Rust crate async_zip to 0.0.18 (<a
href="https://redirect.github.com/j178/prek/issues/2217">#2217</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/257e98a429e96f89a4d965ad28568cba77ca33c2"><code>257e98a</code></a>
Update pre-commit to v1.47.2 (<a
href="https://redirect.github.com/j178/prek/issues/2216">#2216</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/0c0460241a13b9ac519e1abd3a0a8a3ad60d4d2f"><code>0c04602</code></a>
Update GitHub Actions (<a
href="https://redirect.github.com/j178/prek/issues/2215">#2215</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.4...v0.4.5">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 00:00:30 -04:00
dependabot[bot] 3c1b79989a Bump node from fb71d01 to 156b55f in the docker-base-image-digests group (#1075)
Bumps the docker-base-image-digests group with 1 update: node.

Updates `node` from `fb71d01` to `156b55f`


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=node&package-manager=docker&previous-version=24-alpine&new-version=24-alpine)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 00:00:22 -04:00
dependabot[bot] e41c1d4e8e Bump python from 3.14.5-slim to 3.14.6-slim (#1076)
Bumps python from 3.14.5-slim to 3.14.6-slim.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=python&package-manager=docker&previous-version=3.14.5-slim&new-version=3.14.6-slim)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 00:00:13 -04:00
Hrachya ShaginyanandZo Bot ec7e3482bb use a stable hash for the Booklore options cache key (#1079)
`_get_booklore_cache_key` returned
`f"{base_url}|{username}|{hash(password)}"`. Python's built-in `hash()`
is randomized per process (`PYTHONHASHSEED`), so the cache key for the
same Booklore credentials changed between every worker process and every
restart. If the dashboard was opened by a worker that landed on a
different seed than the worker that warmed the cache, the
`_BOOKLORE_OPTIONS_CACHE.get("key") == cache_key` check would miss on
every lookup, forcing a fresh `booklore_login` API call each time.

Switch to `hashlib.sha256(password.encode()).hexdigest()` —
deterministic across processes and restarts. SHA-256 is overkill for a
cache key, but matching the existing convention (`hashlib.sha1` is used
elsewhere in the codebase) is what we want here.

The password is already in memory (it comes from the request body /
`config.get`), so this doesn't introduce a new secret-handling concern.

Co-authored-by: Zo Bot <github-automation@zo.computer>
2026-06-20 23:59:56 -04:00
dependabot[bot] 05cd384efc Bump the python-deps group with 3 updates (#1073)
Bumps the python-deps group with 3 updates:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase),
[basedpyright](https://github.com/detachhead/basedpyright) and
[pytest](https://github.com/pytest-dev/pytest).

Updates `seleniumbase` from 4.49.12 to 4.49.13
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.13 - Refresh Python dependencies</h2>
<h2>Refresh Python dependencies</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1cfc9c241fa4e8065a61ea1124f374257e464af4">Refresh
Python dependencies</a>
-- Refresh <code>filelock</code>, <code>pytest</code>, and
<code>pyotp</code>.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Refresh Python dependencies by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4390">seleniumbase/SeleniumBase#4390</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.12...v4.49.13">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.12...v4.49.13</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/daa6847905136b1e62a44837a1a03c7b3ca415d2"><code>daa6847</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4390">#4390</a>
from seleniumbase/refresh-python-dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/07722ce8bb401174ac1b7d3e0bfc3a476ea2d4d8"><code>07722ce</code></a>
Version 4.39.13</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1cfc9c241fa4e8065a61ea1124f374257e464af4"><code>1cfc9c2</code></a>
Refresh Python dependencies</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.12...v4.49.13">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.7 to 1.39.8
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/fab7323c03bfa17db61cf63457beee9e484fde80"><code>fab7323</code></a>
1.39.8</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/c685372fd5da030a7c922b65ef8ecfd1e1cf7265"><code>c685372</code></a>
Avoid auto f-string conversion for raw strings</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/a55c2a4ddc65230bde700c32677d62e4e7c6586b"><code>a55c2a4</code></a>
docs: document typeCheckingMode off behavior</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/61b9817de80a927395ce2315a2e34c663ac43664"><code>61b9817</code></a>
fix: clarify implicit abstract class diagnostic</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/7dd1aafafd74d3c9c07a2a287295c5dafa073f38"><code>7dd1aaf</code></a>
fix default value in <code>pythonPlatform</code> documentation, which
differs from upstream</li>
<li>See full diff in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.7...v1.39.8">compare
view</a></li>
</ul>
</details>
<br />

Updates `pytest` from 9.0.3 to 9.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.1.0</h2>
<h1>pytest 9.1.0 (2026-06-13)</h1>
<h2>Removals and backward incompatible breaking changes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14533">#14533</a>:
When using <code>--doctest-modules</code>, autouse fixtures with
<code>module</code>, <code>package</code> or <code>session</code> scope
that are defined inline in Python test modules (not plugins or
conftests) will now possibly execute twice.</p>
<p>If this is undesirable, move the fixture definition to a
<code>conftest.py</code> file if possible.</p>
<p>Technical explanation for those interested:
When using <!-- raw HTML omitted -->--doctest-modules<!-- raw HTML
omitted -->, pytest possibly collects Python modules twice, once as
<code>pytest.Module</code> and once as a <code>DoctestModule</code>
(depending on the configuration).
Due to improvements in pytest's fixture implementation, if e.g. the
<code>DoctestModule</code> collects a fixture, it is now visible to it
only, and not to the <code>Module</code>.
This means that both need to register the fixtures independently.</p>
</li>
</ul>
<h2>Deprecations (removal in next major release)</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/10819">#10819</a>:
Added a deprecation warning for class-scoped fixtures defined as
instance methods (without <code>@classmethod</code>). Such fixtures set
attributes on a different instance than the test methods use, leading to
unexpected behavior. Use <code>@classmethod</code> decorator instead --
by <code>yastcher</code>.</p>
<p>See <code>10819</code> and <code>14011</code>.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/12882">#12882</a>:
Calling <code>request.getfixturevalue()
&lt;pytest.FixtureRequest.getfixturevalue&gt;</code> during teardown to
request a fixture that was not already requested is now deprecated and
will become an error in pytest 10.</p>
<p>See <code>dynamic-fixture-request-during-teardown</code> for
details.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13409">#13409</a>:
Using non-<code>~collections.abc.Collection</code> iterables (such as
generators, iterators, or custom iterable objects) for the
<code>argvalues</code> parameter in <code>@pytest.mark.parametrize
&lt;pytest.mark.parametrize ref&gt;</code> and
<code>metafunc.parametrize &lt;pytest.Metafunc.parametrize&gt;</code> is
now deprecated.</p>
<p>These iterables get exhausted after the first iteration,
leading to tests getting unexpectedly skipped in cases such as running
<code>pytest.main()</code> multiple times,
using class-level parametrize decorators,
or collecting tests multiple times.</p>
<p>See <code>parametrize-iterators</code> for details and
suggestions.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13946">#13946</a>:
The private <code>config.inicfg</code> attribute is now deprecated.
Use <code>config.getini() &lt;pytest.Config.getini&gt;</code> to access
configuration values instead.</p>
<p>See <code>config-inicfg</code> for more details.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14004">#14004</a>:
Passing <code>baseid</code> to <code>~pytest.FixtureDef</code> or
<code>nodeid</code> strings to fixture registration APIs is now
deprecated. These are internal pytest APIs that are used by some
plugins.</p>
<p>Use the <code>node</code> parameter instead for fixture scoping. This
enables more robust node-based
matching instead of string prefix matching.
If you've used <code>nodeid=None</code>, pass <code>node=session</code>
instead.</p>
<p>This will be removed in pytest 10.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14335">#14335</a>:
The method of configuring hooks using markers, deprecated since pytest
7.2, is now scheduled to be removed in pytest 10.
See <code>hook-markers</code> for more details.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14434">#14434</a>:
The <code>--pastebin</code> option is now deprecated.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pytest-dev/pytest/commit/b2522cf0b11fb33ecc1f4895fa1dffbb9252a63d"><code>b2522cf</code></a>
Prepare release version 9.1.0</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/368d2fca78e86ac79ec269bb078fcb1259a94fed"><code>368d2fc</code></a>
[refactor] Tighten <code>SetComparisonFunction</code> to
<code>Iterator[str]</code> (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14587">#14587</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/ff77cd8b66b43a88c26ca54384bbcab72d079497"><code>ff77cd8</code></a>
[refactor] Make base assertion comparisons return an iterator instead of
a li...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/0d8491a4ecf971800de0479ef55c7f5292c54937"><code>0d8491a</code></a>
build(deps): Bump actions/stale from 10.2.0 to 10.3.0</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/4a809d9c892f6abb5ba92b77b06f1dd878f4660a"><code>4a809d9</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14568">#14568</a>
from pytest-dev/register-fixture</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/5dfa38541becfb77d0f52cac4cc8cce71849ab61"><code>5dfa385</code></a>
Fix recursion traceback test to cover all styles (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14582">#14582</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/f52ff0c1778c15038cf2bbb00b7668dac674cc26"><code>f52ff0c</code></a>
Add <code>pytest.register_fixture</code></li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/a8ac094e80df788aec844794170b126eab0be7a4"><code>a8ac094</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14567">#14567</a>
from pytest-dev/more-visibility-deprecate</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/e5620cd21ec62f5a5f9a5141a3c76fb3953729b6"><code>e5620cd</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14577">#14577</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/2ce9c6d94eb691ea4da7f91f330602cbb67a6daf"><code>2ce9c6d</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14540">#14540</a>
from minbang930/fix-14533-doctest-module-fixtures</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/9.0.3...9.1.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 00:29:33 -04:00
dependabot[bot] 880cc4a299 Bump seleniumbase from 4.49.10 to 4.49.12 in the python-deps group (#1070)
Bumps the python-deps group with 1 update:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `seleniumbase` from 4.49.10 to 4.49.12
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.12 - CDP Mode: Patch 116</h2>
<h2>CDP Mode: Patch 116</h2>
<ul>
<li><a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4389/commits/f87cf4f13a0e19fc360d7e8b98037dc79ec64da1">Add
missing await for async method call in CDP Mode</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4388">seleniumbase/SeleniumBase#4388</a>
-- (Applies to setting <code>ad_block=True</code> in CDP Mode)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 116 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4389">seleniumbase/SeleniumBase#4389</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.11...v4.49.12">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.11...v4.49.12</a></p>
<h2>4.49.11 - CDP Mode: Patch 115</h2>
<h2>CDP Mode: Patch 115</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4207eebedeb32eb2d7c13145c70d50680b6f5fbb">Update
MyCDP</a>
-- (Note that all CDP calls go through <code>MyCDP</code>)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d2a57ef2c4a2a8b706093c588c7e9da78782611f">Update
CDP Mode</a>
-- Added a custom message option for all assertions
-- Added more time for the ad-blocker to take effect</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 115 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4385">seleniumbase/SeleniumBase#4385</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.10...v4.49.11">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.10...v4.49.11</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/18b058837f4645588ec76eb859f57104aca78b95"><code>18b0588</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4389">#4389</a>
from seleniumbase/cdp-mode-patch-116</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7a71fea3f9d3419cfbe7dff7d630b59d53851ac2"><code>7a71fea</code></a>
Version 4.49.12</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f87cf4f13a0e19fc360d7e8b98037dc79ec64da1"><code>f87cf4f</code></a>
Add missing <code>await</code> for async method call</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c9b450433a5750426a1143250ad7e0c24ed3ffa4"><code>c9b4504</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4385">#4385</a>
from seleniumbase/cdp-mode-patch-115</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/daefe6f4ff1bf20408ba666a1f07347a81a9f6b8"><code>daefe6f</code></a>
Version 4.49.11</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/fc721de65c74b42bca13b89bec411aa90ffe55bb"><code>fc721de</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/eb063047cc6e8ffd4a7fca8ff3b07701d8b16037"><code>eb06304</code></a>
Update an optional Python dependency</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4207eebedeb32eb2d7c13145c70d50680b6f5fbb"><code>4207eeb</code></a>
Update MyCDP</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/d2a57ef2c4a2a8b706093c588c7e9da78782611f"><code>d2a57ef</code></a>
Update CDP Mode</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.10...v4.49.12">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=seleniumbase&package-manager=uv&previous-version=4.49.10&new-version=4.49.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-17 14:26:40 -04:00
CaliBrain e9668371f7 Fix IRC caching (#1072) 2026-06-17 14:25:31 -04:00
CaliBrain d55e42fbc6 Add torrent fix for untrusted URL (#1071) 2026-06-17 13:46:51 -04:00
dependabot[bot] ade4878cfd Bump the python-deps group with 2 updates (#1068)
Bumps the python-deps group with 2 updates:
[seleniumbase](https://github.com/seleniumbase/SeleniumBase) and
[ruff](https://github.com/astral-sh/ruff).

Updates `seleniumbase` from 4.49.9 to 4.49.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.10 - CDP Mode: Patch 114</h2>
<h2>CDP Mode: Patch 114</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/86f67c312b02c308c90e823080f2c6a98cb0986a">Update
CDP Mode</a>
-- Improve error-handling for various edge-cases
-- Make sure all CDP Mode methods can be called via
<code>sb.METHOD</code> (rather than <code>sb.cdp.METHOD</code>)</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0588e9b5470deb0406b7f9584be93dfb00453979">Optimize
imports in browser_launcher.py</a>
-- A few of the big imports are not always needed</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/205bf88f0c58c400ed900fd0f9cdf91ba1200e5c">Update
examples</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/07ce62e9516138ec1a7c3e41529efc0690ff7bf3">Update
the docs</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 114 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4381">seleniumbase/SeleniumBase#4381</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.9...v4.49.10">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.9...v4.49.10</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8204d89e43855801be6ab0bfbb572e015ce3502d"><code>8204d89</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4381">#4381</a>
from seleniumbase/cdp-mode-patch-114</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/598917507da14acfaf2339acd377fe6b8f643a53"><code>5989175</code></a>
Version 4.49.10</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/07ce62e9516138ec1a7c3e41529efc0690ff7bf3"><code>07ce62e</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/205bf88f0c58c400ed900fd0f9cdf91ba1200e5c"><code>205bf88</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0588e9b5470deb0406b7f9584be93dfb00453979"><code>0588e9b</code></a>
Optimize imports in browser_launcher.py</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/86f67c312b02c308c90e823080f2c6a98cb0986a"><code>86f67c3</code></a>
Update CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c7d6a6d192f6782cb7388e84290a0c96106d15c2"><code>c7d6a6d</code></a>
Update the ReadMe</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1f22eb4bcc3478ca791ba06bfde1ff8a097d1f6d"><code>1f22eb4</code></a>
Update a presentation</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3ef7b314900560624f8be90bd4db232688fcb267"><code>3ef7b31</code></a>
Update Google examples</li>
<li>See full diff in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.9...v4.49.10">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.16 to 0.15.17
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.17</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-11.</p>
<h3>Preview features</h3>
<ul>
<li>Allow human-readable names in suppression comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25614">#25614</a>)</li>
<li>Fix handling of <code>ignore</code> comments within a
<code>disable</code>/<code>enable</code> pair (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25845">#25845</a>)</li>
<li>Prioritize human-readable names in CLI output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25869">#25869</a>)</li>
<li>Respect diagnostic start and parent ranges and trailing comments in
<code>ruff:ignore</code> suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25673">#25673</a>)</li>
<li>[<code>flake8-async</code>] Add <code>trio.as_safe_channel</code> to
safe decorators (<code>ASYNC119</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25775">#25775</a>)</li>
<li>[<code>flake8-pytest-style</code>] Also check
<code>pytest_asyncio</code> fixtures (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25375">#25375</a>)</li>
<li>[<code>ruff</code>] Ban <code>pytest</code> autouse fixtures
(<code>RUF076</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25477">#25477</a>)</li>
<li>[<code>pyupgrade</code>] Add <code>from __future__ import
annotations</code> automatically (<code>UP007</code>,
<code>UP045</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23259">#23259</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix diagnostic when <code>ruff:enable</code> or
<code>ruff:disable</code> appears where <code>ruff:ignore</code> is
expected (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25700">#25700</a>)</li>
<li>[<code>pyupgrade</code>] Preserve leading empty literals to avoid
syntax errors (<code>UP032</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25491">#25491</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Clarify diagnostic message for
single parameters (<code>PT007</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25592">#25592</a>)</li>
<li>[<code>numpy</code>] Drop autofix for <code>np.in1d</code>
(<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25612">#25612</a>)</li>
<li>[<code>pylint</code>] Exempt Python version comparisons
(<code>PLR2004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25743">#25743</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reserve AST <code>Vec</code>s with correct capacity for common cases
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/25451">#25451</a>)</li>
</ul>
<h3>Formatter</h3>
<ul>
<li>Preserve whitespace for Quarto cell option comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25641">#25641</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Allow rule names in <code>ruff rule</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25640">#25640</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Fix playground diagnostics scrollbars (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25642">#25642</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/SuryanshSS1011"><code>@​SuryanshSS1011</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a
href="https://github.com/karlhillx"><code>@​karlhillx</code></a></li>
<li><a href="https://github.com/carljm"><code>@​carljm</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.17</h2>
<p>Released on 2026-06-11.</p>
<h3>Preview features</h3>
<ul>
<li>Allow human-readable names in suppression comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25614">#25614</a>)</li>
<li>Fix handling of <code>ignore</code> comments within a
<code>disable</code>/<code>enable</code> pair (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25845">#25845</a>)</li>
<li>Prioritize human-readable names in CLI output (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25869">#25869</a>)</li>
<li>Respect diagnostic start and parent ranges and trailing comments in
<code>ruff:ignore</code> suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25673">#25673</a>)</li>
<li>[<code>flake8-async</code>] Add <code>trio.as_safe_channel</code> to
safe decorators (<code>ASYNC119</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25775">#25775</a>)</li>
<li>[<code>flake8-pytest-style</code>] Also check
<code>pytest_asyncio</code> fixtures (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25375">#25375</a>)</li>
<li>[<code>ruff</code>] Ban <code>pytest</code> autouse fixtures
(<code>RUF076</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25477">#25477</a>)</li>
<li>[<code>pyupgrade</code>] Add <code>from __future__ import
annotations</code> automatically (<code>UP007</code>,
<code>UP045</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23259">#23259</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix diagnostic when <code>ruff:enable</code> or
<code>ruff:disable</code> appears where <code>ruff:ignore</code> is
expected (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25700">#25700</a>)</li>
<li>[<code>pyupgrade</code>] Preserve leading empty literals to avoid
syntax errors (<code>UP032</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25491">#25491</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Clarify diagnostic message for
single parameters (<code>PT007</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25592">#25592</a>)</li>
<li>[<code>numpy</code>] Drop autofix for <code>np.in1d</code>
(<code>NPY201</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25612">#25612</a>)</li>
<li>[<code>pylint</code>] Exempt Python version comparisons
(<code>PLR2004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25743">#25743</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reserve AST <code>Vec</code>s with correct capacity for common cases
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/25451">#25451</a>)</li>
</ul>
<h3>Formatter</h3>
<ul>
<li>Preserve whitespace for Quarto cell option comments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25641">#25641</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Allow rule names in <code>ruff rule</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25640">#25640</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Fix playground diagnostics scrollbars (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25642">#25642</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/SuryanshSS1011"><code>@​SuryanshSS1011</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/romero-deshaw"><code>@​romero-deshaw</code></a></li>
<li><a
href="https://github.com/karlhillx"><code>@​karlhillx</code></a></li>
<li><a href="https://github.com/carljm"><code>@​carljm</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/7c645a9a1be8258b9f9e005208a55a0b7e8e18f0"><code>7c645a9</code></a>
Bump 0.15.17 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25872">#25872</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f381eb1d54997cfbfa6f63c15dd2d760f70e85e1"><code>f381eb1</code></a>
Prioritize human-readable names in CLI output (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25869">#25869</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b9b4546ad27d8fd12acc979e312a3ee25ef8ac4f"><code>b9b4546</code></a>
Minor workflow simplification (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25870">#25870</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/1e77ba02570bbe4952f7cf0e4ebb97b8b4e6e58d"><code>1e77ba0</code></a>
[ty] Move <code>PreformattedBlockScanner</code> to format-agnostic
location. (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25856">#25856</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/6f2b772285aa478e8aee3f4b54dfa9ce903a0ce1"><code>6f2b772</code></a>
[ty] Preserve nominal type of enum.property instances (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25849">#25849</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/be4777c8766a38d405a69948989cdfa2674adaae"><code>be4777c</code></a>
[ty] Fix site-package error when multiple versions of pythons are
installed i...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/53f6ff7200983a67778fcba7106019d2615846f0"><code>53f6ff7</code></a>
Allow human-readable names in suppression comments (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25614">#25614</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/67403254192f3541bd7e1027c8f1805cf7a9c2be"><code>6740325</code></a>
[ty] Restrict uncached raw signature access (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25866">#25866</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/970b1bf4a4d83359c9e28cad5f127ebbd6769682"><code>970b1bf</code></a>
Auto-update snapshots when syncing typeshed (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25841">#25841</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/0785793750fd6c74124a189259822f1a28eb5c13"><code>0785793</code></a>
Fix handling of <code>ignore</code> comments within a
<code>disable</code>/<code>enable</code> pair (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25845">#25845</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.16...0.15.17">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-15 00:30:58 -04:00
aba1a68dda Backport bug fixes from NemesisHubris/litfinder (addresses #999, #956, #1010, #1021, #1025, #1040) (#1066)
## Backport bug fixes from `NemesisHubris/litfinder`

Forwards a curated set of bug fixes from
[NemesisHubris/litfinder](https://github.com/NemesisHubris/litfinder) —
a community fork of this project — that address open issues here. All
commits preserve original authorship via `git cherry-pick`; this PR is a
backport rather than original work. Each fix has been reviewed locally,
lint/format-cleaned to match this repo's existing ruff config, and
verified with the test suite. Rebrand strings, license switches, and
features have been deliberately excluded.

### Upstream issues addressed

- **#999** — Mirror URLs with query params no longer break search
requests (strip query string/fragment in `normalize_http_url`)
- **#956** — Apprise notifications now respect the configured proxy
(proxy env vars injected before dispatch)
- **#1025** — rTorrent: separate `RTORRENT_AUDIOBOOK_LABEL` setting,
falls back to book label if unset
- **#1010** — Stop button in Activity no longer makes the panel
disappear (snapshot refresh on cancel)
- **#1021** — Anna's Archive slow-download countdown now caps retries
instead of looping forever
- **#1040** — Empty destination directory cleaned up when write probe
fails
- **PR #1031** — Language detection from Anna's Archive distant path
when listing metadata is missing

### Additional fixes (no open issue but clear bugs)

- **fix: Python 2 `except` syntax across 27 files** — `except X, Y:` is
a SyntaxError in Python 3 and prevents affected modules from importing
at runtime. Mechanical sweep to `except (X, Y):`.
- **fix(abb): info hash validation with magnet fallback** — adds
SHA-1/SHA-256 hex validation on extracted info hashes; falls back to
scanning the full page for a magnet link (e.g. posted in comments) when
the table value is malformed. Also extends the exact-phrase fallback to
manual queries and defaults the ABB listing language to `en` when
missing, preventing valid results from being hidden by the language
filter. Includes a small test-fixture fix (`test(abb): use valid hex
info hashes in scraper test fixtures`) since the existing fixtures used
non-hex placeholders that the new validation correctly rejects.
- **fix: Anna's Archive title parser** — handles nested edition spans
and filters `lgli` catalog descriptor entries (e.g. "Book/Online Audio")
that were polluting search results.

### Deliberately not included

- LitFinder rebranding (UI strings, Apprise app ID, logo). The `fix:
three upstream bugs` commit (#999/#956/#1025) was cherry-picked with
Apprise app-id, description, and logo-URL strings reverted from
"LitFinder" back to "Shelfmark"; noted in the commit body.
- Features from the LitFinder fork (multi-variant title search,
multi-book flat-folder grouping, fuzzy text matching, "Leave in Place"
output handler, admin display name, custom-source plugin system). These
are larger behavior changes that each warrant their own focused review —
happy to send any of them separately if of interest.
- LitFinder-specific test environment and CI infrastructure.

### Verification

- Backend: **1879 passed**, 96 skipped (1 preexisting failure on
`seleniumbase`-dependent test in local venv; runs fine in the standard
Docker image with the `browser` extra)
- Lint, format, dead-code: all clean against this repo's existing
ruff/vulture config
- One follow-up cleanup commit (`style: ruff lint and format fixes for
ported commits`) brings the cherry-picked code into compliance with this
repo's ruff settings — no behavior changes there

### Etiquette / credit

Per-commit authorship preserved by cherry-pick. The only edits to the
original commits are:
- `fix: three upstream bugs` — Apprise rebrand strings reverted to
"Shelfmark" (noted in commit body, original author retained as
`Co-Authored-By` via cherry-pick)
- One follow-up `style:` commit for ruff config alignment

Big thanks to [@NemesisHubris](https://github.com/NemesisHubris) for the
original work in LitFinder; this PR exists to make sure these fixes
reach Shelfmark's wider user base. Happy to revise scope, split into
smaller PRs, or split off the Py2 cleanup separately if that's
preferable.

---------

Co-authored-by: NemesisHubris <155838970+NemesisHubris@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-15 00:28:43 -04:00
bullitt168 6231678c28 fix: "No files found." check produces false positives when AA returns results alongside that string (#1067)
## Problem

Searching Anna's Archive with multiple format filters (e.g. `epub`,
`mobi`, `pdf`, …) combined with a language filter (`lang=de`) and a
specific title produces a response that **contains both a full results
table and a `\"No files found.\"` span** in a separate section of the
page.

The previous code performed a naïve substring check on the raw HTML
before parsing:

```python
if "No files found." in html:
    logger.info("No books found for query: %s", query)
    return []
```

When Anna's Archive renders a page that has, e.g., results for one
content type but no results for another sub-filter, it emits a `<span
class="font-bold">No files found.</span>` in the empty sub-section while
the main results table is fully populated (650+ entries in the tested
case). The early return discards all those results, making Shelfmark
appear unable to find anything on Anna's Archive.

Reported upstream as: https://github.com/calibrain/shelfmark/issues/1042

## Root cause

The string `"No files found."` appears in multiple places on an AA
search results page. It is not a reliable signal that the entire query
returned zero results — only that *some* filtered sub-section is empty.

## Fix

Parse the HTML into BeautifulSoup first and look for the results
`<table>`. Only if no table is present does it make sense to fall back
to the string check:

```python
soup = BeautifulSoup(_html_response_text(html), "html.parser")
tbody = soup.find("table")

if tbody is None:
    if "No files found." in html:
        logger.info("No books found for query: %s", query)
        return []
    logger.warning("No results table found for query: %s", query)
    msg = "No books found. Please try another query."
    raise RuntimeError(msg)
```

This preserves both existing behaviours:
- Genuine empty results (no table + "No files found." present) → return
`[]`
- Unexpected response structure (no table, no "No files found." either)
→ raise `RuntimeError`

And fixes the false-positive case (table present + "No files found." in
another section) → proceed normally and parse the table.

## Testing

Verified on a self-hosted Shelfmark v1.3.0 instance against
`annas-archive.gl`:

- Query: `"Reise zum Mittelpunkt der Erde"` + `lang=de` + all supported
ebook formats
- Before fix: `search_books()` returned `[]` immediately
- After fix: `search_books()` returned 6 matching German epub/mobi
results

The fix is a pure restructuring — no logic is added or removed, only the
order of operations changes.
2026-06-14 22:45:36 -04:00
dependabot[bot] b5acbc1209 Bump node from 2bdb65e to fb71d01 in the docker-base-image-digests group (#1061)
Bumps the docker-base-image-digests group with 1 update: node.

Updates `node` from `2bdb65e` to `fb71d01`


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=node&package-manager=docker&previous-version=24-alpine&new-version=24-alpine)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 01:41:02 -04:00
dependabot[bot] b0df608a53 Bump the python-deps group with 2 updates (#1064)
Bumps the python-deps group with 2 updates:
[tqdm](https://github.com/tqdm/tqdm) and
[seleniumbase](https://github.com/seleniumbase/SeleniumBase).

Updates `tqdm` from 4.68.1 to 4.68.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.68.2 stable</h2>
<ul>
<li>revert accidental change to <code>ascii</code> default (fixes <a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a>)
<ul>
<li><code>UnicodeEncodeError: 'charmap' codec can't encode characters in
position 6-7: character maps to &lt;undefined&gt;</code> can be fixed by
installing <code>tqdm!=4.68.0,!=4.68.1</code></li>
</ul>
</li>
<li>misc docs updates
<ul>
<li>fix links</li>
<li>replace stray <code>rst</code> -&gt; <code>md</code> syntax</li>
<li>consistent &quot;progress bar&quot; terminology (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1737">#1737</a>)</li>
</ul>
</li>
<li>tests: fix coverage (fixes <a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/4b3395272d66a00d7d4eebec5a4e19ae679aa95d"><code>4b33952</code></a>
revert accidental change to <code>tqdm(ascii)</code> default</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/b10848f8aaece089c70590425fd4262a68beb57f"><code>b10848f</code></a>
docs: fix links</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/85b62dd5fc5f1cc83f37802312d5d71a1a970e86"><code>85b62dd</code></a>
docs: replace stray rst -&gt; md</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/d2fb04af6fbf49501dce9cc82f0ea8971924dee7"><code>d2fb04a</code></a>
docs: mention OpenAI sponsorship</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/85940f9d17a679f9189a8346b05c0580f313f69f"><code>85940f9</code></a>
docs: consistent progress bar terminology</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/9dbb36be49a91bb86b15883e0d8c6ad1d3fb4aa2"><code>9dbb36b</code></a>
tests: fix coverage</li>
<li>See full diff in <a
href="https://github.com/tqdm/tqdm/compare/v4.68.1...v4.68.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.49.7 to 4.49.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.9 - CDP Mode: Patch 113</h2>
<h2>CDP Mode: Patch 113</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b519bf97b34f4d84a7492cf89ce6b441f7ac0516">Add
functionality for handling downloads in CDP Mode</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4376">seleniumbase/SeleniumBase#4376</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/351c3c94964661e203292bab08e815c5f3cbbb05">Add
method for extracting all links in CDP Mode</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4377">seleniumbase/SeleniumBase#4377</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/08a439413d62c3033a007ae52f332fd9382eaea5">Allow
custom messages with failed assertions in CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3452e83fdb7593cf98c2f190d1658377e279394d">Update
the docs</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1dda14cd8f68aa8e88e6a6430980a014924e9715">Update
examples</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/81321f8d21095787d71ce9c5aa0096ea90d1b060">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 113 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4378">seleniumbase/SeleniumBase#4378</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.8...v4.49.9">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.8...v4.49.9</a></p>
<h2>4.49.8 - The Great Refactor</h2>
<h2>The Great Refactor</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7f937365d93263cc2b19f8501e76bb27597b20df">Update
the self-hosted dashboard</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4372">seleniumbase/SeleniumBase#4372</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/532cc63228ed520d1df714d072fd2f01ac4fc9bf">Refactor
code, examples, and docs</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4370">seleniumbase/SeleniumBase#4370</a>
-- This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4371">seleniumbase/SeleniumBase#4371</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/61bfb23b2dddafc9f5725a7c2168d41b30b05cc6">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>The Great Refactor by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4373">seleniumbase/SeleniumBase#4373</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.7...v4.49.8">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.7...v4.49.8</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e12db778079b4e7d0e871d8a6e1184d8ffa78d50"><code>e12db77</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4378">#4378</a>
from seleniumbase/cdp-mode-patch-113</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/838147d8e3a91f2dbdae7c2714e5f46b3b6ecd3c"><code>838147d</code></a>
Version 4.49.9</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/81321f8d21095787d71ce9c5aa0096ea90d1b060"><code>81321f8</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3452e83fdb7593cf98c2f190d1658377e279394d"><code>3452e83</code></a>
Update the docs</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1dda14cd8f68aa8e88e6a6430980a014924e9715"><code>1dda14c</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/08a439413d62c3033a007ae52f332fd9382eaea5"><code>08a4394</code></a>
Allow custom messages with failed assertions in CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/351c3c94964661e203292bab08e815c5f3cbbb05"><code>351c3c9</code></a>
Add method for extracting all links in CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b519bf97b34f4d84a7492cf89ce6b441f7ac0516"><code>b519bf9</code></a>
Add functionality for handling downloads in CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cb1ad4f6469e6774c6057c382b9e35ce2aefdab1"><code>cb1ad4f</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4373">#4373</a>
from seleniumbase/the-great-refactor</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/6d789dd65f3f3f0334c44df0ad7d429943e53301"><code>6d789dd</code></a>
Version 4.49.8</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.7...v4.49.9">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 01:40:40 -04:00
dependabot[bot] 68e4e6120e Bump @types/node from 25.9.2 to 25.9.3 in /src/frontend in the npm-deps group (#1063)
Bumps the npm-deps group in /src/frontend with 1 update:
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).

Updates `@types/node` from 25.9.2 to 25.9.3
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=25.9.2&new-version=25.9.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 01:40:31 -04:00
CaliBrain c64c2d374a Make IRC less spammy and require a bot name for conversatons (#1065)
First step towards fixing the friction created by shelfmark in #997
2026-06-14 01:40:09 -04:00
CaliBrain 75c0b0c33a Update dependabot.yml (#1060) 2026-06-14 01:19:08 -04:00
dependabot[bot] d695b636f0 Bump the npm-deps group in /src/frontend with 6 updates (#1056)
Bumps the npm-deps group in /src/frontend with 6 updates:

| Package | From | To |
| --- | --- | --- |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.16.0` | `7.17.0` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `25.9.1` | `25.9.2` |
|
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)
| `19.2.16` | `19.2.17` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.15.0` | `6.16.1` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.53.0` | `0.54.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.68.0` | `1.69.0` |

Updates `react-router-dom` from 7.16.0 to 7.17.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.17.0</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.17.0"><code>react-router@7.17.0</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/195a0d03c1417127ccee73853058c8521beb4fce"><code>195a0d0</code></a>
Release v7.17.0 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15145">#15145</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.17.0/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 25.9.1 to 25.9.2
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react` from 19.2.16 to 19.2.17
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.15.0 to 6.16.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.16.1</h2>
<ul>
<li>Resolve SvelteKit ./$types in monorepos (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1778">#1778</a>)
(370ef4cefec6540ee7d58249cc402f479ec76405)</li>
</ul>
<h2>Release 6.16.0</h2>
<ul>
<li>Update sponsors data + fix sponsors layout on narrow screen
(fadf13aad5ebc36f7bc2fbc7615bfa77681d3660)</li>
<li>Detect binaries and entry files in node:child_process calls
(fc3598cfac640a2ae53b0113883574bf15bc5d47)</li>
<li>It works™ (2d9ce845121484ef3ff84e4a761cfd98891d6c09)</li>
<li>Extend known issues doc w/ workaround (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1763">#1763</a>)
(fcd444bf4c6b2ddc5d7bb0ebfd6f3991cf5d0be2)</li>
<li>Support ignoreExportsUsedInFile per workspace (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1495">#1495</a>)
(4b898a971105d865d86d4dc81bc694721bff8793)</li>
<li>feat(vscode): add <code>workspaceRoot</code> config option to enable
use in a VSCode workspace that does not have package.json at the
workspace root (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1667">#1667</a>)
(7c1ebef6ab6d1c5a7f2f920d4243241246b53f4b) - thanks <a
href="https://github.com/anmilleriii"><code>@​anmilleriii</code></a>!</li>
<li>Replace minimist with node:util.parseArgs (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1492">#1492</a>)
(b360c5ce1acfbb2cbd5f4e92ecca6c9b461ae094)</li>
<li>Preserve minimist numeric coercion and --no-x negation
(c12153ce0601378354421e454a6b6bbab74ae9fb)</li>
<li>Simplify parseArgs adapter
(ba15e413be7515620e4224b21483a1a87659dc34)</li>
<li>Detect and credit registered custom elements (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1394">#1394</a>)
(62dcda5fa46ccf6bdd94175b725fd38678049319)</li>
<li>Add Lit and FAST plugins to detect <a
href="https://github.com/customElement"><code>@​customElement</code></a>
classes (348d2c9decf09bb61ab47477bc6cc57e4b089ec3)</li>
<li>Add new testimonials (77fd7ed7dffaccfa8bc024105fe81dbe09b70671)</li>
<li>Scope custom path aliases per workspace (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1775">#1775</a>)
(d908099b52e4fd93b7947bafecbabeddfc7847f3)</li>
<li>Restructure tests (ec4c77941d42aef54bed9e4dd1cae8e8784aa147)</li>
<li>Simplify boolean check in parseArgs adapter
(ba6865de03785eb49b2adf833f7f769eece78d49)</li>
<li>Scope static custom-element define detection to the FAST plugin
(94632cddd15f75eadd204cb480b3df6c1f2a842d)</li>
<li>Add Custom Elements feature docs page
(230bd734652f3a269b70da09cd26ac7e80a210cd)</li>
<li>Update known-issues.md
(f1f4c1bceef9a6575d7b31cc1340538ea894f824)</li>
<li>Fix crash on backtick string literals in plugin config (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1776">#1776</a>)
(f1adc7fbd68fc52a89a4d2a4d6b17d905d051de7)</li>
<li>Format (e4720cab435be48e1a40afa8c548e21bdb74b14e)</li>
<li>Fix backtick string literals in require() and plugin-name config
arrays (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1776">#1776</a>)
(d14eb053331daaaeaec89c3c8e04cfeeba7580af)</li>
<li>Credit custom elements via aliases, scoped registries, and static
blocks (d7cbe12bd904f65b20016bdd2dfd4a5d7c5c1524)</li>
<li>Improve Stencil plugin: credit <a
href="https://github.com/Component"><code>@​Component</code></a> and
recognize test files (152d73052f87f29b348abbab90e117cfb97dd69b)</li>
<li>Add Catalyst plugin to credit bare <a
href="https://github.com/controller"><code>@​controller</code></a>
custom elements (8a37f8c25b03cd4e55bd18ba822906be35fcd97b)</li>
<li>Document Stencil, Catalyst, static-block custom el reg.
(105fba3a829f1cf4cf871035dbc9c170b0de7bc1)</li>
<li>Auto-format md (f4fcf4e1c6a399d761151fc367125416e7741675)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/a3169ec99b4708d7199ed9c38682a7f5f0639b1c"><code>a3169ec</code></a>
Release knip@6.16.1</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/370ef4cefec6540ee7d58249cc402f479ec76405"><code>370ef4c</code></a>
Resolve SvelteKit ./$types in monorepos (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1778">#1778</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e9a5a64f6d551ceef0bb6667e2c2582b94a77c4f"><code>e9a5a64</code></a>
Release knip@6.16.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/8a37f8c25b03cd4e55bd18ba822906be35fcd97b"><code>8a37f8c</code></a>
Add Catalyst plugin to credit bare <a
href="https://github.com/controller"><code>@​controller</code></a>
custom elements</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/152d73052f87f29b348abbab90e117cfb97dd69b"><code>152d730</code></a>
Improve Stencil plugin: credit <a
href="https://github.com/Component"><code>@​Component</code></a> and
recognize test files</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/d7cbe12bd904f65b20016bdd2dfd4a5d7c5c1524"><code>d7cbe12</code></a>
Credit custom elements via aliases, scoped registries, and static
blocks</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/d14eb053331daaaeaec89c3c8e04cfeeba7580af"><code>d14eb05</code></a>
Fix backtick string literals in require() and plugin-name config arrays
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1776">#1776</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f1adc7fbd68fc52a89a4d2a4d6b17d905d051de7"><code>f1adc7f</code></a>
Fix crash on backtick string literals in plugin config (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1776">#1776</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/94632cddd15f75eadd204cb480b3df6c1f2a842d"><code>94632cd</code></a>
Scope static custom-element define detection to the FAST plugin</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/ba6865de03785eb49b2adf833f7f769eece78d49"><code>ba6865d</code></a>
Simplify boolean check in parseArgs adapter</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.16.1/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.53.0 to 0.54.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.54.0] - 2026-06-08</h2>
<h3>📚 Documentation</h3>
<ul>
<li>dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22965">#22965</a>)
(Boshen)</li>
<li>f88961a oxfmt: Annotate each config option with supported languages
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22953">#22953</a>)
(leaysgur)</li>
</ul>
<h2>[0.52.0] - 2026-05-26</h2>
<h3>🚀 Features</h3>
<ul>
<li>16b8058 oxfmt: Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22454">#22454</a>)
(leaysgur)</li>
</ul>
<h2>[0.50.0] - 2026-05-15</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>43b9978 formatter/sort_imports: Treat subpath imports as internal
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22440">#22440</a>)
(leaysgur)</li>
</ul>
<h2>[0.49.0] - 2026-05-11</h2>
<h3>🚀 Features</h3>
<ul>
<li>6e8e818 oxfmt: Experimental .svelte support (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21700">#21700</a>)
(leaysgur)</li>
</ul>
<h2>[0.45.0] - 2026-04-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>50c389b oxfmt: Support <code>.editorconfig</code>
<code>quote_type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20989">#20989</a>)
(leaysgur)</li>
</ul>
<h2>[0.44.0] - 2026-04-06</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>dd2df87 npm: Export package.json for oxlint and oxfmt (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20784">#20784</a>)
(kazuya kawaguchi)</li>
<li>4216380 oxfmt: Support <code>.editorconfig</code>
<code>tab_width</code> fallback (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20988">#20988</a>)
(leaysgur)</li>
</ul>
<h2>[0.43.0] - 2026-03-30</h2>
<h3>🚀 Features</h3>
<ul>
<li>6ef440a oxfmt: Support bool for object style options (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20853">#20853</a>)
(leaysgur)</li>
</ul>
<h2>[0.42.0] - 2026-03-24</h2>
<h3>🚀 Features</h3>
<ul>
<li>416865a formatter,oxfmt: Add doc comments for
<code>JsdocConfig</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20644">#20644</a>)
(leaysgur)</li>
<li>4fec907 formatter: Add JSDoc comment formatting support (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/19828">#19828</a>)
(Dunqing)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/44ae845fe19d3700128e50e7e61d98c7a85f3f47"><code>44ae845</code></a>
release(apps): oxlint v1.69.0 &amp;&amp; oxfmt v0.54.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/23116">#23116</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/dadafe3e0874b2b75775d265b24d19d7f446e2bf"><code>dadafe3</code></a>
docs(oxlint, oxfmt): mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22965">#22965</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/f88961ae2968ae2a12035111d07c72797812d2fd"><code>f88961a</code></a>
docs(oxfmt): annotate each config option with supported languages (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22953">#22953</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.54.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.68.0 to 1.69.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.69.0] - 2026-06-08</h2>
<h3>🚀 Features</h3>
<ul>
<li>e805174 linter: Add schema for <code>jest/vitest/max-expects</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23105">#23105</a>)
(Sysix)</li>
<li>7850577 linter: Add schema for
<code>jest/vitest/expect-expect</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23104">#23104</a>)
(Sysix)</li>
<li>75f641a linter: Add schema for
<code>jest/vitest/consistent-test-it</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23103">#23103</a>)
(Sysix)</li>
<li>5125f89 linter/unicorn: Support no-null <code>checkArguments</code>
option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23098">#23098</a>)
(camc314)</li>
<li>b8b9797 linter: Add schema for <code>import-max-dependencies</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23096">#23096</a>)
(Sysix)</li>
<li>65cb47a linter/eslint: Support no-unused-expressions
<code>ignoreDirectives</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23097">#23097</a>)
(camc314)</li>
<li>f6c36d5 linter: Add schema for
<code>import/prefer-default-export</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23091">#23091</a>)
(Sysix)</li>
<li>0d4a5d1 linter: Add schema for <code>eslint/sort-vars</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23090">#23090</a>)
(Sysix)</li>
<li>fdb5bf5 linter: Add schema for <code>eslint/radix</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23082">#23082</a>)
(Sysix)</li>
<li>05b4dcf linter: Add schema for <code>eslint/prefer-const</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23081">#23081</a>)
(Sysix)</li>
<li>5a06c4d linter/vue: Implement next-tick-style rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23041">#23041</a>)
(Alex Peshkov)</li>
<li>e38a36a linter: Add schema for
<code>eslint/operator-assignment</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23080">#23080</a>)
(Sysix)</li>
<li>907cee7 linter: Add schema for
<code>eslint/no-warning-comments</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23075">#23075</a>)
(Sysix)</li>
<li>9470bb2 linter: Add schema for <code>eslint/no-unused-vars</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23073">#23073</a>)
(Sysix)</li>
<li>234b5cf linter: Add schema for <code>eslint/no-shadow</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23072">#23072</a>)
(Sysix)</li>
<li>de0dd8b linter: Add schema for
<code>eslint/no-restricted-exports</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23020">#23020</a>)
(Sysix)</li>
<li>faa3e0d linter: Add schema for <code>eslint/no-param-reassign</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23018">#23018</a>)
(Sysix)</li>
<li>dbc9c27 linter: Add schema for <code>eslint/no-magic-numbers</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23017">#23017</a>)
(Sysix)</li>
<li>38d3569 linter: Add schema for
<code>eslint/no-inner-declarations</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23016">#23016</a>)
(Sysix)</li>
<li>008fa41 linter: Add schema for
<code>eslint/no-constant-condition</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22991">#22991</a>)
(Sysix)</li>
<li>ca44623 linter: Add schema for <code>eslint/no-empty-function</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22988">#22988</a>)
(Sysix)</li>
<li>43eb04d linter: Add schema for <code>eslint/id-match</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22987">#22987</a>)
(Sysix)</li>
<li>a800f27 linter: Add schema for
<code>eslint/capitalized-comments</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22984">#22984</a>)
(Sysix)</li>
<li>96e2d32 linter: Add schema for <code>eslint/id-length</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22963">#22963</a>)
(Sysix)</li>
<li>545493f linter: Add schema for <code>eslint/complexity</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22960">#22960</a>)
(Sysix)</li>
<li>5f0b558 linter: Add schema for
<code>eslint/class-methods-use-this</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22959">#22959</a>)
(Sysix)</li>
<li>719b720 linter: Add schema for simple rule configurations (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22948">#22948</a>)
(Sysix)</li>
<li>fd00966 linter: Add right schema for <code>eslint/max-*</code> rules
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22923">#22923</a>)
(Sysix)</li>
<li>1226d78 linter: Fill schema with rule configurations (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22907">#22907</a>)
(Sysix)</li>
<li>8f423c1 linter/vue: Implement <code>require-direct-export</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/17623">#17623</a>)
(yefan)</li>
<li>78e915b linter/vue: Implement no-reserved-props rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22914">#22914</a>)
(bab)</li>
<li>0f200a9 linter/vue: Implement require-prop-types rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22083">#22083</a>)
(Alex Peshkov)</li>
<li>5da9da9 linter/vue: Implement no-reserved-keys rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21780">#21780</a>)
(bab)</li>
<li>75e14a8 linter/vue: Implement prop-name-casing rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22892">#22892</a>)
(bab)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>0383e61 linter: Fix schema for rules without a config (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22946">#22946</a>)
(Sysix)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>dadafe3 oxlint, oxfmt: Mention migrate skills in npm READMEs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22965">#22965</a>)
(Boshen)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/44ae845fe19d3700128e50e7e61d98c7a85f3f47"><code>44ae845</code></a>
release(apps): oxlint v1.69.0 &amp;&amp; oxfmt v0.54.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23116">#23116</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/e8051744a1bd8cd97e91f1c397f58ca9e81d4edb"><code>e805174</code></a>
feat(linter): add schema for <code>jest/vitest/max-expects</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23105">#23105</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/78505778061a70d0469382a8e786a2696a24fe74"><code>7850577</code></a>
feat(linter): add schema for <code>jest/vitest/expect-expect</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23104">#23104</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/75f641aa7388b18c14393b7b745c9cb03ec31c0b"><code>75f641a</code></a>
feat(linter): add schema for <code>jest/vitest/consistent-test-it</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23103">#23103</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d65b860b357e12120ea1f08794e1e7cfb4b5e6b7"><code>d65b860</code></a>
refactor(linter): reuse non-object references for rules schemas (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23100">#23100</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6bcd52ccdeb5c8a1ccb5fc3b1eb9227c08b7d932"><code>6bcd52c</code></a>
refactor(linter): share <code>&quot;alway&quot; |
&quot;never&quot;</code> option across rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23099">#23099</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/5125f8955ab27e4a9673f1cf34bc9d8f0aa6c6a7"><code>5125f89</code></a>
feat(linter/unicorn): support no-null <code>checkArguments</code> option
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23098">#23098</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/b8b97973c4fb7b6134a103a1c57c50db4b3d0bef"><code>b8b9797</code></a>
feat(linter): add schema for <code>import-max-dependencies</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23096">#23096</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/65cb47a197a07d3a570341ff3c3f69bb77cfd8ed"><code>65cb47a</code></a>
feat(linter/eslint): support no-unused-expressions
<code>ignoreDirectives</code> option ...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/f6c36d54d92a372b5b9486892227d34f43160cfa"><code>f6c36d5</code></a>
feat(linter): add schema for <code>import/prefer-default-export</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/23091">#23091</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.69.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 00:10:02 -04:00
dependabot[bot] bce5ea0641 Bump the gh-actions group with 2 updates (#1057)
Bumps the gh-actions group with 2 updates:
[astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and
[github/codeql-action](https://github.com/github/codeql-action).

Updates `astral-sh/setup-uv` from 8.1.0 to 8.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v8.2.0 🌈 New inputs <code>quiet</code> and
<code>download-from-astral-mirror</code></h2>
<h2>Changes</h2>
<p>This release brings two new inputs and a few bug fixes.</p>
<h3>New inputs</h3>
<p>Lets talk about the new inputs first.</p>
<h4>quiet</h4>
<p>Pretty simple. It turns of all <code>info</code> loggings. Useful if
you use this in a composite action and are not interested in all the
details.
In the upcoming releases we will add log groups to fully implement
support for &quot;less noise&quot;</p>
<blockquote>
<p>[!NOTE]<br />
Warnings and errors are always logged.</p>
</blockquote>
<h4>download-from-astral-mirror</h4>
<p>In some cases you may want to directly use the fallback of checking
for available versions and downloading releases from GitHub instead of
using the astral.sh mirror. Setting <code>download-from-astral-mirror:
false</code> allows you to do that.</p>
<h3>Bugfixes</h3>
<p>When using the astral.sh mirror to query available versions and
download releases (done by default) we now stop sending the GitHub token
in the header. The mirror never looked at it but we shouldn't be handing
out that data even if it is just a short lived token.
All other bugfixes try to limit the impact of failed GitHub queries due
to retries and other faults.</p>
<p>We couldn't pinpoint all rootcauses yet but added more logging for
error cases to track them down.</p>
<h2>🐛 Bug fixes</h2>
<ul>
<li>fix: report unexpected cache save failures <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/896">#896</a>)</li>
<li>fix: report unexpected setup failures <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/895">#895</a>)</li>
<li>fix: add timeout to fetch to prevent silent hangs <a
href="https://github.com/eifinger-bot"><code>@​eifinger-bot</code></a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/883">#883</a>)</li>
<li>Limit GitHub tokens to github.com download URLs <a
href="https://github.com/zsol"><code>@​zsol</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/878">#878</a>)</li>
<li>increase libuv-workaround timeout to 100ms <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/880">#880</a>)</li>
</ul>
<h2>🚀 Enhancements</h2>
<ul>
<li>Add quiet input to suppress info-level log output <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/898">#898</a>)</li>
<li>feat: add <code>download-from-astral-mirror</code> input <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/897">#897</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>docs: update dependabot rollup biome guidance <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/902">#902</a>)</li>
<li>chore: update known checksums for 0.11.18 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/899">#899</a>)</li>
<li>chore: update known checksums for 0.11.17 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/892">#892</a>)</li>
<li>chore: update known checksums for 0.11.16 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/889">#889</a>)</li>
<li>chore: update known checksums for 0.11.15 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/885">#885</a>)</li>
<li>chore: update known checksums for 0.11.14 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/879">#879</a>)</li>
<li>chore: update known checksums for 0.11.13 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/877">#877</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/fac544c07dec837d0ccb6301d7b5580bf5edae39"><code>fac544c</code></a>
chore(deps): roll up dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/903">#903</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/7390f777b051d6c47c9cb905ff80e7d5d85a7068"><code>7390f77</code></a>
docs: update dependabot rollup biome guidance (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/902">#902</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/363c64a728451954156ddb9e3f368b879eeee5da"><code>363c64a</code></a>
chore(deps): roll up dependabot updates (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/901">#901</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/c4fcbafce4f941a09e04c45c42db7a2e3ba5cd91"><code>c4fcbaf</code></a>
chore(deps): bump release-drafter/release-drafter from 7.3.0 to 7.3.1
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/900">#900</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/8e642c5e623b521f8b6b15bbc2ba54bae583fe45"><code>8e642c5</code></a>
chore: update known checksums for 0.11.18 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/899">#899</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/a92cb430984b4b2b34c9c47e020cf035089958fa"><code>a92cb43</code></a>
Add quiet input to suppress info-level log output (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/898">#898</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e07f2ac4b796a5fa8dc51ebf0a5187d0463eb4d6"><code>e07f2ac</code></a>
chore(deps): bump eifinger/actionlint-action from 1.10.1 to 1.10.2 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/842">#842</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/bc4034eedf3a6f77238660a28089c6b201eae39f"><code>bc4034e</code></a>
chore(deps): bump github/codeql-action from 4.35.4 to 4.36.0 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/893">#893</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/df42d4f6ba41cdcf6eda832c32439db37cc28b39"><code>df42d4f</code></a>
chore(deps): bump zizmorcore/zizmor-action from 0.5.5 to 0.5.6 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/891">#891</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/b9c8c4c7baf912cbda30843477d08b3f63b0f660"><code>b9c8c4c</code></a>
feat: add <code>download-from-astral-mirror</code> input (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/897">#897</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/08807647e7069bb48b6ef5acd8ec9567f424441b...fac544c07dec837d0ccb6301d7b5580bf5edae39">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action` from 4.36.1 to 4.36.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.36.2</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>4.35.5 - 15 May 2026</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
<h2>4.35.4 - 07 May 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.19.3 and earlier. These versions of
CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise
Server 3.15, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li>
<li>Configurations for private registries that use Cloudsmith or GCP
OIDC are now accepted. <a
href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li>
<li>Best-effort connection tests for private registries now use
<code>GET</code> requests instead of <code>HEAD</code> for better
compatibility with various registry implementations. For NuGet feeds,
the test is now always performed against the service index. <a
href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li>
<li>Fixed a bug where two diagnostics produced within the same
millisecond could overwrite each other on disk, causing one of them to
be lost. <a
href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li>
</ul>
<h2>4.35.2 - 15 Apr 2026</h2>
<ul>
<li>The undocumented TRAP cache cleanup feature that could be enabled
using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment
variable is deprecated and will be removed in May 2026. If you are
affected by this, we recommend disabling TRAP caching by passing the
<code>trap-caching: false</code> input to the <code>init</code> Action.
<a
href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li>
<li>The Git version 2.36.0 requirement for improved incremental analysis
now only applies to repositories that contain submodules. <a
href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li>
<li>Python analysis on GHES no longer extracts the standard library,
relying instead on models of the standard library. This should result in
significantly faster extraction and analysis times, while the effect on
alerts should be minimal. <a
href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li>
<li>Fixed a bug in the validation of OIDC configurations for private
registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/8aad20d150bbac5944a9f9d289da16a4b0d87c1e"><code>8aad20d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3949">#3949</a>
from github/update-v4.36.2-dcb947ce1</li>
<li><a
href="https://github.com/github/codeql-action/commit/f521b08cd8f468ab193ea950a589cb2e9c869c6a"><code>f521b08</code></a>
Add additional changelog notes</li>
<li><a
href="https://github.com/github/codeql-action/commit/8aeff0ffb7b78582ee0d0e6eebb8140684400d08"><code>8aeff0f</code></a>
Update changelog for v4.36.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/dcb947ce15976d40ea82935510b2db4872ec124c"><code>dcb947c</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3948">#3948</a>
from github/update-bundle/codeql-bundle-v2.25.6</li>
<li><a
href="https://github.com/github/codeql-action/commit/c251bcefa178f7780f62f150002acffe3d07fde9"><code>c251bce</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/62953c18b35f59e28351d2f1e806925aef8b1e3c"><code>62953c1</code></a>
Update default bundle to codeql-bundle-v2.25.6</li>
<li><a
href="https://github.com/github/codeql-action/commit/423b570baf1976cd7a3daeba5d6e9f9b76432f37"><code>423b570</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3946">#3946</a>
from github/dependabot/npm_and_yarn/npm-minor-5d507a...</li>
<li><a
href="https://github.com/github/codeql-action/commit/c35d1b164463ee62a100735382aaaa525c5d3496"><code>c35d1b1</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3947">#3947</a>
from github/dependabot/github_actions/dot-github/wor...</li>
<li><a
href="https://github.com/github/codeql-action/commit/cb1a588b02755b176e7b9d033ed4b69312f0e1bd"><code>cb1a588</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3937">#3937</a>
from github/robertbrignull/waitForProcessing_backoff</li>
<li><a
href="https://github.com/github/codeql-action/commit/ba47406412c54532b5b4fcfbaf877c9e2382b206"><code>ba47406</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3943">#3943</a>
from github/henrymercer/cache-cli-version-info</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 00:09:58 -04:00
spindrift 0633cfde87 Add content_type=combined URL parameter and FORCE_COMBINED_SEARCH user setting (#1058)
Adds support for `content_type=combined` in URL search parameters,
letting users force combined-mode searches via a bookmarkable link
rather than relying on the last-used preference from localStorage.

The override is applied only in Universal mode and only when combined
mode is actually available (universal enabled, `show_combined_selector`
on, neither content type blocked by policy). Otherwise, it's silently
ignored, consistent with how `content_type=ebook`/`audiobook` already
behave outside Universal.

Existing `content_type=ebook`/`audiobook` URLs now also force combined
mode off, so the URL is authoritative regardless of prior preference.

Also adds a per-user `FORCE_COMBINED_SEARCH` setting that locks combined
mode on whenever it's available.

URL `content_type=ebook`/`audiobook` overrides are also superseded by
force-combined for the same reason: the search bar wouldn't let users
switch back, so honoring the URL param would leave them in a state they
couldn't escape from.
2026-06-14 00:09:30 -04:00
dependabot[bot] b2131fa940 Bump the python-deps group across 1 directory with 2 updates (#1054)
Bumps the python-deps group with 2 updates in the / directory:
[flask-cors](https://github.com/corydolphin/flask-cors) and
[basedpyright](https://github.com/detachhead/basedpyright).

Updates `flask-cors` from 6.0.3 to 6.0.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/corydolphin/flask-cors/releases">flask-cors's
releases</a>.</em></p>
<blockquote>
<h2>6.0.5</h2>
<p>Supersedes 6.0.4</p>
<h2>What's Changed</h2>
<ul>
<li>Add MyPy Typing and modernize options parsing by <a
href="https://github.com/corydolphin"><code>@​corydolphin</code></a> in
<a
href="https://redirect.github.com/corydolphin/flask-cors/pull/409">corydolphin/flask-cors#409</a>
(this broke strict type checking when using Blueprints)</li>
<li>Restore Blueprint support in CORS type signatures (<a
href="https://redirect.github.com/corydolphin/flask-cors/issues/410">#410</a>)
by <a
href="https://github.com/corydolphin"><code>@​corydolphin</code></a> in
<a
href="https://redirect.github.com/corydolphin/flask-cors/pull/411">corydolphin/flask-cors#411</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.3...6.0.5">https://github.com/corydolphin/flask-cors/compare/6.0.3...6.0.5</a></p>
<h2>6.0.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add MyPy Typing by <a
href="https://github.com/corydolphin"><code>@​corydolphin</code></a> in
<a
href="https://redirect.github.com/corydolphin/flask-cors/pull/409">corydolphin/flask-cors#409</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.3...6.0.4">https://github.com/corydolphin/flask-cors/compare/6.0.3...6.0.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/corydolphin/flask-cors/commit/91ebc49c25aaf76b0e53e925feef1e3f19617c87"><code>91ebc49</code></a>
Typing Hotfix: support blueprints in the type system</li>
<li><a
href="https://github.com/corydolphin/flask-cors/commit/d601665840bdf128912573c9b02e1b55062625a1"><code>d601665</code></a>
Add strict MyPy Typing</li>
<li>See full diff in <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.3...6.0.5">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.6 to 1.39.7
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/c9a757d246d3301e992796278216a2120b8163b0"><code>c9a757d</code></a>
1.39.7</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/d253d82094093686e95fa4b0d12ced13f8094d79"><code>d253d82</code></a>
avoid duplicated capability registrations</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/19c354517cc1e1341b9a90d7f672a1edfa4b1b97"><code>19c3545</code></a>
fix empty semantic tokens response interfering with other language
servers wh...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/b0181925c9bb68eebd394764ceb54531c6b23c56"><code>b018192</code></a>
update baseline file</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/15ee8f1eacd803fdbfa4915d4e402c6bd962df97"><code>15ee8f1</code></a>
revert upstream's ai generated bash clusterfuck of an attempt at fixing
the p...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/daec470463d8fe39e1c83d1abfa17748b3cdfe60"><code>daec470</code></a>
try using pyprojectx to install primer instead of uv</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f9650c5b2e87a3a8a81bda43010ec25a555116e1"><code>f9650c5</code></a>
update mypy_primer repo</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/48fe1c8fc731b2a9812a2b742a608ee1ce1c8286"><code>48fe1c8</code></a>
don't recurse submodules when cloning repos in the primer, it screws up
becau...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/af9a1fd8fd67f8d2ac697965b617a85aa70b8a20"><code>af9a1fd</code></a>
fix completely useless <code>CalledProcesError</code> messages</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/3b5becb063a7a8b76727317bc4abef2fd44294e8"><code>3b5becb</code></a>
update this project's basedpyright/ruff config for the mypy_primer
repo</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.6...v1.39.7">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-12 00:23:48 -04:00
dependabot[bot]andCaliBrain 7e8a0248a0 Bump the python-deps group with 2 updates (#1051)
Bumps the python-deps group with 2 updates:
[flask-cors](https://github.com/corydolphin/flask-cors) and
[qbittorrent-api](https://github.com/rmartin16/qbittorrent-api).

Updates `flask-cors` from 6.0.2 to 6.0.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/corydolphin/flask-cors/releases">flask-cors's
releases</a>.</em></p>
<blockquote>
<h2>6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Derive package version from git tag via setuptools-scm by <a
href="https://github.com/corydolphin"><code>@​corydolphin</code></a> in
<a
href="https://redirect.github.com/corydolphin/flask-cors/pull/405">corydolphin/flask-cors#405</a></li>
<li>Improve CI/CD security with least privilege and build separation by
<a href="https://github.com/corydolphin"><code>@​corydolphin</code></a>
in <a
href="https://redirect.github.com/corydolphin/flask-cors/pull/406">corydolphin/flask-cors#406</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.2...6.0.3">https://github.com/corydolphin/flask-cors/compare/6.0.2...6.0.3</a></p>
<h2>6.0.3-pre</h2>
<h2>What's Changed</h2>
<ul>
<li>Derive package version from git tag via setuptools-scm by <a
href="https://github.com/corydolphin"><code>@​corydolphin</code></a> in
<a
href="https://redirect.github.com/corydolphin/flask-cors/pull/405">corydolphin/flask-cors#405</a></li>
<li>Improve CI/CD security with least privilege and build separation by
<a href="https://github.com/corydolphin"><code>@​corydolphin</code></a>
in <a
href="https://redirect.github.com/corydolphin/flask-cors/pull/406">corydolphin/flask-cors#406</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.2...6.0.3">https://github.com/corydolphin/flask-cors/compare/6.0.2...6.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/corydolphin/flask-cors/commit/c8e8871076c7ed378eb0ae773a2079b6d62ed7a9"><code>c8e8871</code></a>
Harden release publishing workflow (<a
href="https://redirect.github.com/corydolphin/flask-cors/issues/406">#406</a>)</li>
<li><a
href="https://github.com/corydolphin/flask-cors/commit/e1d4034e2b2d5232f6fed27bc753f90331747b64"><code>e1d4034</code></a>
Derive package version from git tag via setuptools-scm (<a
href="https://redirect.github.com/corydolphin/flask-cors/issues/405">#405</a>)</li>
<li>See full diff in <a
href="https://github.com/corydolphin/flask-cors/compare/6.0.2...6.0.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `qbittorrent-api` from 2026.5.1 to 2026.6.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/releases">qbittorrent-api's
releases</a>.</em></p>
<blockquote>
<h2>release-2026.6.0</h2>
<h2>What's Changed</h2>
<h3>Features</h3>
<ul>
<li>Add processInfo to API by <a
href="https://github.com/GordonFreemanK"><code>@​GordonFreemanK</code></a>
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/626">rmartin16/qbittorrent-api#626</a></li>
</ul>
<h3>Fixes</h3>
<ul>
<li>fix: correct syntax errors in code examples in
behavior&amp;configuration.rst by <a
href="https://github.com/AmSach"><code>@​AmSach</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/627">rmartin16/qbittorrent-api#627</a></li>
</ul>
<h3>Chores</h3>
<ul>
<li>Bump pre-commit hook for ruff-pre-commit from v0.15.12 to v0.15.15
by <a href="https://github.com/rmartin16"><code>@​rmartin16</code></a>
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/622">rmartin16/qbittorrent-api#622</a></li>
<li>Bump pre-commit hook for mirrors-mypy from v1.20.2 to v2.1.0 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/621">rmartin16/qbittorrent-api#621</a></li>
<li>Bump the github-actions group with 3 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/623">rmartin16/qbittorrent-api#623</a></li>
<li>use uv for project orchestration by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/624">rmartin16/qbittorrent-api#624</a></li>
<li>Bump actions/cache from 4 to 5 in the github-actions group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/625">rmartin16/qbittorrent-api#625</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/AmSach"><code>@​AmSach</code></a> made
their first contribution in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/627">rmartin16/qbittorrent-api#627</a></li>
<li><a
href="https://github.com/GordonFreemanK"><code>@​GordonFreemanK</code></a>
made their first contribution in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/626">rmartin16/qbittorrent-api#626</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.3...v2026.6.0">https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.3...v2026.6.0</a></p>
<h2>release-2026.5.3</h2>
<h2>What's Changed</h2>
<ul>
<li>minimum python 3.10 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/618">rmartin16/qbittorrent-api#618</a></li>
<li>add support for auth via api key by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/620">rmartin16/qbittorrent-api#620</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.2...v2026.5.3">https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.2...v2026.5.3</a></p>
<h2>release-2026.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>add support for share limits mode by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/614">rmartin16/qbittorrent-api#614</a></li>
<li>document &quot;Default&quot; option for share_limit_action parameter
by <a
href="https://github.com/HertogArjan"><code>@​HertogArjan</code></a> in
<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/616">rmartin16/qbittorrent-api#616</a></li>
<li>advertise support for qBittorrent v5.2.1 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/617">rmartin16/qbittorrent-api#617</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.1...v2026.5.2">https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.1...v2026.5.2</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md">qbittorrent-api's
changelog</a>.</em></p>
<blockquote>
<h3>v2026.6.0 (5 jun 2026)</h3>
<ul>
<li>Add support for <code>app/processInfo</code></li>
</ul>
<h3>v2026.5.3 (30 may 2026)</h3>
<ul>
<li>Add support for API key authentication (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/620">#620</a>)</li>
<li>Minimum Python is now 3.10 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/618">#618</a>)</li>
</ul>
<h3>v2026.5.2 (30 may 2026)</h3>
<ul>
<li>Advertise support for qBittorrent v5.2.1</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/0bd26a9f44c113a315146428c3fd78408bc2c985"><code>0bd26a9</code></a>
Add processInfo to API (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/626">#626</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/c68695ca517a13956e8377c782afeb4c06b71e73"><code>c68695c</code></a>
fix: correct syntax errors in code examples in
behavior&amp;configuration.rst (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/627">#627</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/80f0557f7a39938572a7b77a80a06ade981a6d8a"><code>80f0557</code></a>
Bump actions/cache from 4 to 5 in the github-actions group (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/625">#625</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/9c828e7bc38b17aaddd798edb4cf65657bec5c9d"><code>9c828e7</code></a>
use uv for project orchestration (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/624">#624</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/95c1daec209d54f723bc48e21254a9cffa3072dd"><code>95c1dae</code></a>
Bump the github-actions group with 3 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/623">#623</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/e56e6131a3d3eddee759b61e50d633cd96aa0736"><code>e56e613</code></a>
Bumped pre-commit hook for mirrors-mypy from v1.20.2 to v2.1.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/621">#621</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/e2dbe0f8c30bdea9f8fb497ca9c89ceb67099e4a"><code>e2dbe0f</code></a>
Bumped pre-commit hook for ruff-pre-commit from v0.15.12 to v0.15.15 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/622">#622</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/1e3716a71796ed0769756d6f6dabf1de9204b614"><code>1e3716a</code></a>
bump to v2026.5.3</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/0e8476f6d1a2023d4d4e7a32e875a79aa815bb61"><code>0e8476f</code></a>
add support for auth via api key (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/620">#620</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/f606b854959776204836a76b1e5a9aef959acc67"><code>f606b85</code></a>
Bump the pip group with 8 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/619">#619</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.1...v2026.6.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-10 03:26:50 -04:00
CaliBrain b914f77748 Fix CI/CD issues (#1052) 2026-06-10 03:17:40 -04:00
5f3a94d3b2 fix(transmission): handle completion when seed ratio is 0 (#1023)
## Description
When using Transmission as the torrent client with a seed ratio/limit
set to `0` (so it immediately stops seeding upon completion), the
torrent moves directly to the `"stopped"` state upon reaching 100%
completion.
Previously, `transmission.py` strictly checked that the state was
`"seeding"` to mark it complete:
  ```python
complete = progress >= _SEEDING_PROGRESS_PERCENT and status_value ==
"seeding"
  ```
Because of this, the completed torrent was never marked as finished, and
Shelfmark got stuck in an infinite polling loop. After 5 minutes, the
orchestrator's stall detector triggered and cancelled the download in
the queue (even though the files were fully downloaded and sitting in
  the complete directory).
  ## Fix
Updated the completion check in
`shelfmark/download/clients/transmission.py` to allow `"stopped"` as a
completed state as long as progress is 100%. This aligns it with how
other torrent clients (like qBittorrent and Deluge) handle completion:
  ```python
complete = progress >= _SEEDING_PROGRESS_PERCENT and status_value in
("seeding", "stopped")
  ```
  ## Related Issue
  Fixes #1022

Co-authored-by: cfoucher <cfoucher@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 20:55:38 -04:00
dependabot[bot]andCaliBrain 5d5b8d4bef Bump the python-deps group across 1 directory with 8 updates (#1049)
Bumps the python-deps group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [python-socketio](https://github.com/miguelgrinberg/python-socketio) |
`5.16.1` | `5.16.2` |
| [tqdm](https://github.com/tqdm/tqdm) | `4.67.3` | `4.68.1` |
| [gevent](https://github.com/gevent/gevent) | `26.4.0` | `26.5.0` |
| [apprise](https://github.com/caronc/apprise) | `1.10.0` | `1.11.0` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.48.4` | `4.49.7` |
| [basedpyright](https://github.com/detachhead/basedpyright) | `1.39.3`
| `1.39.6` |
| [prek](https://github.com/j178/prek) | `0.3.13` | `0.4.4` |
| [ruff](https://github.com/astral-sh/ruff) | `0.15.12` | `0.15.16` |


Updates `python-socketio` from 5.16.1 to 5.16.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/releases">python-socketio's
releases</a>.</em></p>
<blockquote>
<h2>Release 5.16.2</h2>
<p>See <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">CHANGES.md</a>
for release notes.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/miguelgrinberg/python-socketio/blob/main/CHANGES.md">python-socketio's
changelog</a>.</em></p>
<blockquote>
<h1>python-socketio change log</h1>
<p><strong>Release 5.16.2</strong> - 2026-05-21</p>
<ul>
<li>Prevent unnecessary resource allocations <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1574">#1574</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ca140fe44d0ceb3004073645222abec182d8784b">commit</a>)</li>
<li>Add zizmor to CI builds <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1570">#1570</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/664dc27ec6f34179ed1724430eda3520627fc642">commit</a>)</li>
</ul>
<p><strong>Release 5.16.1</strong> - 2026-02-06</p>
<ul>
<li>Use configured JSON module in managers <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1549">#1549</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6229261ae6e8c01e675097242e333ee84587a544">commit</a>)</li>
<li>Admin UI fixes: remove duplicate tasks, report transport upgrades
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1c2eab13a92fac9e43663eb0b5f099eb1c40ea5b">commit</a>)</li>
<li>Switch to Furo documentation template (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/add47d8c7abca697a2804141bbf29bfb095f7d5e">commit</a>)</li>
<li>Add Python free-threading to CI <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1554">#1554</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/ccdd2004a038ae4b8171a05120c5d0787332f7ee">commit</a>)</li>
</ul>
<p><strong>Release 5.16.0</strong> - 2025-12-24</p>
<ul>
<li>Address deprecation warnings (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b235699d9b06564753c570b76055997e9d62a938">commit</a>)</li>
<li>Drop Python 3.8 and 3.9 from CI builds (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/d0728d2f74538762dd551fa9cd0cd1fd5aedfa37">commit</a>)</li>
</ul>
<p><strong>Release 5.15.1</strong> - 2025-12-16</p>
<ul>
<li>Restore support multiple arguments via pubsub emits <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1540">#1540</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c279f26bb8c9887c4ca99d4d81ad331c4844438c">commit</a>)</li>
</ul>
<p><strong>Release 5.15.0</strong> - 2025-11-22</p>
<ul>
<li>Retry initial Redis connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1536">#1534</a>
([commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1">#1</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad">https://github.com/miguelgrinberg/python-socketio/commit/1e903e173a2d7b04599c4f7f9630c1abbb531fad</a>)
[commit <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/2">#2</a>](<a
href="https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d">https://github.com/miguelgrinberg/python-socketio/commit/5e898a9b93526e6e667767e54c60f4c84589989d</a>))</li>
<li>Correctly regenerate RabbitMQ binding after a connection failure <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1516">#1516</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/c52e93b4a328d98a968bfbdec0cfd598b73ee913">commit</a>)
(thanks <strong>Gritty_dev</strong>!)</li>
<li>Support <code>ext_type</code> in the <code>MsgPackPacket</code>
class <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1521">#1521</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/208925344a48485d2cd56e40eb74266c3bcb5311">commit</a>)</li>
<li>Support sending <code>bytesarray</code>s when using pub/sub managers
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6c9b9974f72e2efdf62407ecab24ee6995448098">commit</a>)</li>
<li>Fix typos in documentation <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1520">#1520</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/db3f1c2a0105c30cb833ddfca8f05fe4320468fd">commit</a>)
(thanks <strong>Lê Nam Khánh</strong>!)</li>
<li>Improvements to the logging documentation (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/b423d0e38eef559b7e81acb7e32059de305f982c">commit</a>)</li>
</ul>
<p><strong>Release 5.14.3</strong> - 2025-10-29</p>
<ul>
<li>Support Python's native <code>ConnectionRefusedError</code>
exception to reject a connection <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1515">#1515</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f3b18bde3f16437b223491d4c3e440ea37105fe3">commit</a>)</li>
<li>Push binary data to the aiopika client manager <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1514">#1514</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/194e1b7f277b5f72e1de78d3f614e7b8b6c788ac">commit</a>)</li>
</ul>
<p><strong>Release 5.14.2</strong> - 2025-10-15</p>
<ul>
<li>Restore binary message support in message queue setups <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1509">#1509</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/bab4a10f48aaae11d7f832ebe5c30ad3f85d31b3">commit</a>)</li>
<li>Fix formatting of client connection error <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1507">#1507</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/f298c9b54d76ab09ff72935937e1b9575bc45ffd">commit</a>)</li>
<li>Add 3.14 and pypy-3.11 CI tasks (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/1f4cd3b025c294f25208ec3c05b5f8df6209e403">commit</a>)</li>
<li>Improve documentation of the
<code>BaseManager.get_participants()</code> method (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/33722a0d96036f005188b07b8b46a5ef091fe65f">commit</a>)</li>
</ul>
<p><strong>Release 5.14.1</strong> - 2025-10-02</p>
<ul>
<li>Restore support for <code>rediss://</code> URLs, and add support for
<code>valkeys://</code> as well (<a
href="https://github.com/miguelgrinberg/python-socketio/commit/6e2d0de12bb4e4a99fdfc30bed0706ded620822c">commit</a>)</li>
<li>Add support for Redis connections using unix sockets <a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1503">#1503</a>
(<a
href="https://github.com/miguelgrinberg/python-socketio/commit/a8deb3a8f3ee51d75c124157efa7fc9289fd592b">commit</a>)
(thanks <strong>Darren Chang</strong>!)</li>
</ul>
<p><strong>Release 5.14.0</strong> - 2025-09-30</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/6e2b7175c97c2785edd2ea60df026c12240c785c"><code>6e2b717</code></a>
Release 5.16.2</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/cb658291085842372a16863d83e14373f85b3d3e"><code>cb65829</code></a>
update python-engineio version</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/ca140fe44d0ceb3004073645222abec182d8784b"><code>ca140fe</code></a>
prevent unnecessary resource allocation (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1574">#1574</a>)</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/b29beef6bfd38d5a3c3b89da96b7a4574a91efcf"><code>b29beef</code></a>
tox configuration</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/e8981302a3d5b525ee73c2ec9c13859ce2f764e8"><code>e898130</code></a>
Bump ujson from 5.4.0 to 5.12.1 in /examples/server/sanic (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1573">#1573</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/05c32f5da85fe5e5d647c937c7eab0972760ca05"><code>05c32f5</code></a>
Bump qs and body-parser in /examples/server/javascript (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1572">#1572</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/287dc6715b801d319f5baa0fb727e232e728b8aa"><code>287dc67</code></a>
Bump qs and body-parser in /examples/client/javascript (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1571">#1571</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/664dc27ec6f34179ed1724430eda3520627fc642"><code>664dc27</code></a>
add zizmor to ci (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1570">#1570</a>)</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/14c62366a85cfe34e0bd69a22b905eb329873dd3"><code>14c6236</code></a>
Bump django in /examples/server/wsgi/django_socketio (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1566">#1566</a>)
#nolog</li>
<li><a
href="https://github.com/miguelgrinberg/python-socketio/commit/29b2e5cdbe87e8216bc46fccb864b84ab9f55cf9"><code>29b2e5c</code></a>
Bump aiohttp from 3.13.3 to 3.13.4 in /examples/server/aiohttp (<a
href="https://redirect.github.com/miguelgrinberg/python-socketio/issues/1565">#1565</a>)
#nolog</li>
<li>Additional commits viewable in <a
href="https://github.com/miguelgrinberg/python-socketio/compare/v5.16.1...v5.16.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `tqdm` from 4.67.3 to 4.68.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tqdm/tqdm/releases">tqdm's
releases</a>.</em></p>
<blockquote>
<h2>tqdm v4.68.1 stable</h2>
<ul>
<li>set name of monitor thread (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1669">#1669</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1752">#1752</a> &lt;-
<a
href="https://redirect.github.com/tqdm/tqdm/issues/1435">#1435</a>)</li>
<li>fix monitor thread <code>atexit</code> deadlock (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1751">#1751</a> &lt;-
<a href="https://redirect.github.com/tqdm/tqdm/issues/528">#528</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/627">#627</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1435">#1435</a>, <a
href="https://redirect.github.com/tqdm/tqdm/issues/1564">#1564</a>)</li>
<li>docs: minor copyediting</li>
</ul>
<h2>tqdm v4.68.0 stable</h2>
<ul>
<li><code>utils</code>: simplify terminal size detection (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a>)</li>
<li><code>contrib</code>
<ul>
<li><code>itertools</code> (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a>)
<ul>
<li>add <code>chain</code>, <code>permutations</code>,
<code>combinations</code>, <code>combinations_with_replacement</code>,
<code>batched</code></li>
<li>add <code>product(repeat=1)</code> keyword argument (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1428">#1428</a>)</li>
</ul>
</li>
<li>fix <code>discord</code>, <code>telegram</code> error handling</li>
<li>fix <code>discord</code>, <code>slack</code>, <code>telegram</code>
format for <code>total=None</code></li>
</ul>
</li>
<li>soft-deprecate <code>tqdm.utils.envwrap</code> -&gt; <a
href="https://github.com/tqdm/envwrap"><code>envwrap</code></a></li>
<li>benchmarks: fix <code>asv</code></li>
<li>misc linting</li>
<li>misc framework updates
<ul>
<li>CI: migrate manual job to <code>pre-commit.ci</code></li>
<li>bump workflow actions &amp; pre-commit hooks</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tqdm/tqdm/commit/67cf355f96dfc3e459d18193d68a98a7abb6e08e"><code>67cf355</code></a>
Merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1751">#1751</a> from
jaltmayerpizzorno/fix-atexit-monitor-deadlock</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/cfa4a8522e8915e5f3f29dec9cedf7a75e366e1a"><code>cfa4a85</code></a>
minor docstring updates</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/f83290ce32f424e0562d47efe2304cdb90d244d5"><code>f83290c</code></a>
Fix TMonitor deadlock at interpreter shutdown</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/59029c37ad6af57df7b49d31c0f48728280ae824"><code>59029c3</code></a>
Set name for tqdm monitor thread (<a
href="https://redirect.github.com/tqdm/tqdm/issues/1752">#1752</a>)</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/ef4a142ebd53f05b8765b969590e9a888498ab57"><code>ef4a142</code></a>
bump version, merge pull request <a
href="https://redirect.github.com/tqdm/tqdm/issues/1760">#1760</a> from
tqdm/devel</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/17f246b77dcfc29bfeaaa8bfa12ddb45557606bc"><code>17f246b</code></a>
lint warning suppression</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/c682c7b73142b1b469e698e0cf62e2963cdfb7d1"><code>c682c7b</code></a>
benchmarks: fix asv</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/fc69588dc219f30c4c59adad98355cc09933f271"><code>fc69588</code></a>
CI: migrate to pre-commit.ci</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/a31d97f821d9bf33f1b7e0a9738a3ea62baa68ca"><code>a31d97f</code></a>
more contrib.itertools</li>
<li><a
href="https://github.com/tqdm/tqdm/commit/e4d97426d6c6df91bbd681f3fe9ac98b1d704011"><code>e4d9742</code></a>
soft-deprecate tqdm.utils.envwrap -&gt; envwrap</li>
<li>Additional commits viewable in <a
href="https://github.com/tqdm/tqdm/compare/v4.67.3...v4.68.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `gevent` from 26.4.0 to 26.5.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/gevent/gevent/commit/33c560c2e26998eff1e1cea252646a17922ec5d7"><code>33c560c</code></a>
Preparing release 26.5.0</li>
<li><a
href="https://github.com/gevent/gevent/commit/7cebc52f71cd2609c4af4f5037fe630601197e14"><code>7cebc52</code></a>
ci.yml: add comments about likely problem with macOS 15/26</li>
<li><a
href="https://github.com/gevent/gevent/commit/6a9192e6fd6b2db29a70bd5a801a5d48d2d7fcdf"><code>6a9192e</code></a>
Add 315 to make-manylinux.</li>
<li><a
href="https://github.com/gevent/gevent/commit/65561dc1642304ab3cde9636146a8537ae1e7ae4"><code>65561dc</code></a>
Add change note.</li>
<li><a
href="https://github.com/gevent/gevent/commit/a65159824046b3b2da942e516c49e6b959a82548"><code>a651598</code></a>
test__threading is apparently initializing the hub on
3.15b1/ubuntu-latest/GH...</li>
<li><a
href="https://github.com/gevent/gevent/commit/c2cda32db8c33c68ee115d22bebfb3b02436298e"><code>c2cda32</code></a>
Disable some linux-specific pidfd tests because we don't use that.</li>
<li><a
href="https://github.com/gevent/gevent/commit/53371df6bef15c66f495f907d965be089d326e44"><code>53371df</code></a>
We can't do coverage on 3.15b1, it doesn't have the binary tracer needed
for ...</li>
<li><a
href="https://github.com/gevent/gevent/commit/ed9160afeb8032d9a0a1ce9cb31f817b5c63c05a"><code>ed9160a</code></a>
Initial support for Python 3.15</li>
<li><a
href="https://github.com/gevent/gevent/commit/36e8203a07ac4610102b6170161467a9595a4642"><code>36e8203</code></a>
Remove the CI badges from README.rst.</li>
<li><a
href="https://github.com/gevent/gevent/commit/21bf47d6b18caa91a151a4654b54b3145e1eb5d0"><code>21bf47d</code></a>
Disable appveyor, the windows github action runners were
successful.</li>
<li>Additional commits viewable in <a
href="https://github.com/gevent/gevent/compare/26.4.0...26.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `apprise` from 1.10.0 to 1.11.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/caronc/apprise/releases">apprise's
releases</a>.</em></p>
<blockquote>
<h2>Release v1.11.0</h2>
<h2>What's Changed</h2>
<p>A big win for this release is priortization of grouped/tagged
content. Basically, this release allows you to tag multiple items and
provide a weight to them. Apprise will attempt to notify the highest
priority/weighted services first (of same level), and only if this level
fails will it try the next. Tagging is no longer just a
<code>tag</code>. It's now <code>weight:tag</code> too; for example
<code>100:friends</code> associates the weight of <code>100</code> with
the tag <code>friends</code>. You can still continue to notify friends
with your Apprise calls, but if there are weight categories, then these
will be factored into the order. Highest priority (weighted) tags have a
lower integer value (zero being the higest priority). Only the next
priority will be notified if the first fails.</p>
<p>This releae also allows you to set up a notifiation service to
gracefully fail and not have Apprise itself report a failure. This is
useful for situations where you notify several end points and you really
don't care if they're unavailable or not. Apprise wil do it's usual best
effort to send the notification, but not treat it as a failure if it
can't get through. Use <code>optional=yes</code> on your Apprise
URL.</p>
<p>Thirdly, this release introduces retries! You can now have Apprise
attempt to notify your endpoint a second, or a third, (up to 10x) tries
before giving up and deeming it unable to send the notification. Use
<code>retry=X</code> on your Apprise URL</p>
<h3>📣 New Notification Services:</h3>
<ul>
<li>Added Zoom (Incoming Webhook) Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1596">caronc/apprise#1596</a></li>
<li>Added WeChat Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1598">caronc/apprise#1598</a></li>
<li>RingCentral Support Added in <a
href="https://redirect.github.com/caronc/apprise/pull/878">caronc/apprise#878</a></li>
<li>Session Open Group Server Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1615">caronc/apprise#1615</a></li>
<li>Added HumHub Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1623">caronc/apprise#1623</a></li>
<li>Amazon Chime Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1627">caronc/apprise#1627</a></li>
<li>GroupMe Support Added in <a
href="https://redirect.github.com/caronc/apprise/pull/1629">caronc/apprise#1629</a></li>
</ul>
<h3>🐞  Bugfixes</h3>
<ul>
<li>improved robustness of windows test cases preventing others from
passing in <a
href="https://redirect.github.com/caronc/apprise/pull/1609">caronc/apprise#1609</a></li>
<li>Handle XMPP SASL SCRAM-PLUS / Channel Binding in <a
href="https://redirect.github.com/caronc/apprise/pull/1619">caronc/apprise#1619</a></li>
<li>TRACE logging during apprise init cleaned up in <a
href="https://redirect.github.com/caronc/apprise/pull/1622">caronc/apprise#1622</a></li>
<li>fixed mastodon error: AttributeError - 'list' object has no
attribute 'union' in <a
href="https://redirect.github.com/caronc/apprise/pull/1631">caronc/apprise#1631</a></li>
</ul>
<h3>💡 Features</h3>
<ul>
<li>o365:// saveToSentItems configurable - ?savesent=no in <a
href="https://redirect.github.com/caronc/apprise/pull/1599">caronc/apprise#1599</a></li>
<li>updated WhatsApp Buisness Graph API to v21 in <a
href="https://redirect.github.com/caronc/apprise/pull/1603">caronc/apprise#1603</a></li>
<li>🔥 Built in retries, escalations, priorities, and optional
service calls in <a
href="https://redirect.github.com/caronc/apprise/pull/1601">caronc/apprise#1601</a></li>
<li>Slack Template/Payload support in <a
href="https://redirect.github.com/caronc/apprise/pull/1604">caronc/apprise#1604</a></li>
<li>Added Slack workflows and trigger support in <a
href="https://redirect.github.com/caronc/apprise/pull/1605">caronc/apprise#1605</a></li>
<li>🚀 Pushover E2EE Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1612">caronc/apprise#1612</a></li>
<li>WKD support added to email plugin in <a
href="https://redirect.github.com/caronc/apprise/pull/1614">caronc/apprise#1614</a>
and <a
href="https://redirect.github.com/caronc/apprise/pull/1618">caronc/apprise#1618</a></li>
<li>Amazon SNS/SES Improvements in <a
href="https://redirect.github.com/caronc/apprise/pull/1620">caronc/apprise#1620</a></li>
<li>Notifico Standalone Support Added in <a
href="https://redirect.github.com/caronc/apprise/pull/1275">caronc/apprise#1275</a></li>
</ul>
<h3>❤️ Life-Cycle Support</h3>
<ul>
<li>Update LoC badge by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/caronc/apprise/pull/1593">caronc/apprise#1593</a></li>
<li>Twitter/X migration to API v2 in <a
href="https://redirect.github.com/caronc/apprise/pull/1607">caronc/apprise#1607</a></li>
<li>improvements to workflow:// based on recent slack:// changes in <a
href="https://redirect.github.com/caronc/apprise/pull/1608">caronc/apprise#1608</a></li>
<li>🔓 Added redirect= for allowing url redirection control in <a
href="https://redirect.github.com/caronc/apprise/pull/1610">caronc/apprise#1610</a></li>
<li>mqtt:// now depends on paho-mqtt v2.1.0+ in <a
href="https://redirect.github.com/caronc/apprise/pull/1613">caronc/apprise#1613</a></li>
<li>💀 Retire msteams:// as it is no longer in service upstream in
<a
href="https://redirect.github.com/caronc/apprise/pull/1625">caronc/apprise#1625</a></li>
</ul>
<h2>Installation</h2>
<p>Apprise is available <a href="https://pypi.org/project/apprise/">on
PyPI</a> through <em>pip</em>:</p>
<pre lang="bash"><code># Install Apprise v1.11.0 from PyPI
pip install apprise==1.11.0
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/caronc/apprise/commit/158c4e1febc3e6093b0f357776b315a90c8a89b5"><code>158c4e1</code></a>
bumped version to v1.11.0</li>
<li><a
href="https://github.com/caronc/apprise/commit/21db421ee89b24f1716a4fce74a4404a94bbabe7"><code>21db421</code></a>
GroupMe Support Added (<a
href="https://redirect.github.com/caronc/apprise/issues/1629">#1629</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/f1e4ad2fd6659529597b1e07a1e44192faebff54"><code>f1e4ad2</code></a>
fixed mastodon error: AttributeError - 'list' object has no attribute
'union'...</li>
<li><a
href="https://github.com/caronc/apprise/commit/e17fe9dd64dd79e373877cf8ee07595cc50a01cc"><code>e17fe9d</code></a>
Amazon Chime Support (<a
href="https://redirect.github.com/caronc/apprise/issues/1627">#1627</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/dfdac59c9945385c4c75613e57d19558ec995d50"><code>dfdac59</code></a>
HumHub Support added (<a
href="https://redirect.github.com/caronc/apprise/issues/1623">#1623</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/9de0397c30a7a2e58eb57c8da995ec54eada80bc"><code>9de0397</code></a>
Notifico Standalone Support Added (<a
href="https://redirect.github.com/caronc/apprise/issues/1275">#1275</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/c3e67e61d35a1b0609d176786db1e0b2cc1287da"><code>c3e67e6</code></a>
Retired msteams:// - as it is no longer in service upstream (<a
href="https://redirect.github.com/caronc/apprise/issues/1625">#1625</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/b463f23979455b61c548a550e40a3c75f0191b30"><code>b463f23</code></a>
TRACE logging during apprise init cleaned up (<a
href="https://redirect.github.com/caronc/apprise/issues/1622">#1622</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/1e2fdeb72bd8165ad613b162794778ff1c684e67"><code>1e2fdeb</code></a>
Amazon SNS/SES Improvements (<a
href="https://redirect.github.com/caronc/apprise/issues/1620">#1620</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/4706d0a4599a5072c8ae17375ee81862bcaac460"><code>4706d0a</code></a>
Handle XMPP SASL SCRAM-PLUS / Channel Binding (<a
href="https://redirect.github.com/caronc/apprise/issues/1619">#1619</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/caronc/apprise/compare/v1.10.0...v1.11.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.48.4 to 4.49.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.49.7 - CDP Mode: Patch 112</h2>
<h2>CDP Mode: Patch 112</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a9a76399a3cd114f905a0a99e4abd68d3bab0d4e">Fix
RuntimeWarning: coroutine 'Connection.aclose' was never awaited</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 112 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4367">seleniumbase/SeleniumBase#4367</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.6...v4.49.7">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.6...v4.49.7</a></p>
<h2>4.49.6 - CDP Mode: Patch 111 (and more)</h2>
<h2>CDP Mode: Patch 111 (and more)</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3cbb5772fa133619fa874e27f58f20ad6ad95dc1">Fix
RuntimeWarning: coroutine 'Event.wait' was never awaited</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4363">seleniumbase/SeleniumBase#4363</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e7fc1a854c6dc42b61c88b0afa883f1550983c38">Remove
the selenium-wire integration</a>
--&gt; This resolves <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4362">seleniumbase/SeleniumBase#4362</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ed817adefb810db91b47f62d1b17faa2a3420cce">activate_cdp_mode(url)
should still open the url if already active</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/cf996bf0399b5c41ac70e1e3e84992cdf4d154be">Save
time &amp; memory by only importing sb_install if needed</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c1ab11fc1ddf2ab9077041481d0085310482ed23">Update
the CDP Mode activation sequence</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8274d737affebf0096cb287e09d3a3a3d6b8c915">Optimize
the pytest-html report plugin</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f709444731c7c6285a31aaeaa13a2e439d51be43">Refresh
Python dependencies</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/41666ae760049966f0be96acd6aa5b04c77b8a15">Update
examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 111 (and more) by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4365">seleniumbase/SeleniumBase#4365</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.5...v4.49.6">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.5...v4.49.6</a></p>
<h2>4.49.5 - CDP Mode: Patch 110</h2>
<h2>CDP Mode: Patch 110</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0b8a5ce63821fe0cb238331e21d5706c66964ef0">Update
error-handling for checking if a process is still running</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 110 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4360">seleniumbase/SeleniumBase#4360</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.4...v4.49.5">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.4...v4.49.5</a></p>
<h2>4.49.4 - CDP Mode: Patch 109</h2>
<h2>CDP Mode: Patch 109</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/74ee362dc453c2a4f02a9da6469817ec936cc4bd">Handle
PermissionError in methods that use psutil</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b41d33187342560fb0c0d580a0c76162b4217910">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 109 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4358">seleniumbase/SeleniumBase#4358</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.49.3...v4.49.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.49.3...v4.49.4</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9cd73e6698bf065e966e85457d1896cc6e4475a3"><code>9cd73e6</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4367">#4367</a>
from seleniumbase/cdp-mode-patch-112</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/c2973f391eda5eac4ecbf2a900c88797161cd88c"><code>c2973f3</code></a>
Version 4.49.7</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a9a76399a3cd114f905a0a99e4abd68d3bab0d4e"><code>a9a7639</code></a>
Fix <code>RuntimeWarning: coroutine 'Connection.aclose' was never
awaited</code></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/4732aafc5d24b8ad99f8cc6141b105318e9597e4"><code>4732aaf</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4365">#4365</a>
from seleniumbase/cdp-mode-patch-111</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/583e6cd6b97c17dcc5f9fc52b440727b3216d6e8"><code>583e6cd</code></a>
Version 4.49.6</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9e78a662ab7c5fef9fa80ab4357510848cf913a6"><code>9e78a66</code></a>
Officially support Python 3.15</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/f709444731c7c6285a31aaeaa13a2e439d51be43"><code>f709444</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/1c234e270d233eb8b0709276c470f36a99566d97"><code>1c234e2</code></a>
Refresh mkdocs dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/41666ae760049966f0be96acd6aa5b04c77b8a15"><code>41666ae</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b8686dc65d43a2baf9a5280c2ee1b8ad6ff0a7aa"><code>b8686dc</code></a>
Update the documentation</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.4...v4.49.7">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.3 to 1.39.6
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/ad82d91ce241116737e65e660c5420dd0366f405"><code>ad82d91</code></a>
1.39.6</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/cf60738b8dbbcc89f02d097a2dfa6e91c540bd86"><code>cf60738</code></a>
fix vscode config for formatting markdown files now that we use two
formatter...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/29e303a1b0b5f401f21c28fe3ea7da4b9db09e35"><code>29e303a</code></a>
print stderr from npm commands when build fails</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f133f3d6b9a4ef3cf2d53a929a053875e1effbe4"><code>f133f3d</code></a>
uncomment some test code which started causing a test to fail. no idea
why i ...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/f71e96bfe63f0833f3d169cf0df9208a7734929f"><code>f71e96b</code></a>
remove python 3.9 check from <code>TypeAlias4</code> test because
typeshed has dropped s...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/e4c40b76f5cb70a44825aa65da7fdaa3f32b4f85"><code>e4c40b7</code></a>
fix tests</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/d7c522bc2a8b105d206b5efce0d6dd4e2610b917"><code>d7c522b</code></a>
ruff ignore new <code>benchmarkData</code> files from upstream</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/a7cf33dce12ce64f8fb2fecf039c4422c232784a"><code>a7cf33d</code></a>
fix eslint in vscode</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/14c96beec311ff57bb3ef416ac86f886648b1adb"><code>14c96be</code></a>
fix logic for reporting invalid <code>pythonPlatform</code> detected by
the new eslint v...</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/280802ce1b2bdbaf78a880b94355ebf702241ca9"><code>280802c</code></a>
remove remnants of webpack</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.3...v1.39.6">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.3.13 to 0.4.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.4</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-04.</p>
<h3>  Highlights</h3>
<p>0.4.4 makes <code>prek run</code> easier to watch and easier to
slice.</p>
<p>Hook stream output now shows a small live preview under the running
hook in the
progress UI. Long-running hooks no longer look stuck while they are
producing
logs, and failed hooks are easier to diagnose because recent output is
already
visible before the final result.</p>
<p>The new group selector lets a single config support different
workflows. Tag
hooks with <code>groups</code>, then select or exclude those groups at
run time:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: format
        name: Format Python
        language: system
        entry: ruff format
        groups: [format, ci]
<pre><code>  - id: lint
    name: Lint Python
    language: system
    entry: ruff check
    groups: [lint, ci]
</code></pre>
<p></code></pre></p>
<pre lang="bash"><code>prek run --all-files --group ci
prek run --all-files --no-group format
</code></pre>
<p>This is useful when local development, CI, slow validation, or
project-specific
checks need different hook sets without splitting the config.</p>
<h3>💚 Sponsorship</h3>
<p>If prek saves time for you or your team, please consider sponsoring
the
project on <a href="https://github.com/sponsors/j178">GitHub
Sponsors</a>. It helps keep
new features, performance work, and maintenance moving.</p>
<h3>Enhancements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.4</h2>
<p>Released on 2026-06-04.</p>
<h3>Highlights</h3>
<p>0.4.4 makes <code>prek run</code> easier to watch and easier to
slice.</p>
<p>Hook stream output now shows a small live preview under the running
hook in the
progress UI. Long-running hooks no longer look stuck while they are
producing
logs, and failed hooks are easier to diagnose because recent output is
already
visible before the final result.</p>
<p>The new group selector lets a single config support different
workflows. Tag
hooks with <code>groups</code>, then select or exclude those groups at
run time:</p>
<pre lang="yaml"><code>repos:
  - repo: local
    hooks:
      - id: format
        name: Format Python
        language: system
        entry: ruff format
        groups: [format, ci]
<pre><code>  - id: lint
    name: Lint Python
    language: system
    entry: ruff check
    groups: [lint, ci]
</code></pre>
<p></code></pre></p>
<pre lang="bash"><code>prek run --all-files --group ci
prek run --all-files --no-group format
</code></pre>
<p>This is useful when local development, CI, slow validation, or
project-specific
checks need different hook sets without splitting the config.</p>
<h3>Enhancements</h3>
<ul>
<li>Add hook group filters to <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/pull/2141">#2141</a>)</li>
<li>Delay hook output preview rendering (<a
href="https://redirect.github.com/j178/prek/pull/2140">#2140</a>)</li>
<li>Stream hook output in progress UI (<a
href="https://redirect.github.com/j178/prek/pull/2136">#2136</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Fix intent-to-add stash restore (<a
href="https://redirect.github.com/j178/prek/pull/2143">#2143</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/f44270e63f839011442ac96420cedc6aec3d8dfa"><code>f44270e</code></a>
Bump version 0.4.4 (<a
href="https://redirect.github.com/j178/prek/issues/2148">#2148</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/da457c57b5602b815dceb9ba115ad164f5e1315c"><code>da457c5</code></a>
Document hook stage file input (<a
href="https://redirect.github.com/j178/prek/issues/2147">#2147</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/0fa29294fad36956c5099d8b6cb790d6122ab9ac"><code>0fa2929</code></a>
Add hook group filters to <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/issues/2141">#2141</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/9b0047ffb3c1f255edac769ce56667aad0f935dc"><code>9b0047f</code></a>
Fix intent-to-add stash restore (<a
href="https://redirect.github.com/j178/prek/issues/2143">#2143</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/00b2520f41c5722db0b3be684be245320c4dec37"><code>00b2520</code></a>
Delay hook output preview rendering (<a
href="https://redirect.github.com/j178/prek/issues/2140">#2140</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/a54fdf0935e18d3e35f848cb40c18ae96220288b"><code>a54fdf0</code></a>
Simplify hook output preview rendering (<a
href="https://redirect.github.com/j178/prek/issues/2139">#2139</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ab7165d5cd06be239766ab25426d4459d51ec5e4"><code>ab7165d</code></a>
Stream hook output in progress UI (<a
href="https://redirect.github.com/j178/prek/issues/2136">#2136</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f60958443fa8a9928924aa9cfcbb6d3412d9ef71"><code>f609584</code></a>
Remove unpinned dotnet test (<a
href="https://redirect.github.com/j178/prek/issues/2137">#2137</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ce0d8b34de8800f713de19a108dfcf70a95b2a62"><code>ce0d8b3</code></a>
Update Rust to 1.96 (<a
href="https://redirect.github.com/j178/prek/issues/2134">#2134</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1815fc50cca664fa48c96494ec7d4aa7df72a135"><code>1815fc5</code></a>
Update PyPI Downloads badge to dynamic JSON</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.3.13...v0.4.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.12 to 0.15.16
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.16</h2>
<h2>Release Notes</h2>
<p>Released on 2026-06-04.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-async</code>] Implement
<code>yield-in-context-manager-in-async-generator</code>
(<code>ASYNC119</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24644">#24644</a>)</li>
<li>[<code>pylint</code>] Narrow diagnostic range and exclude cases
without exception handlers (<code>PLW0717</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25440">#25440</a>)</li>
<li>[<code>ruff</code>] Treat <code>yield</code> before
<code>break</code> from a terminal loop as terminal
(<code>RUF075</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25447">#25447</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>eradicate</code>] Avoid flagging <code>ruff:ignore</code>
comments as code (<code>ERA001</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25537">#25537</a>)</li>
<li>[<code>eradicate</code>] Fix <code>ERA001</code>/<code>RUF100</code>
conflict when <code>noqa</code> is on commented-out code (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25414">#25414</a>)</li>
<li>[<code>pyflakes</code>] Avoid removing the <code>format</code> call
when it would change behavior (<code>F523</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25320">#25320</a>)</li>
<li>[<code>pylint</code>] Avoid syntax errors in invalid character
replacements in f-strings before Python 3.12 (<code>PLE2510</code>,
<code>PLE2512</code>, <code>PLE2513</code>, <code>PLE2514</code>,
<code>PLE2515</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25544">#25544</a>)</li>
<li>[<code>pyupgrade</code>] Avoid converting <code>format</code> calls
with more kinds of side effects (<code>UP032</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25484">#25484</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Avoid fixes for ambiguous
<code>argnames</code> and <code>argvalues</code> combinations
(<code>PT006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24776">#24776</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Drop excess capacity from statement suites during parsing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25368">#25368</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>pydocstyle</code>] Improve discoverability of rules enabled
for each convention (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24973">#24973</a>)</li>
<li>[<code>ruff</code>] Restore example code for Python versions before
3.15 (<code>RUF017</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25439">#25439</a>)</li>
<li>Fix typo <code>bin/active</code> → <code>bin/activate</code> in
tutorial (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25473">#25473</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Shrink additional parser AST collections (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25465">#25465</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Redslayer112"><code>@​Redslayer112</code></a></li>
<li><a
href="https://github.com/koriyoshi2041"><code>@​koriyoshi2041</code></a></li>
<li><a
href="https://github.com/George-Ogden"><code>@​George-Ogden</code></a></li>
<li><a
href="https://github.com/TejasAmle"><code>@​TejasAmle</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/loganrosen"><code>@​loganrosen</code></a></li>
<li><a
href="https://github.com/RafaelJohn9"><code>@​RafaelJohn9</code></a></li>
<li><a
href="https://github.com/adityasingh2400"><code>@​adityasingh2400</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.16</h2>
<p>Released on 2026-06-04.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-async</code>] Implement
<code>yield-in-context-manager-in-async-generator</code>
(<code>ASYNC119</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24644">#24644</a>)</li>
<li>[<code>pylint</code>] Narrow diagnostic range and exclude cases
without exception handlers (<code>PLW0717</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25440">#25440</a>)</li>
<li>[<code>ruff</code>] Treat <code>yield</code> before
<code>break</code> from a terminal loop as terminal
(<code>RUF075</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25447">#25447</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>eradicate</code>] Avoid flagging <code>ruff:ignore</code>
comments as code (<code>ERA001</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25537">#25537</a>)</li>
<li>[<code>eradicate</code>] Fix <code>ERA001</code>/<code>RUF100</code>
conflict when <code>noqa</code> is on commented-out code (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25414">#25414</a>)</li>
<li>[<code>pyflakes</code>] Avoid removing the <code>format</code> call
when it would change behavior (<code>F523</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25320">#25320</a>)</li>
<li>[<code>pylint</code>] Avoid syntax errors in invalid character
replacements in f-strings before Python 3.12 (<code>PLE2510</code>,
<code>PLE2512</code>, <code>PLE2513</code>, <code>PLE2514</code>,
<code>PLE2515</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25544">#25544</a>)</li>
<li>[<code>pyupgrade</code>] Avoid converting <code>format</code> calls
with more kinds of side effects (<code>UP032</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25484">#25484</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>flake8-pytest-style</code>] Avoid fixes for ambiguous
<code>argnames</code> and <code>argvalues</code> combinations
(<code>PT006</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24776">#24776</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Drop excess capacity from statement suites during parsing (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25368">#25368</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>pydocstyle</code>] Improve discoverability of rules enabled
for each convention (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24973">#24973</a>)</li>
<li>[<code>ruff</code>] Restore example code for Python versions before
3.15 (<code>RUF017</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25439">#25439</a>)</li>
<li>Fix typo <code>bin/active</code> → <code>bin/activate</code> in
tutorial (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25473">#25473</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Shrink additional parser AST collections (<a
href="https://redirect.github.com/astral-sh/ruff/pull/25465">#25465</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/Redslayer112"><code>@​Redslayer112</code></a></li>
<li><a
href="https://github.com/koriyoshi2041"><code>@​koriyoshi2041</code></a></li>
<li><a
href="https://github.com/George-Ogden"><code>@​George-Ogden</code></a></li>
<li><a
href="https://github.com/TejasAmle"><code>@​TejasAmle</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/loganrosen"><code>@​loganrosen</code></a></li>
<li><a
href="https://github.com/RafaelJohn9"><code>@​RafaelJohn9</code></a></li>
<li><a
href="https://github.com/adityasingh2400"><code>@​adityasingh2400</code></a></li>
</ul>
<h2>0.15.15</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/6c498ab5394edc5622d7f348e12956bf86203716"><code>6c498ab</code></a>
Bump 0.15.16 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25635">#25635</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e51e132831c4e1c4a5ac00fca4c9256354ab99bf"><code>e51e132</code></a>
[<code>flake8-async</code>] Implement
<code>yield-in-context-manager-in-async-generator</code> (`AS...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/7c6dcd9f2611999c449143d241c582dedf287964"><code>7c6dcd9</code></a>
[ty] Add caching for pattern match narrowing (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25613">#25613</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/27058fc071b542bf06395ba89cabed061d313ca6"><code>27058fc</code></a>
[ty] Compact retained definition and expression identities (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25606">#25606</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/bf80d05f007c939799f530c9e775ed9449f5b2eb"><code>bf80d05</code></a>
Fix CODEOWNERS syntax (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25622">#25622</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/10ccd511e94a81d1e836b174f1c553a73ff3f1b3"><code>10ccd51</code></a>
Shrink additional parser AST collections (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25465">#25465</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/0d7135f4d23e7f4d8404daed16b9ef11d14f3fb9"><code>0d7135f</code></a>
[ty] Upgrade Salsa (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25545">#25545</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/49493a3cea83a08fa9aa143695017c816a540f1d"><code>49493a3</code></a>
[ty] Show type alias value on hover (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25381">#25381</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/85207d3b7657a84252f266766cb0d56034dc21cc"><code>85207d3</code></a>
[ty] sys.implementation.version is not sys.version_info (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25608">#25608</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/a8a0614348c1fcf47fc9b666eff61a103914d520"><code>a8a0614</code></a>
[ty] Avoid retaining duplicate function signatures (<a
href="https://redirect.github.com/astral-sh/ruff/issues/25609">#25609</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.12...0.15.16">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-09 20:53:20 -04:00
dependabot[bot]andCaliBrain 8c86cdc1dd Bump the npm-deps group across 1 directory with 14 updates (#1043)
Bumps the npm-deps group with 13 updates in the /src/frontend directory:

| Package | From | To |
| --- | --- | --- |
|
[@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)
| `4.2.4` | `4.3.0` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) |
`19.2.6` | `19.2.7` |
|
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)
| `19.2.14` | `19.2.16` |
|
[react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom)
| `19.2.6` | `19.2.7` |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.15.0` | `7.16.0` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `25.6.2` | `25.9.1` |
|
[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react)
| `6.0.1` | `6.0.2` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.12.1` | `6.15.0` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.48.0` | `0.53.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.63.0` | `1.68.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.22.1`
| `0.23.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.0.11` | `8.0.16` |
|
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
| `4.1.5` | `4.1.8` |


Updates `@tailwindcss/vite` from 4.2.4 to 4.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">@​tailwindcss/vite's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<h3>Added</h3>
<ul>
<li>Add <code>@container-size</code> utility (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/18901">#18901</a>)</li>
<li>Add <code>scrollbar-{auto,thin,none}</code> utilities for
<code>scrollbar-width</code>, and <code>scrollbar-thumb-*</code> /
<code>scrollbar-track-*</code> color utilities for
<code>scrollbar-color</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19981">#19981</a>,
<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20019">#20019</a>)</li>
<li>Add <code>scrollbar-gutter-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20018">#20018</a>)</li>
<li>Add <code>zoom-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20020">#20020</a>)</li>
<li>Add <code>tab-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20022">#20022</a>)</li>
<li>Allow using <code>@variant</code> with stacked variants (e.g.
<code>@variant hover:focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Allow using <code>@variant</code> with compound variants (e.g.
<code>@variant hover, focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Support <code>--default(…)</code> in <code>--value(…)</code> and
<code>--modifier(…)</code> for functional <code>@utility</code>
definitions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19989">#19989</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Ensure <code>@plugin</code> resolves package JavaScript entries
instead of browser CSS entries when using <code>@tailwindcss/vite</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19949">#19949</a>)</li>
<li>Fix relative <code>@import</code> and <code>@plugin</code> paths
resolving from the wrong directory when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19965">#19965</a>)</li>
<li>Ensure CSS files containing <code>@variant</code> are processed by
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19966">#19966</a>)</li>
<li>Resolve imports relative to <code>base</code> when
<code>result.opts.from</code> is not provided when using
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19980">#19980</a>)</li>
<li>Canonicalization: preserve significant <code>_</code> whitespace in
arbitrary values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19986">#19986</a>)</li>
<li>Canonicalization: add parentheses when removing whitespace from
arbitrary values would hurt readability (e.g.
<code>w-[calc(100%---spacing(60))]</code> →
<code>w-[calc(100%-(--spacing(60)))]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19986">#19986</a>)</li>
<li>Canonicalization: preserve the original unit in arbitrary values
instead of normalizing to base units (e.g. <code>-mt-[20in]</code> →
<code>mt-[-20in]</code>, not <code>mt-[-1920px]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19988">#19988</a>)</li>
<li>Canonicalization: migrate arbitrary <code>:has()</code> variants
from <code>[&amp;:has(…)]</code> to <code>has-[…]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19991">#19991</a>)</li>
<li>Upgrade: don’t migrate inline <code>style</code> attributes (e.g.
<code>style=&quot;flex-grow: 1&quot;</code> →
<code>style=&quot;flex-grow: 1&quot;</code>, not <code>style=&quot;grow:
1&quot;</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19918">#19918</a>)</li>
<li>Allow multiple <code>@utility</code> definitions with the same name
but different value types (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19777">#19777</a>)</li>
<li>Export missing <code>PluginWithConfig</code> type from
<code>tailwindcss/plugin</code> to fix errors when inferring plugin
config types (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19707">#19707</a>)</li>
<li>Ensure <code>start</code> and <code>end</code> legacy utilities
without values do not generate CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20003">#20003</a>)</li>
<li>Ensure <code>--value(…)</code> is required in functional
<code>@utility</code> definitions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20005">#20005</a>)</li>
<li>Canonicalization: preserve required whitespace around operators in
negated arbitrary values (e.g. <code>-left-[(var(--a)+var(--b))]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20011">#20011</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">@​tailwindcss/vite's
changelog</a>.</em></p>
<blockquote>
<h2>[4.3.0] - 2026-05-08</h2>
<h3>Added</h3>
<ul>
<li>Add <code>@container-size</code> utility (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/18901">#18901</a>)</li>
<li>Add <code>scrollbar-{auto,thin,none}</code> utilities for
<code>scrollbar-width</code>, and <code>scrollbar-thumb-*</code> /
<code>scrollbar-track-*</code> color utilities for
<code>scrollbar-color</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19981">#19981</a>,
<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20019">#20019</a>)</li>
<li>Add <code>scrollbar-gutter-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20018">#20018</a>)</li>
<li>Add <code>zoom-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20020">#20020</a>)</li>
<li>Add <code>tab-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20022">#20022</a>)</li>
<li>Allow using <code>@variant</code> with stacked variants (e.g.
<code>@variant hover:focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Allow using <code>@variant</code> with compound variants (e.g.
<code>@variant hover, focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Support <code>--default(…)</code> in <code>--value(…)</code> and
<code>--modifier(…)</code> for functional <code>@utility</code>
definitions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19989">#19989</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Ensure <code>@plugin</code> resolves package JavaScript entries
instead of browser CSS entries when using <code>@tailwindcss/vite</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19949">#19949</a>)</li>
<li>Fix relative <code>@import</code> and <code>@plugin</code> paths
resolving from the wrong directory when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19965">#19965</a>)</li>
<li>Ensure CSS files containing <code>@variant</code> are processed by
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19966">#19966</a>)</li>
<li>Resolve imports relative to <code>base</code> when
<code>result.opts.from</code> is not provided when using
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19980">#19980</a>)</li>
<li>Canonicalization: preserve significant <code>_</code> whitespace in
arbitrary values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19986">#19986</a>)</li>
<li>Canonicalization: add parentheses when removing whitespace from
arbitrary values would hurt readability (e.g.
<code>w-[calc(100%---spacing(60))]</code> →
<code>w-[calc(100%-(--spacing(60)))]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19986">#19986</a>)</li>
<li>Canonicalization: preserve the original unit in arbitrary values
instead of normalizing to base units (e.g. <code>-mt-[20in]</code> →
<code>mt-[-20in]</code>, not <code>mt-[-1920px]</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19988">#19988</a>)</li>
<li>Canonicalization: migrate arbitrary <code>:has()</code> variants
from <code>[&amp;:has(…)]</code> to <code>has-[…]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19991">#19991</a>)</li>
<li>Upgrade: don’t migrate inline <code>style</code> attributes (e.g.
<code>style=&quot;flex-grow: 1&quot;</code> →
<code>style=&quot;flex-grow: 1&quot;</code>, not <code>style=&quot;grow:
1&quot;</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19918">#19918</a>)</li>
<li>Allow multiple <code>@utility</code> definitions with the same name
but different value types (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19777">#19777</a>)</li>
<li>Export missing <code>PluginWithConfig</code> type from
<code>tailwindcss/plugin</code> to fix errors when inferring plugin
config types (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19707">#19707</a>)</li>
<li>Ensure <code>start</code> and <code>end</code> legacy utilities
without values do not generate CSS (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20003">#20003</a>)</li>
<li>Ensure <code>--value(…)</code> is required in functional
<code>@utility</code> definitions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20005">#20005</a>)</li>
<li>Canonicalization: preserve required whitespace around operators in
negated arbitrary values (e.g. <code>-left-[(var(--a)+var(--b))]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20011">#20011</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/588bd7371f4cae96426e1387819b7fd1d99765f9"><code>588bd73</code></a>
4.3.0 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/20023">#20023</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/d194d4c3e656313421f1cfa1954db8f58eec0fcd"><code>d194d4c</code></a>
docs: fix various typos in comments and documentation (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19878">#19878</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/db27049caaae08978995f25b61f8336f543a4640"><code>db27049</code></a>
fix(<code>@​tailwindcss/vite</code>): include <a
href="https://github.com/variant"><code>@​variant</code></a> in feature
detection (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19966">#19966</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/5a799900d4b43ca4902398a38c6f0a5b37a98ed9"><code>5a79990</code></a>
Always resolve relative files, relative to the current .css file (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19965">#19965</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/f3fdda2a5cb9de50c897c79003aa58182cd9269b"><code>f3fdda2</code></a>
fix(vite): avoid resolving JS plugins to browser CSS entries (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19949">#19949</a>)</li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.3.0/packages/@tailwindcss-vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `react` from 19.2.6 to 19.2.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react's
releases</a>.</em></p>
<blockquote>
<h2>19.2.7 (June 1st, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Fixed missing <code>FormData</code> entries in Server Actions which
regressed in 19.2.6
(<a
href="https://redirect.github.com/facebook/react/pull/36566">#36566</a>
by <a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/6117d7cca4906492c51fe6a03381e35adfd86e7d"><code>6117d7c</code></a>
Version 19.2.7 (<a
href="https://github.com/facebook/react/tree/HEAD/packages/react/issues/36591">#36591</a>)</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.7/packages/react">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for react since your current version.</p>
</details>
<br />

Updates `@types/react` from 19.2.14 to 19.2.16
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-dom` from 19.2.6 to 19.2.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react-dom's
releases</a>.</em></p>
<blockquote>
<h2>19.2.7 (June 1st, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Fixed missing <code>FormData</code> entries in Server Actions which
regressed in 19.2.6
(<a
href="https://redirect.github.com/facebook/react/pull/36566">#36566</a>
by <a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/6117d7cca4906492c51fe6a03381e35adfd86e7d"><code>6117d7c</code></a>
Version 19.2.7 (<a
href="https://github.com/facebook/react/tree/HEAD/packages/react-dom/issues/36591">#36591</a>)</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.7/packages/react-dom">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for react-dom since your current version.</p>
</details>
<br />

Updates `react-router-dom` from 7.15.0 to 7.16.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.16.0</h2>
<h3>Patch Changes</h3>
<ul>
<li>Remove stale/invalid <code>unpkg</code> field from
<code>package.json</code>. This was removed from other packages with the
release of v7 but missed in the <code>react-router-dom</code> re-export
package (<a
href="https://redirect.github.com/remix-run/react-router/pull/15075">#15075</a>)</li>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.16.0"><code>react-router@7.16.0</code></a></li>
</ul>
</li>
</ul>
<h2>v7.15.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.15.1"><code>react-router@7.15.1</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/8984d23f86ca7ae5655711744b77816090bda4e6"><code>8984d23</code></a>
Release v7.16.0 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15105">#15105</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/3ed77afcde0ad9aea79f1afe5f05a700b201f289"><code>3ed77af</code></a>
chore: format</li>
<li><a
href="https://github.com/remix-run/react-router/commit/e96962bc6159a2290632849b55872a3878753342"><code>e96962b</code></a>
fix: remove stale unpkg field from react-router-dom (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15075">#15075</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/587d08fca6ca61e00f44c1eda95bf6e6a9ab76ef"><code>587d08f</code></a>
Release v7.15.1 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15038">#15038</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.16.0/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 25.6.2 to 25.9.1
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/react` from 19.2.14 to 19.2.16
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `@vitejs/plugin-react` from 6.0.1 to 6.0.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/releases">@​vitejs/plugin-react's
releases</a>.</em></p>
<blockquote>
<h2>plugin-react@6.0.2</h2>
<h3>Allow all options in reactCompilerPreset (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1189">#1189</a>)</h3>
<p>This is a type only change. Only <code>compilationMode</code> and
<code>target</code> options were available for
<code>reactCompilerPreset</code>.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md">@​vitejs/plugin-react's
changelog</a>.</em></p>
<blockquote>
<h2>6.0.2 (2026-05-14)</h2>
<h3>Allow all options in reactCompilerPreset (<a
href="https://redirect.github.com/vitejs/vite-plugin-react/pull/1189">#1189</a>)</h3>
<p>This is a type only change. Only <code>compilationMode</code> and
<code>target</code> options were available for
<code>reactCompilerPreset</code>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/6535b55e956b425e6650ffc2cc98fd23cca1d231"><code>6535b55</code></a>
release: plugin-react@6.0.2</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/bf0e43b756e3be81f8572d59727c218311f431ef"><code>bf0e43b</code></a>
feat(react): whitelist debugging-options (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1189">#1189</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/3bd1f08ae0b82ee0e96feb2ff265e61c6fe74b54"><code>3bd1f08</code></a>
feat: use carets for rolldown versions (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1216">#1216</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/2b8df67323265d1ff5ddf47b2db9ab0b9de5c688"><code>2b8df67</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1218">#1218</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/8fa9619e1b1f51b079f4c1df6bcf076dcafc5aed"><code>8fa9619</code></a>
fix(deps): update react 19.2.6 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1211">#1211</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/a4296ad2995a8d493528b8d5450a1209de2943cb"><code>a4296ad</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1209">#1209</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/323ccd72576be636b50baa7d9ce816cc94d5991e"><code>323ccd7</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1196">#1196</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/a7506e105df00cdadc58c0aecc4512d8cfdd9765"><code>a7506e1</code></a>
chore(deps): update vite 8.0.10 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1198">#1198</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/02cff2a0cf5c7e9792b1612baa380228f5e4d3c1"><code>02cff2a</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1184">#1184</a>)</li>
<li><a
href="https://github.com/vitejs/vite-plugin-react/commit/4b9c890cdb21078ac45a86873b24f7e8613b8526"><code>4b9c890</code></a>
fix(deps): update react 19.2.5 (<a
href="https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react/issues/1181">#1181</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.2/packages/plugin-react">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.12.1 to 6.15.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.15.0</h2>
<ul>
<li>Report exported type used only in inferred-return function body
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1765">#1765</a>)
(2413408753f7abc7a9dfdba520990afd18c53ee0)</li>
<li>Work that EXPORTS.md again
(7e13451fab7ad85362fb63a4715ea450690aedef)</li>
<li>Update npmx ecosystem snapshot
(dfc401145a880f156c66eb83ea1622a99540304a)</li>
<li>Link <code>dependencies</code> key with notes (closes <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1764">#1764</a>)
(e3e66cea9e946558940bf8705129efea3f23b3ba)</li>
<li>Resolve tsconfig paths when loading plugin configs (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1762">#1762</a>)
(0177c7466559e2ae99b5e1cd1e3a8043ca494edc) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Avoid caching failed plugin config loads (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1768">#1768</a>)
(5e201cde9b1ba2568ead2ae790ab888c966828ae) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Resolve extensionless .sass imports in SCSS compiler (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1770">#1770</a>)
(30c22835383b2355787cc2a871b22de80ff75544) - thanks <a
href="https://github.com/sebacardello"><code>@​sebacardello</code></a>!</li>
<li>fix(vite): detect inline module script entry points in index.html
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1772">#1772</a>)
(51f4eddc9e1b2fed1ba25e81fc596e9fb514ce01) - thanks <a
href="https://github.com/lucas-spin"><code>@​lucas-spin</code></a>!</li>
<li>Harden vite inline module script import detection
(b8abcfd2f4f5486aea08a934514bc55de86be030)</li>
<li>Use RecordableHistogram for timerified function stats
(d575c6905704af1b0b4620edd874fc09bc86ed28)</li>
<li>Add orval plugin (resolves <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1751">#1751</a>)
(4c82aa82c2a02fbda27a316389f210d11621f8cb)</li>
<li>Add treatTagHintsAsErrors and --no-tag-hints (resolves <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1767">#1767</a>)
(4b6a573e0c1e0daf65c76c32f7336ea71db6bb64)</li>
<li>Add nano-spawn plugin (resolves <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1769">#1769</a>)
(b2cad06dfd9958485537c5545c6c497fc8823ac3)</li>
<li>Simplify glob cache validation and ignore-list assembly
(df1a9603a5ea8ed7bad9588bf13672cedf37c90e)</li>
<li>Dedupe ignore-pattern collection and dependency fixing
(d49b626ad6736d7123d44568ef8c42a3e1d28aa3)</li>
<li>Simplify installed-binaries collection in manifest metadata
(55143941eebbc8dac12c79b77c1f65a8b61dfbef)</li>
<li>Flatten control flow in ConfigurationChief
(010d5709b0f9a3adc5ebe6e7169b9f5c4f29abc5)</li>
<li>Inline trivial installed-binaries and types-included accessors
(b5afb9f29e3474eee4bf276c1de83cb0682a5663)</li>
<li>Format (eb4b178d5d90a719cdc576d644766f8f95a47876)</li>
<li>Replace <code>@​wdio/types</code> dev dep with inline types
(a3747d61ee0e594854e5da0ca6cb7597e0096b99)</li>
<li>Bump dependencies (822ab3905cb7b5a216404231607a7820105930a2)</li>
<li>Work AGENTS.md, etcetera
(361bd4803934a01e01b08170565f8374e4e49eb2)</li>
<li>Remove rootDirs workaround resolved by oxc-resolver 11.20.0
(e190a9fec22db41975cf9568a31970a05c86e66b)</li>
<li>Add nuxt no-root-tsconfig fixture guarding alias resolution
(e3e5bc94d5f7b6ffdbc89b18d7c8d5acbb5a9008)</li>
<li>Allow extra args for release-it
(f9c59952fa2c8c4c13bd42edc0935610900d1980)</li>
<li>Add <a href="https://github.com/vercel"><code>@​vercel</code></a> as
platinum sponsor (c4c06a9149c986680f0d1aa74b57a46ff1f88601)</li>
<li>Overhaul &amp; improve --trace functionailty
(60df0b05f364c8d841c0f784a06bab2a3215a32f)</li>
<li>Re-gen plugins.md (0f9d044d312053154498a562e3a9422a4f44afe6)</li>
</ul>
<h2>Release 6.14.2</h2>
<ul>
<li>Fix vscode-knip build: pin native oxc bindings to bundled JS version
(1b45a4103312c9c059560ae2e1eac25d86b4e2ac)</li>
<li>Release vscode-knip@2.1.5
(328892eb04e65b4702e1ef2303db3156b8f2e1a3)</li>
<li>Fix Astro plugin to support both possible middleware entry points
(<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1749">#1749</a>)
(33e0cc1a530a8cf5b6b05c8b3a3ca55f8fce8a75) - thanks <a
href="https://github.com/schmalz-dmi"><code>@​schmalz-dmi</code></a>!</li>
<li>Fix LICENSE link (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1760">#1760</a>)
(829620f9077ddea086a610c279c7c1250dd66e11) - thanks <a
href="https://github.com/vortispy"><code>@​vortispy</code></a>!</li>
<li>Fix GraphQL Codegen script config dependencies (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1756">#1756</a>)
(e841c6355e7eff240e74010bfd2be8bbb22ff2b6) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Set pnpm config via env vars, disable verify-deps in ecosystem tests
(53c12248cc3e79fd79f3efde691d463fc795c40f)</li>
<li>Update slonik ecosystem snapshot
(f18410b34c8554364a9f003660bebae5e826de57)</li>
<li>Fix Serverless TypeScript plugin dependencies (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1757">#1757</a>)
(ebde7f8f3e3004db7f51fb5d60a0bdc2452116ef) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Fix extended tsconfig type dependency attribution (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1758">#1758</a>)
(f600b09e562317a37844ed8cdf1b9b46e06c9405) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Fix Bun binary dependency tracking (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1759">#1759</a>)
(1b289239f35ff2912195b7e39a96c667c54c1fc5) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Detect Babel plugins/presets in Vite plugin options (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1761">#1761</a>)
(2753d6910743a12a207fca81cb8325c00803963a)</li>
</ul>
<h2>Release 6.14.1</h2>
<ul>
<li>Detect dynamic imports in Svelte compiler (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1747">#1747</a>)
(e1c1b1705f96ed7d6ac537a7969cbd07d238246a) - thanks <a
href="https://github.com/jinhyuk9714"><code>@​jinhyuk9714</code></a>!</li>
<li>Detect dynamic import attributes; share import matcher with
Astro-MDX (9dae64166bbc45be1abeb8d741127d109d48d351)</li>
<li>Work the docs (close <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1746">#1746</a>)
(919cba2f11d1979b854c7abaaca8992ee8b08e23)</li>
</ul>
<h2>Release 6.14.0</h2>
<ul>
<li>Resolve imports satisfied via transitive peerDeps (d654ec74d)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/3f3769e37b75e3d35e3713e8435735adc00df52b"><code>3f3769e</code></a>
Release knip@6.15.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/60df0b05f364c8d841c0f784a06bab2a3215a32f"><code>60df0b0</code></a>
Overhaul &amp; improve --trace functionailty</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e3e5bc94d5f7b6ffdbc89b18d7c8d5acbb5a9008"><code>e3e5bc9</code></a>
Add nuxt no-root-tsconfig fixture guarding alias resolution</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/e190a9fec22db41975cf9568a31970a05c86e66b"><code>e190a9f</code></a>
Remove rootDirs workaround resolved by oxc-resolver 11.20.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/822ab3905cb7b5a216404231607a7820105930a2"><code>822ab39</code></a>
Bump dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/a3747d61ee0e594854e5da0ca6cb7597e0096b99"><code>a3747d6</code></a>
Replace <code>@​wdio/types</code> dev dep with inline types</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/eb4b178d5d90a719cdc576d644766f8f95a47876"><code>eb4b178</code></a>
Format</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/b5afb9f29e3474eee4bf276c1de83cb0682a5663"><code>b5afb9f</code></a>
Inline trivial installed-binaries and types-included accessors</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/010d5709b0f9a3adc5ebe6e7169b9f5c4f29abc5"><code>010d570</code></a>
Flatten control flow in ConfigurationChief</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/55143941eebbc8dac12c79b77c1f65a8b61dfbef"><code>5514394</code></a>
Simplify installed-binaries collection in manifest metadata</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.15.0/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.48.0 to 0.53.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/964a7580840f394d67c149ea083e35a1e74c128f"><code>964a758</code></a>
release(apps): oxlint v1.68.0 &amp;&amp; oxfmt v0.53.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22883">#22883</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/68b455d84f0b18bd6646cfe4f9babb12ec4fc448"><code>68b455d</code></a>
release(apps): oxlint v1.67.0 &amp;&amp; oxfmt v0.52.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22735">#22735</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/16b8058cd6fd55472cb3a225852ca22db24bb461"><code>16b8058</code></a>
feat(oxfmt): Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22454">#22454</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/557020642e27b948e46f73754b82bee452a82f32"><code>5570206</code></a>
release(apps): oxlint v1.66.0 &amp;&amp; oxfmt v0.51.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22528">#22528</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/25e5cbc76f887cf5c0c2bdfbef8d4a74fd1ce87d"><code>25e5cbc</code></a>
release(apps): oxlint v1.65.0 &amp;&amp; oxfmt v0.50.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22458">#22458</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/43b997847b76bfbc35e83738296330a9a33de4e4"><code>43b9978</code></a>
fix(formatter/sort_imports): Treat subpath imports as internal (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22440">#22440</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d652a556196178515a3c1ea6d25a832c74961d02"><code>d652a55</code></a>
release(apps): oxlint v1.64.0 &amp;&amp; oxfmt v0.49.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22318">#22318</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/6e8e8185c0a3d653bb90dff051ec7d4558793752"><code>6e8e818</code></a>
feat(oxfmt): Experimental .svelte support (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21700">#21700</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/330fe31f826b7d4ae11ae49ba50e2b2ab2bdc6f1"><code>330fe31</code></a>
refactor(config): Update doc comment for <code>GlobSet</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22197">#22197</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/fb3067ca2bafbbf7d75b058788202dc16d994f3e"><code>fb3067c</code></a>
refactor(oxfmt): use shared GlobSet for overrides (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22147">#22147</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.53.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.63.0 to 1.68.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.68.0] - 2026-06-01</h2>
<h3>🚀 Features</h3>
<ul>
<li>e4b1f46 linter/typescript: Implement
<code>method-signature-style</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22679">#22679</a>)
(Mikhail Baev)</li>
<li>bc462ca linter/vue: Implement no-reserved-component-names rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22741">#22741</a>)
(bab)</li>
<li>ef9e751 linter/vue: Implement component-definition-name-casing rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22818">#22818</a>)
(bab)</li>
<li>d67f51a linter/vue: Implement require-prop-type-constructor rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22708">#22708</a>)
(bab)</li>
<li>8422e8b linter/jsdoc: Implement
<code>require-yields-description</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22805">#22805</a>)
(Mikhail Baev)</li>
<li>fe93f97 linter/eslint: Implement
<code>prefer-named-capture-group</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22759">#22759</a>)
(Sebastian Poxhofer)</li>
</ul>
<h2>[1.67.0] - 2026-05-26</h2>
<h3>🚀 Features</h3>
<ul>
<li>b84941e linter/vue: Implement no-expose-after-await rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22675">#22675</a>)
(bab)</li>
<li>98b98c1 linter/vue: Implement no-computed-properties-in-data rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22674">#22674</a>)
(bab)</li>
<li>2d4c919 oxlint: Support <code>vite-plus/resolveConfig</code> for
vite.config.ts (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22456">#22456</a>)
(leaysgur)</li>
<li>2a60012 linter/vue: Implement require-render-return rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22613">#22613</a>)
(bab)</li>
<li>9f227fd linter/vue: Implement no-deprecated-props-default-this rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21892">#21892</a>)
(bab)</li>
<li>87f065e linter/vue: Implement return-in-emits-validator rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21935">#21935</a>)
(bab)</li>
<li>ea0380c linter/unicorn: Implement <code>import-style</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22173">#22173</a>)
(Hao Chen)</li>
<li>dde40fe linter/vue: Implement no-watch-after-await rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22006">#22006</a>)
(bab)</li>
<li>a735eb0 linter/vue: Implement valid-next-tick rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22531">#22531</a>)
(bab)</li>
<li>6dc615d linter/vue: Implement no-shared-component-data rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21842">#21842</a>)
(bab)</li>
<li>a656418 linter/vue: Implement valid-define-options rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22107">#22107</a>)
(bab)</li>
<li>bb6f1b2 linter/vue: Implement require-slots-as-functions rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22244">#22244</a>)
(bab)</li>
<li>5fa4774 linter/n: Implement <code>callback-return</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22470">#22470</a>)
(Mikhail Baev)</li>
</ul>
<h2>[1.66.0] - 2026-05-18</h2>
<h3>🚀 Features</h3>
<ul>
<li>0440b0f linter/eslint: Implement <code>id-match</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22379">#22379</a>)
(Vladislav Sayapin)</li>
<li>65bf119 linter: Implement react no-object-type-as-default-prop (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22481">#22481</a>)
(uhyo)</li>
<li>2a6ddce linter/eslint: Implement <code>no-implied-eval</code> rule
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22391">#22391</a>)
(Vladislav Sayapin)</li>
<li>625758a linter/vitest: Implement padding-around-after-all-blocks
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21788">#21788</a>)
(kapobajza)</li>
<li>37680b0 linter: Implement react no-unstable-nested-components (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22248">#22248</a>)
(Jovi De Croock)</li>
<li>d8d9c74 linter: Implement import/newline-after-import rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/19142">#19142</a>)
(Ryuya Yanagi)</li>
</ul>
<h2>[1.65.0] - 2026-05-15</h2>
<h3>🚀 Features</h3>
<ul>
<li>5478fb5 linter/jsdoc: Implement
<code>require-throws-description</code> rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22386">#22386</a>)
(Mikhail Baev)</li>
<li>c73225e linter/eslint: Implement <code>prefer-arrow-callback</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22312">#22312</a>)
(박천(Cheon Park))</li>
<li>de82b59 linter: Add support for
<code>eslint-plugin-jsx-a11y-x</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22356">#22356</a>)
(mehm8128)</li>
<li>f44b6c8 linter: Fill schemas <code>DummyRuleMap</code> with built-in
rules (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22288">#22288</a>)
(Sysix)</li>
</ul>
<h2>[1.64.0] - 2026-05-11</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/964a7580840f394d67c149ea083e35a1e74c128f"><code>964a758</code></a>
release(apps): oxlint v1.68.0 &amp;&amp; oxfmt v0.53.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22883">#22883</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/3f05c5e1267c25daa1c90babd84427f59acf96be"><code>3f05c5e</code></a>
feat(linter): expose <code>override::exclude_files</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22884">#22884</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/e4b1f46bec95da661af72f513e769d729ff605c6"><code>e4b1f46</code></a>
feat(linter/typescript): implement <code>method-signature-style</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22679">#22679</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/bc462ca5a778c246d6185d9b8d2cbdf3919ed527"><code>bc462ca</code></a>
feat(linter/vue): implement no-reserved-component-names rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22741">#22741</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/ef9e75170dca39091e4aa8360f7d59dc5aa206eb"><code>ef9e751</code></a>
feat(linter/vue): implement component-definition-name-casing rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22818">#22818</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d67f51aba16939ce33b21c7504e177a9ff1c6887"><code>d67f51a</code></a>
feat(linter/vue): implement require-prop-type-constructor rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22708">#22708</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/8422e8bc44db47033ce516f9375867624e265823"><code>8422e8b</code></a>
feat(linter/jsdoc): implement <code>require-yields-description</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22805">#22805</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/fe93f9718ac09bab79286eb6dbc90ad14f8270bd"><code>fe93f97</code></a>
feat(linter/eslint): implement <code>prefer-named-capture-group</code>
rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22759">#22759</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/68b455d84f0b18bd6646cfe4f9babb12ec4fc448"><code>68b455d</code></a>
release(apps): oxlint v1.67.0 &amp;&amp; oxfmt v0.52.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22735">#22735</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/b84941e69e2e630e998fe6b1e90b0506608f7caa"><code>b84941e</code></a>
feat(linter/vue): implement no-expose-after-await rule (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22675">#22675</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.68.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint-tsgolint` from 0.22.1 to 0.23.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v0.23.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update crate-ci/typos action to v1.45.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/915">oxc-project/tsgolint#915</a></li>
<li>feat: add skill for upgrading typescript-go by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/918">oxc-project/tsgolint#918</a></li>
<li>chore(deps): update pnpm to v10.33.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/921">oxc-project/tsgolint#921</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/922">oxc-project/tsgolint#922</a></li>
<li>fix: attach tsconfig path to diagnostics by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/923">oxc-project/tsgolint#923</a></li>
<li>fix(prefer-nullish-coalescing): parenthesize mixed logical fixes by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/924">oxc-project/tsgolint#924</a></li>
<li>tests(return-await): cover non-async arrow functions by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/926">oxc-project/tsgolint#926</a></li>
<li>chore(deps): update github.com/go-json-experiment/json digest to
b6187a3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/927">oxc-project/tsgolint#927</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/928">oxc-project/tsgolint#928</a></li>
<li>chore(deps): update crate-ci/typos action to v1.46.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/929">oxc-project/tsgolint#929</a></li>
<li>chore(deps): update module github.com/dlclark/regexp2 to v2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/930">oxc-project/tsgolint#930</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/931">oxc-project/tsgolint#931</a></li>
<li>chore(deps): update typescript-go digest to 48e2953 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/933">oxc-project/tsgolint#933</a></li>
<li>chore(deps): update typescript-go digest to 5eb880f by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/936">oxc-project/tsgolint#936</a></li>
<li>fix(no-misused-promises): handle empty JSX attributes by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/938">oxc-project/tsgolint#938</a></li>
<li>fix(no-unsafe-enum-comparison): flag string literal unions by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/937">oxc-project/tsgolint#937</a></li>
<li>chore(deps): update typescript-go digest to e1f8f97 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/939">oxc-project/tsgolint#939</a></li>
<li>chore(deps): update typescript-go digest to 092b34f by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/940">oxc-project/tsgolint#940</a></li>
<li>chore: configure typescript-go renovate schedule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/941">oxc-project/tsgolint#941</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/945">oxc-project/tsgolint#945</a></li>
<li>chore(deps): update dependency dprint-typescript to v0.96.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/947">oxc-project/tsgolint#947</a></li>
<li>chore(deps): update gomod by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/946">oxc-project/tsgolint#946</a></li>
<li>chore(deps): update crate-ci/typos action to v1.46.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/948">oxc-project/tsgolint#948</a></li>
<li>fix(prefer-nullish-coalescing): emit suggestion over fix by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/951">oxc-project/tsgolint#951</a></li>
<li>chore: update packageManager to pnpm 11.0.4 by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/953">oxc-project/tsgolint#953</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/955">oxc-project/tsgolint#955</a></li>
<li>fix(no-nullable-type-assertion-style): use suggestion instead of fix
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/956">oxc-project/tsgolint#956</a></li>
<li>docs: Update Go version requirement to 1.26 in CONTRIBUTING.md. by
<a href="https://github.com/connorshea"><code>@​connorshea</code></a> in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/957">oxc-project/tsgolint#957</a></li>
<li>fix: allow safe promise intersection members by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/959">oxc-project/tsgolint#959</a></li>
<li>ci: switch security workflow to ubuntu-latest by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/962">oxc-project/tsgolint#962</a></li>
<li>chore(deps): update dependency vitest to v4.1.6 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/963">oxc-project/tsgolint#963</a></li>
<li>chore(deps): update module github.com/dlclark/regexp2/v2 to v2.0.3
by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/964">oxc-project/tsgolint#964</a></li>
<li>chore(deps): update dependency dprint-markdown to v0.22.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/965">oxc-project/tsgolint#965</a></li>
<li>chore(deps): update github actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/966">oxc-project/tsgolint#966</a></li>
<li>perf(no-unnecessary-type-parameters): stop counting settled
candidates by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/967">oxc-project/tsgolint#967</a></li>
<li>chore: add <code>dprint</code> to pnpm <code>allowBuilds</code> by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/968">oxc-project/tsgolint#968</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.22.1...v0.23.0">https://github.com/oxc-project/tsgolint/compare/v0.22.1...v0.23.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/0e575fae8407227601f66c1d8d8927a535aea58b"><code>0e575fa</code></a>
chore: add <code>dprint</code> to pnpm <code>allowBuilds</code> (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/968">#968</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/bb8886bef7ae76cf3280852228a05214c54f2a83"><code>bb8886b</code></a>
perf(no-unnecessary-type-parameters): stop counting settled candidates
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/967">#967</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/90be7b2609efd2bcae290b09e4835fe9ae52c63e"><code>90be7b2</code></a>
chore(deps): update github actions (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/966">#966</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/cdae358c525a9a93ab48af36b51ae2a6c740830d"><code>cdae358</code></a>
chore(deps): update dependency dprint-markdown to v0.22.0 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/965">#965</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/d356c9e3d66d0b4fbe1b7353fcf5b8f857d6ed80"><code>d356c9e</code></a>
chore(deps): update module github.com/dlclark/regexp2/v2 to v2.0.3 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/964">#964</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/7cba6be4c0d972578d14e52c7a454a0a15961727"><code>7cba6be</code></a>
chore(deps): update dependency vitest to v4.1.6 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/963">#963</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/1dcd2a6f4138f4b9a273a231def838995ac589e5"><code>1dcd2a6</code></a>
ci: switch security workflow to ubuntu-latest (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/962">#962</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/b4f66246a62ea03d7cd664bf940d2f978c2068d5"><code>b4f6624</code></a>
fix: allow safe promise intersection members (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/959">#959</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/233eeb35db9d698db67c4d4247963047ceb30fb7"><code>233eeb3</code></a>
docs: Update Go version requirement to 1.26 in CONTRIBUTING.md. (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/957">#957</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/8bd37abc596e5dd0d54ec6625b6c2a77922b7ca4"><code>8bd37ab</code></a>
fix(no-nullable-type-assertion-style): use suggestion instead of fix (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/956">#956</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.22.1...v0.23.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `tailwindcss` from 4.2.4 to 4.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<h3>Added</h3>
<ul>
<li>Add <code>@container-size</code> utility (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/18901">#18901</a>)</li>
<li>Add <code>scrollbar-{auto,thin,none}</code> utilities for
<code>scrollbar-width</code>, and <code>scrollbar-thumb-*</code> /
<code>scrollbar-track-*</code> color utilities for
<code>scrollbar-color</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19981">#19981</a>,
<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20019">#20019</a>)</li>
<li>Add <code>scrollbar-gutter-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20018">#20018</a>)</li>
<li>Add <code>zoom-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20020">#20020</a>)</li>
<li>Add <code>tab-*</code> utilities (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/20022">#20022</a>)</li>
<li>Allow using <code>@variant</code> with stacked variants (e.g.
<code>@variant hover:focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Allow using <code>@variant</code> with compound variants (e.g.
<code>@variant hover, focus { … }</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19996">#19996</a>)</li>
<li>Support <code>--default(…)</code> in <code>--value(…)</code> and
<code>--modifier(…)</code> for functional <code>@utility</code>
definitions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19989">#19989</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Ensure <code>@plugin</code> resolves package JavaScript entries
instead of browser CSS entries when using <code>@tailwindcss/vite</code>
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19949">#19949</a>)</li>
<li>Fix relative <code>@import</code> and <code>@plugin</code> paths
resolving from the wrong directory when using
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19965">#19965</a>)</li>
<li>Ensure CSS files containing <code>@variant</code> are processed by
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19966">#19966</a>)</li>
<li>Resolve imports relative to <code>base</code> when
<code>result.opts.from</code> is not provided when using
<code>@tailwindcss/postcss</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19980">#19980</a>)</li>
<li>Canonicalization: preserve significant <code>_</code> whitespace in
arbitrary values (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19986">#19986</a>)</li>
<li>Canonicalization: add parentheses when removing whitespace from
arbitrary values would hurt readability (e.g.
<code>w-[calc(100%---spacing...

_Description has been truncated_

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-09 20:53:10 -04:00
dependabot[bot]andCaliBrain 2e25d2d8db Bump qbittorrent-api from 2025.11.1 to 2026.5.1 (#991)
Bumps [qbittorrent-api](https://github.com/rmartin16/qbittorrent-api)
from 2025.11.1 to 2026.5.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/releases">qbittorrent-api's
releases</a>.</em></p>
<blockquote>
<h2>release-2026.5.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Add missing tracker statuses by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/613">rmartin16/qbittorrent-api#613</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.0...v2026.5.1">https://github.com/rmartin16/qbittorrent-api/compare/v2026.5.0...v2026.5.1</a></p>
<h2>release-2026.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add v5_1_x to QBT_VER matrix in CI workflow by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/580">rmartin16/qbittorrent-api#580</a></li>
<li>typo-- by <a
href="https://github.com/ratijas"><code>@​ratijas</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/591">rmartin16/qbittorrent-api#591</a></li>
<li>Update to latest qBittorrent wiki links by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/592">rmartin16/qbittorrent-api#592</a></li>
<li>Disable problematic http scheme change test by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/593">rmartin16/qbittorrent-api#593</a></li>
<li>limit chardet version by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/595">rmartin16/qbittorrent-api#595</a></li>
<li>skip <code>test_update_plugins</code> test for older qbittorrent
versions by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/599">rmartin16/qbittorrent-api#599</a></li>
<li>Add v5_2_x to test matrix by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/601">rmartin16/qbittorrent-api#601</a></li>
<li>fix test failing for unverified request against master by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/600">rmartin16/qbittorrent-api#600</a></li>
<li>Advertise support for qBittorrent v5.2.0 by <a
href="https://github.com/rmartin16"><code>@​rmartin16</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/611">rmartin16/qbittorrent-api#611</a></li>
<li>feat: add torrents_set_comment method to set comments for torrents
by <a href="https://github.com/trim21"><code>@​trim21</code></a> in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/610">rmartin16/qbittorrent-api#610</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/ratijas"><code>@​ratijas</code></a> made
their first contribution in <a
href="https://redirect.github.com/rmartin16/qbittorrent-api/pull/591">rmartin16/qbittorrent-api#591</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2025.11.1...v2026.5.0">https://github.com/rmartin16/qbittorrent-api/compare/v2025.11.1...v2026.5.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md">qbittorrent-api's
changelog</a>.</em></p>
<blockquote>
<h3>v2026.5.1 (05 may 2026)</h3>
<ul>
<li>Add new tracker statuses for qBittorrent v5.2.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/613">#613</a>)</li>
</ul>
<h3>v2026.5.0 (03 may 2026)</h3>
<ul>
<li>Advertise support for qBittorrent v5.2.0</li>
<li>Add support for torrent setComment endpoints (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/610">#610</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/85b6e4d3da4146e40fcaefcd4fecb9186f33c1cb"><code>85b6e4d</code></a>
Bump to v2026.5.1</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/a1c13dd50ae8c8caeac9bb4806830ef62edbbb94"><code>a1c13dd</code></a>
Add missing tracker statuses (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/613">#613</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/b6c7cdcdc88ebf1be0267fe0308e5b7aba551152"><code>b6c7cdc</code></a>
feat: add torrents_set_comment method to set comments for torrents (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/610">#610</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/46b3a5dc06fb409a83edcec7877961b2331610cb"><code>46b3a5d</code></a>
Advertise support for qBittorrent v5.2.0 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/611">#611</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/f0f96970b6506b8411460d0ae991c56918325922"><code>f0f9697</code></a>
Bumped pre-commit hook for mirrors-mypy from v1.20.0 to v1.20.2 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/608">#608</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/e2bf3dde05ad8280faf9d489350646434a3d4dd0"><code>e2bf3dd</code></a>
Bumped pre-commit hook for ruff-pre-commit from v0.15.8 to v0.15.12 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/609">#609</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/19df4c7f45354935b84987f5df8d7f789784b92f"><code>19df4c7</code></a>
Bump build from 1.4.2 to 1.4.4 in the pip group (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/607">#607</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/10fc622202ae819c36856c728e25d9d54e44923d"><code>10fc622</code></a>
Bump the github-actions group with 4 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/606">#606</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/33f5e1c1d731bb042e7f3a6d5accb1138f8cef97"><code>33f5e1c</code></a>
Bump the github-actions group with 6 updates (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/602">#602</a>)</li>
<li><a
href="https://github.com/rmartin16/qbittorrent-api/commit/31f90f35166ade72495fffae268f657e78a52818"><code>31f90f3</code></a>
Bumped pre-commit hook for ruff-pre-commit from v0.15.4 to v0.15.8 (<a
href="https://redirect.github.com/rmartin16/qbittorrent-api/issues/604">#604</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/rmartin16/qbittorrent-api/compare/v2025.11.1...v2026.5.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qbittorrent-api&package-manager=uv&previous-version=2025.11.1&new-version=2026.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-09 20:51:26 -04:00
dependabot[bot]andCaliBrain 709d3828d9 Bump the docker-base-image-digests group across 1 directory with 2 updates (#1015)
Bumps the docker-base-image-digests group with 2 updates in the /
directory: node and python.

Updates `node` from `d1b3b4d` to `2bdb65e`

Updates `python` from 3.14-slim to 3.14.5-slim


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CaliBrain <calibrain@l4n.xyz>
2026-06-09 20:43:01 -04:00
dependabot[bot] d808c362ea Bump the gh-actions group across 1 directory with 6 updates (#1044)
Bumps the gh-actions group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `6.0.2` |
`6.0.3` |
| [docker/login-action](https://github.com/docker/login-action) |
`4.1.0` | `4.2.0` |
| [docker/metadata-action](https://github.com/docker/metadata-action) |
`6.0.0` | `6.1.0` |
|
[docker/setup-buildx-action](https://github.com/docker/setup-buildx-action)
| `4.0.0` | `4.1.0` |
|
[docker/build-push-action](https://github.com/docker/build-push-action)
| `7.1.0` | `7.2.0` |
| [github/codeql-action](https://github.com/github/codeql-action) |
`4.35.4` | `4.36.1` |


Updates `actions/checkout` from 6.0.2 to 6.0.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/df4cb1c069e1874edd31b4311f1884172cec0e10"><code>df4cb1c</code></a>
Update changelog for v6.0.3 (<a
href="https://redirect.github.com/actions/checkout/issues/2446">#2446</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/1cce3390c2bfda521930d01229c073c7ff920824"><code>1cce339</code></a>
Fix checkout init for SHA-256 repositories (<a
href="https://redirect.github.com/actions/checkout/issues/2439">#2439</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/900f2210b1d28bbbd0bd22d17926b9e224e8f231"><code>900f221</code></a>
fix: expand merge commit SHA regex and add SHA-256 test cases (<a
href="https://redirect.github.com/actions/checkout/issues/2414">#2414</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/0c366fd6a839edf440554fa01a7085ccba70ac98"><code>0c366fd</code></a>
Update changelog (<a
href="https://redirect.github.com/actions/checkout/issues/2357">#2357</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/login-action` from 4.1.0 to 4.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/login-action/releases">docker/login-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.2.0</h2>
<ul>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/login-action/pull/976">docker/login-action#976</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1050.0 in <a
href="https://redirect.github.com/docker/login-action/pull/960">docker/login-action#960</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.86.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/login-action/pull/970">docker/login-action#970</a></li>
<li>Bump brace-expansion from 2.0.1 to 5.0.6 in <a
href="https://redirect.github.com/docker/login-action/pull/993">docker/login-action#993</a></li>
<li>Bump fast-xml-builder from 1.1.4 to 1.2.0 in <a
href="https://redirect.github.com/docker/login-action/pull/985">docker/login-action#985</a></li>
<li>Bump fast-xml-parser from 5.3.6 to 5.8.0 in <a
href="https://redirect.github.com/docker/login-action/pull/963">docker/login-action#963</a></li>
<li>Bump http-proxy-agent and https-proxy-agent to 9.0.0 in <a
href="https://redirect.github.com/docker/login-action/pull/961">docker/login-action#961</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/login-action/pull/979">docker/login-action#979</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/login-action/pull/991">docker/login-action#991</a></li>
<li>Bump vite from 7.3.1 to 7.3.3 in <a
href="https://redirect.github.com/docker/login-action/pull/986">docker/login-action#986</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.1.0...v4.2.0">https://github.com/docker/login-action/compare/v4.1.0...v4.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/login-action/commit/650006c6eb7dba73a995cc03b0b2d7f5ca915bee"><code>650006c</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/960">#960</a>
from docker/dependabot/npm_and_yarn/aws-sdk-dependenc...</li>
<li><a
href="https://github.com/docker/login-action/commit/99df1a3f6d65e48177ea57671a50e2242eae4b63"><code>99df1a3</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/3ab375f324f46da5f6901efeda4be4e2566ebaa2"><code>3ab375f</code></a>
build(deps): bump the aws-sdk-dependencies group across 1 directory with
2 up...</li>
<li><a
href="https://github.com/docker/login-action/commit/39d85804ae465a1816c68ff58158ec66883981b4"><code>39d8580</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/970">#970</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/login-action/commit/4eefcd33ca7213989697445a78b6730274bfaba6"><code>4eefcd3</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/56d092c8b3f04006c22f4fc20a2b3d2442caed56"><code>56d092c</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.86.0 to
0.90.0</li>
<li><a
href="https://github.com/docker/login-action/commit/e2e31ca87063ae00fd41ad3b9c548dd8ec24c5ff"><code>e2e31ca</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/976">#976</a>
from docker/dependabot/npm_and_yarn/actions/core-3.0.1</li>
<li><a
href="https://github.com/docker/login-action/commit/0bced941e843afc786fbfd58b1c6c13ca11e09c9"><code>0bced94</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/3e75a0f266b07e09777a621d0ca5f4432ef9f10c"><code>3e75a0f</code></a>
build(deps): bump <code>@​actions/core</code> from 3.0.0 to 3.0.1</li>
<li><a
href="https://github.com/docker/login-action/commit/365bebd9d646160567ebad47824f026e09ee6970"><code>365bebd</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/984">#984</a>
from docker/dependabot/github_actions/aws-actions/con...</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/login-action/compare/4907a6ddec9925e35a0a9e82d7399ccc52663121...650006c6eb7dba73a995cc03b0b2d7f5ca915bee">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/metadata-action` from 6.0.0 to 6.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/metadata-action/releases">docker/metadata-action's
releases</a>.</em></p>
<blockquote>
<h2>v6.1.0</h2>
<ul>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.79.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/metadata-action/pull/613">docker/metadata-action#613</a></li>
<li>Bump brace-expansion from 1.1.12 to 5.0.6 in <a
href="https://redirect.github.com/docker/metadata-action/pull/658">docker/metadata-action#658</a>
<a
href="https://redirect.github.com/docker/metadata-action/pull/630">docker/metadata-action#630</a></li>
<li>Bump csv-parse from 6.1.0 to 6.2.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/617">docker/metadata-action#617</a></li>
<li>Bump fast-xml-parser from 5.4.2 to 5.8.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/620">docker/metadata-action#620</a></li>
<li>Bump flatted from 3.3.3 to 3.4.2 in <a
href="https://redirect.github.com/docker/metadata-action/pull/623">docker/metadata-action#623</a></li>
<li>Bump glob from 10.3.15 to 10.5.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/621">docker/metadata-action#621</a></li>
<li>Bump handlebars from 4.7.8 to 4.7.9 in <a
href="https://redirect.github.com/docker/metadata-action/pull/629">docker/metadata-action#629</a></li>
<li>Bump lodash from 4.17.23 to 4.18.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/639">docker/metadata-action#639</a></li>
<li>Bump moment-timezone from 0.6.0 to 0.6.1 in <a
href="https://redirect.github.com/docker/metadata-action/pull/619">docker/metadata-action#619</a></li>
<li>Bump picomatch from 4.0.3 to 4.0.4 in <a
href="https://redirect.github.com/docker/metadata-action/pull/626">docker/metadata-action#626</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/metadata-action/pull/649">docker/metadata-action#649</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/metadata-action/pull/657">docker/metadata-action#657</a></li>
<li>Bump undici from 6.23.0 to 6.25.0 in <a
href="https://redirect.github.com/docker/metadata-action/pull/614">docker/metadata-action#614</a></li>
<li>Bump vite from 7.3.1 to 7.3.2 in <a
href="https://redirect.github.com/docker/metadata-action/pull/637">docker/metadata-action#637</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/metadata-action/compare/v6.0.0...v6.1.0">https://github.com/docker/metadata-action/compare/v6.0.0...v6.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/metadata-action/commit/80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9"><code>80c7e94</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/613">#613</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/metadata-action/commit/8e0ddab90c29de6fff30c787e328563e48106fd0"><code>8e0ddab</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/metadata-action/commit/a8db14bd863c93be08c93c13e1cc816ec5b49b2e"><code>a8db14b</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.79.0 to
0.90.0</li>
<li><a
href="https://github.com/docker/metadata-action/commit/63a7371ee01888324f2c7b3e18be9ac13b9dbdbc"><code>63a7371</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/617">#617</a>
from docker/dependabot/npm_and_yarn/csv-parse-6.2.0</li>
<li><a
href="https://github.com/docker/metadata-action/commit/c6916a6cf86608c44ba936565d57f550835ecd45"><code>c6916a6</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/metadata-action/commit/aca9205632182712a2d859059cf12fdc9b2ca202"><code>aca9205</code></a>
chore(deps): Bump csv-parse from 6.1.0 to 6.2.1</li>
<li><a
href="https://github.com/docker/metadata-action/commit/9dcfe60f10ebea72e9e48bf8bf366d01629d045a"><code>9dcfe60</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/629">#629</a>
from docker/dependabot/npm_and_yarn/handlebars-4.7.9</li>
<li><a
href="https://github.com/docker/metadata-action/commit/43dea7677c80686dc31a7b16e61ba9d542081b59"><code>43dea76</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/metadata-action/commit/7a56f5af0aa2d36278ba725bb44091417def9f73"><code>7a56f5a</code></a>
chore(deps): Bump handlebars from 4.7.8 to 4.7.9</li>
<li><a
href="https://github.com/docker/metadata-action/commit/e49e0aa5deac3d581afd6ce80464d84ef68f5ccc"><code>e49e0aa</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/metadata-action/issues/658">#658</a>
from docker/dependabot/npm_and_yarn/brace-expansion-5...</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/metadata-action/compare/030e881283bb7a6894de51c315a6bfe6a94e05cf...80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/setup-buildx-action` from 4.0.0 to 4.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/setup-buildx-action/releases">docker/setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.0</h2>
<ul>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.79.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/489">docker/setup-buildx-action#489</a></li>
<li>Bump brace-expansion from 1.1.12 to 5.0.6 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/547">docker/setup-buildx-action#547</a>
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/508">docker/setup-buildx-action#508</a></li>
<li>Bump fast-xml-builder from 1.0.0 to 1.2.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/540">docker/setup-buildx-action#540</a></li>
<li>Bump fast-xml-parser from 5.4.2 to 5.8.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/496">docker/setup-buildx-action#496</a></li>
<li>Bump flatted from 3.3.3 to 3.4.2 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/499">docker/setup-buildx-action#499</a></li>
<li>Bump glob from 10.3.12 to 13.0.6 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/495">docker/setup-buildx-action#495</a></li>
<li>Bump handlebars from 4.7.8 to 4.7.9 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/504">docker/setup-buildx-action#504</a></li>
<li>Bump lodash from 4.17.23 to 4.18.1 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/523">docker/setup-buildx-action#523</a></li>
<li>Bump picomatch from 4.0.3 to 4.0.4 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/503">docker/setup-buildx-action#503</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/537">docker/setup-buildx-action#537</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/545">docker/setup-buildx-action#545</a></li>
<li>Bump undici from 6.23.0 to 6.25.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/492">docker/setup-buildx-action#492</a></li>
<li>Bump vite from 7.3.1 to 7.3.2 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/520">docker/setup-buildx-action#520</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/setup-buildx-action/compare/v4.0.0...v4.1.0">https://github.com/docker/setup-buildx-action/compare/v4.0.0...v4.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5"><code>d7f5e7f</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/489">#489</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/92bc5c9777806d0a73d9d668ba2114fa1177f164"><code>92bc5c9</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/da11e35abee0f20cb4f1c1b7c461d37c29be52f5"><code>da11e35</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.79.0 to
0.90.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/f021e162ef95b6fba51af1c6674f537f25bce851"><code>f021e16</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/492">#492</a>
from docker/dependabot/npm_and_yarn/undici-6.24.1</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/b5af94fab700aee0c64d6077e0e34ae987815b67"><code>b5af94f</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/16ad9776a801d0c47f0a05f007b88a3789aa8ab6"><code>16ad977</code></a>
build(deps): bump undici from 6.23.0 to 6.25.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/d7a12d7df895b33bd02a9b4bf62a12f2b9a24458"><code>d7a12d7</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/495">#495</a>
from docker/dependabot/npm_and_yarn/glob-10.5.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/28ff27de4eed7518d361591f2cd1dfb69c34a7cb"><code>28ff27d</code></a>
build(deps): bump glob from 10.3.12 to 13.0.6</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/daf436b50e13d9053b9730cbc16516891878b019"><code>daf436b</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/496">#496</a>
from docker/dependabot/npm_and_yarn/fast-xml-parser-5...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/9725348367859764880f2f2e688a6b0c353e3f35"><code>9725348</code></a>
chore: update generated content</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/setup-buildx-action/compare/4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd...d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5">compare
view</a></li>
</ul>
</details>
<br />

Updates `docker/build-push-action` from 7.1.0 to 7.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.2.0</h2>
<ul>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1525">docker/build-push-action#1525</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1517">docker/build-push-action#1517</a></li>
<li>Bump brace-expansion from 2.0.2 to 5.0.6 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1534">docker/build-push-action#1534</a></li>
<li>Bump fast-xml-builder from 1.1.4 to 1.2.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1529">docker/build-push-action#1529</a></li>
<li>Bump fast-xml-parser from 5.5.7 to 5.8.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1521">docker/build-push-action#1521</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1526">docker/build-push-action#1526</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1533">docker/build-push-action#1533</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0">https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/build-push-action/commit/f9f3042f7e2789586610d6e8b85c8f03e5195baf"><code>f9f3042</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1517">#1517</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/812d5fd9212a4c5d419e5be02fd8e9bb435c5d76"><code>812d5fd</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/b6f66930769f2917a3275dc4d81f15583ac7e105"><code>b6f6693</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to
0.90.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/c1c626eced73a500ec65c4256c620b3b9e8278c0"><code>c1c626e</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1525">#1525</a>
from docker/dependabot/npm_and_yarn/actions/core-3.0.1</li>
<li><a
href="https://github.com/docker/build-push-action/commit/51bb284cd4d05650aa6f5e4e22cb96d2cbfe62b7"><code>51bb284</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/5f7884def8f133e8ef40c53d003d1471c05621c6"><code>5f7884d</code></a>
chore(deps): Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1</li>
<li><a
href="https://github.com/docker/build-push-action/commit/e01deff7d956c756a20f3e19ff7ddc0e4a50fc1d"><code>e01deff</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1521">#1521</a>
from docker/dependabot/npm_and_yarn/fast-xml-parser-...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/3804d497934b39bd591ee9d1c6c9e593b4488a67"><code>3804d49</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/71e8947aac5dad23ce83a43e9c98f750e02de2f3"><code>71e8947</code></a>
chore(deps): Bump fast-xml-parser from 5.5.7 to 5.8.0</li>
<li><a
href="https://github.com/docker/build-push-action/commit/4925ad24cdbc42ff492d76cf9fe7a30b79976b60"><code>4925ad2</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1526">#1526</a>
from docker/dependabot/npm_and_yarn/postcss-8.5.10</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/build-push-action/compare/bcafcacb16a39f128d818304e6c9c0c18556b85f...f9f3042f7e2789586610d6e8b85c8f03e5195baf">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action` from 4.35.4 to 4.36.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.36.1</h2>
<p>No user facing changes.</p>
<h2>v4.36.0</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>v4.35.5</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.36.2 - 04 Jun 2026</h2>
<ul>
<li>Cache CodeQL CLI version information across Actions steps. <a
href="https://redirect.github.com/github/codeql-action/pull/3943">#3943</a></li>
<li>Reduce requests while waiting for analysis processing by using
exponential backoff when polling SARIF processing status. <a
href="https://redirect.github.com/github/codeql-action/pull/3937">#3937</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.6">2.25.6</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3948">#3948</a></li>
</ul>
<h2>4.36.1 - 02 Jun 2026</h2>
<p>No user facing changes.</p>
<h2>4.36.0 - 22 May 2026</h2>
<ul>
<li><em>Breaking change</em>: Bump the minimum required CodeQL bundle
version to 2.19.4. <a
href="https://redirect.github.com/github/codeql-action/pull/3894">#3894</a></li>
<li>Add support for SHA-256 Git object IDs. <a
href="https://redirect.github.com/github/codeql-action/pull/3893">#3893</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5">2.25.5</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3926">#3926</a></li>
</ul>
<h2>4.35.5 - 15 May 2026</h2>
<ul>
<li>We have improved how the JavaScript bundles for the CodeQL Action
are generated to avoid duplication across bundles and reduce the size of
the repository by around 70%. This should have no effect on the runtime
behaviour of the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3899">#3899</a></li>
<li>For performance and accuracy reasons, <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> will now only be enabled on a pull request when
diff-informed analysis is also enabled for that run. If diff-informed
analysis is unavailable (for example, because the PR diff ranges could
not be computed), the action will fall back to a full analysis. <a
href="https://redirect.github.com/github/codeql-action/pull/3791">#3791</a></li>
<li>If multiple inputs are provided for the GitHub-internal
<code>analysis-kinds</code> input, only <code>code-scanning</code> will
be enabled. The <code>analysis-kinds</code> input is experimental, for
GitHub-internal use only, and may change without notice at any time. <a
href="https://redirect.github.com/github/codeql-action/pull/3892">#3892</a></li>
<li>Added an experimental change which, when running a Code Scanning
analysis for a PR with <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> enabled, prefers CodeQL CLI versions that have
a cached overlay-base database for the configured languages. This speeds
up analysis for a repository when there is not yet a cached overlay-base
database for the latest CLI version. We expect to roll this change out
to everyone in May. <a
href="https://redirect.github.com/github/codeql-action/pull/3880">#3880</a></li>
</ul>
<h2>4.35.4 - 07 May 2026</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.19.3 and earlier. These versions of
CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise
Server 3.15, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li>
<li>Configurations for private registries that use Cloudsmith or GCP
OIDC are now accepted. <a
href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li>
<li>Best-effort connection tests for private registries now use
<code>GET</code> requests instead of <code>HEAD</code> for better
compatibility with various registry implementations. For NuGet feeds,
the test is now always performed against the service index. <a
href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li>
<li>Fixed a bug where two diagnostics produced within the same
millisecond could overwrite each other on disk, causing one of them to
be lost. <a
href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li>
</ul>
<h2>4.35.2 - 15 Apr 2026</h2>
<ul>
<li>The undocumented TRAP cache cleanup feature that could be enabled
using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment
variable is deprecated and will be removed in May 2026. If you are
affected by this, we recommend disabling TRAP caching by passing the
<code>trap-caching: false</code> input to the <code>init</code> Action.
<a
href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li>
<li>The Git version 2.36.0 requirement for improved incremental analysis
now only applies to repositories that contain submodules. <a
href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li>
<li>Python analysis on GHES no longer extracts the standard library,
relying instead on models of the standard library. This should result in
significantly faster extraction and analysis times, while the effect on
alerts should be minimal. <a
href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li>
<li>Fixed a bug in the validation of OIDC configurations for private
registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/87557b9c84dde89fdd9b10e88954ac2f4248e463"><code>87557b9</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3940">#3940</a>
from github/update-v4.36.1-2a1689ed4</li>
<li><a
href="https://github.com/github/codeql-action/commit/94310119648b77e2153bf970fd244062806781de"><code>9431011</code></a>
Update changelog for v4.36.1</li>
<li><a
href="https://github.com/github/codeql-action/commit/2a1689ed43ccdf7eea07e03a75371ce6801d28e6"><code>2a1689e</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3939">#3939</a>
from github/henrymercer/skip-overlay-revert-when-exp...</li>
<li><a
href="https://github.com/github/codeql-action/commit/524532393a46071bdfc81527a811ffa69e16723a"><code>5245323</code></a>
Disable missing diff-ranges fallback when overlay enabled manually</li>
<li><a
href="https://github.com/github/codeql-action/commit/d1eb1207b45130d2edf64a0aa1c93be23510592f"><code>d1eb120</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3933">#3933</a>
from github/update-supported-enterprise-server-versions</li>
<li><a
href="https://github.com/github/codeql-action/commit/115001ba8d0198846992657731666b08686c8ded"><code>115001b</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3934">#3934</a>
from github/dependabot/npm_and_yarn/npm-minor-86fb5c...</li>
<li><a
href="https://github.com/github/codeql-action/commit/cef2e7a910879f4626a24b251504bde16bfe4e76"><code>cef2e7a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3925">#3925</a>
from github/dependabot/github_actions/dot-github/wor...</li>
<li><a
href="https://github.com/github/codeql-action/commit/5e6adf70ed0299cdf20f90e4e37ac5dd30ab7501"><code>5e6adf7</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3936">#3936</a>
from github/dependabot/npm_and_yarn/tmp-0.2.7</li>
<li><a
href="https://github.com/github/codeql-action/commit/ad170e6c4eaf671895978420267d6cb49b66b706"><code>ad170e6</code></a>
Merge branch 'main' into
dependabot/github_actions/dot-github/workflows/actio...</li>
<li><a
href="https://github.com/github/codeql-action/commit/6a37b3a57ac457a679b84930a67c233c15f5ac41"><code>6a37b3a</code></a>
Rebuild</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/68bde559dea0fdcac2102bfdf6230c5f70eb485e...87557b9c84dde89fdd9b10e88954ac2f4248e463">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 20:40:55 -04:00
dependabot[bot] ad5686a23a Bump gunicorn from 25.3.0 to 26.0.0 (#990)
Bumps [gunicorn](https://github.com/benoitc/gunicorn) from 25.3.0 to
26.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/benoitc/gunicorn/releases">gunicorn's
releases</a>.</em></p>
<blockquote>
<h2>26.0.0</h2>
<h2>Breaking Changes</h2>
<ul>
<li><strong>Eventlet worker removed</strong>: The <code>eventlet</code>
worker class has been dropped. Migrate to <code>gevent</code>,
<code>gthread</code>, or <code>tornado</code>.</li>
</ul>
<h2>New Features</h2>
<ul>
<li><strong>ASGI Framework Compatibility Suite</strong>: New end-to-end
compatibility test harness covering Starlette, FastAPI, Litestar, Quart,
Sanic, and BlackSheep. Current grid passes 438/444 tests (98%).</li>
<li><strong>ASGI Test Suite Expansion</strong>: 134 additional ASGI unit
tests covering protocol semantics, lifespan, websockets, and chunked
framing.</li>
</ul>
<h2>Security</h2>
<ul>
<li><strong>HTTP/1.1 Request-Target Validation</strong> (RFC 9112
sections 3.2.3, 3.2.4):
<ul>
<li>Reject <code>authority-form</code> request-target outside
<code>CONNECT</code></li>
<li>Reject <code>asterisk-form</code> request-target outside
<code>OPTIONS</code></li>
<li>Reject <code>relative-reference</code> request-targets</li>
</ul>
</li>
<li><strong>Header Field Hardening</strong> (RFC 9110):
<ul>
<li>Reject control characters in header field-value (section 5.5)</li>
<li>Reject forbidden trailer field-names (section 6.5.1)</li>
<li>Reject <code>Content-Length</code> list form (RFC 9112 section
6.3)</li>
</ul>
</li>
<li><strong>Request Smuggling Hardening</strong>:
<ul>
<li>Tighten keepalive gate and scope <code>finish_body</code> byte
cap</li>
<li>Keep <code>_body_receiver</code> alive across the keepalive
smuggling gate so pipelined requests cannot re-enter a closed body</li>
<li>Address parser/protocol findings from a six-point WSGI/ASGI
audit</li>
</ul>
</li>
<li><strong>PROXY Protocol (ASGI)</strong>: Enforce
<code>proxy_allow_ips</code> and tighten v1/v2 parsing in the ASGI
callback parser.</li>
<li><strong>Connection Draining</strong>: Drain the connection on close
per RFC 9112 section 9.6 to prevent reset-on-close truncation.</li>
</ul>
<h2>Bug Fixes</h2>
<ul>
<li><strong>Body Framing on HEAD/204/304</strong>:
<ul>
<li>Keep <code>Content-Length</code> on HEAD and 304 responses (<a
href="https://redirect.github.com/benoitc/gunicorn/issues/3621">#3621</a>)</li>
<li>Drop body framing on HEAD/204/304 even when the framework set
it</li>
<li>Warn once when an ASGI app emits a body for a no-body response</li>
</ul>
</li>
<li><strong>HTTP/2 ASGI</strong>:
<ul>
<li>Fix <code>_handle_stream_ended</code> to set
<code>_body_complete</code> in the async HTTP/2 handler so request
bodies finalize correctly on stream end</li>
<li>Add <code>InvalidChunkExtension</code> mapping and fast-parser
support in ASGI tests (<a
href="https://redirect.github.com/benoitc/gunicorn/issues/3565">#3565</a>)</li>
</ul>
</li>
<li><strong>HTTP/1.1 100-Continue</strong>: Stop adding
<code>Transfer-Encoding: chunked</code> to 100-Continue interim
responses.</li>
<li><strong>WebSocket Close Handshake</strong> (RFC 6455):
<ul>
<li>Comply with the close handshake state machine</li>
<li>Close the transport after the close handshake completes</li>
<li>Fix binary send when the <code>text</code> key is
<code>None</code></li>
</ul>
</li>
<li><strong>Early Hints</strong>: Validate headers in the
<code>early_hints</code> callback to match <code>process_headers</code>;
pass only the header name to <code>InvalidHeader</code> (<a
href="https://redirect.github.com/benoitc/gunicorn/issues/3588">#3588</a>).</li>
<li><strong>ASGI Framework Fixes</strong>:
<ul>
<li>Fix ASGI disconnect handling for Django-style apps</li>
<li>Fix Litestar request handling (use raw ASGI receive for
body/headers)</li>
<li>Fix Litestar HTTP endpoints for compatibility tests</li>
<li>Fix Quart headers endpoint to normalize keys to lowercase</li>
<li>Fix Quart WebSocket close test app (missing
<code>accept()</code>)</li>
<li>Fix duplicate <code>Transfer-Encoding</code> header for BlackSheep
streaming</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/benoitc/gunicorn/commit/5d819cf36040f6cc6175fcc804d703fb899509dd"><code>5d819cf</code></a>
release: 26.0.0</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/b45c70df105f7d5dcbc5abfb732804d6464edc21"><code>b45c70d</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3611">#3611</a>
from zc-mattcen/docs-typo</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/99c8d48acf453deb5c49fe12e195dbc00d888d1e"><code>99c8d48</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3623">#3623</a>
from benoitc/chore/drop-eventlet-add-h2-uvloop-test-...</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/5a655af50f20e005dd9e32e6078dc82fa45f3d4b"><code>5a655af</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3622">#3622</a>
from benoitc/test/docker-port-and-ipv4-fixes</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/201df19a8011c0a1d6a0e75ebe22e89d48eb935e"><code>201df19</code></a>
chore: remove eventlet worker; add h2 and uvloop to test deps</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/f4ac8e1f1bf1d365e77f41915da55bec31873f84"><code>f4ac8e1</code></a>
test: pass action name to dirty client and stabilize after TTOU
spam</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/54d38afddf1f0db0c15b5f4ff63f3c7bfad96961"><code>54d38af</code></a>
test: unblock docker fixtures on macOS hosts</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/68843c8893dd938456f0a2da62085ab5776f8871"><code>68843c8</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3621">#3621</a>
from benoitc/fix/asgi-preserve-content-length-on-hea...</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/31f2618f733cc0c78690df63f4e344aaf3f56b20"><code>31f2618</code></a>
Merge pull request <a
href="https://redirect.github.com/benoitc/gunicorn/issues/3620">#3620</a>
from benoitc/fix/asgi-proxy-protocol-trust-and-parsing</li>
<li><a
href="https://github.com/benoitc/gunicorn/commit/41ec7527dbd8a9e52728477700707ad40e41d9dc"><code>41ec752</code></a>
fix: keep Content-Length on HEAD and 304 responses</li>
<li>Additional commits viewable in <a
href="https://github.com/benoitc/gunicorn/compare/25.3.0...26.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gunicorn&package-manager=uv&previous-version=25.3.0&new-version=26.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-09 20:40:23 -04:00
Alex 3d18320096 Update readme (#1000) 2026-05-14 14:46:43 +01:00
Alex 3ac8d9f681 Update urllib3 to 2.7.0 (#986) 2026-05-12 12:25:39 +01:00
Alex 2f9b42f428 Clarify Docker digest update group (#992) 2026-05-12 12:21:15 +01:00
Alex 5a53d5910d Update dependabot check timings (#987) 2026-05-12 12:11:12 +01:00
Alex b28ad55d46 Relax URL hardening (#984) 2026-05-12 08:47:53 +01:00
Alex 9c3af5793b Fail closed on unwritable config (#985) 2026-05-12 08:47:42 +01:00
Alex d1fd93f180 Harden Welib URL validation (#979) 2026-05-10 15:20:43 +01:00
Alex b67df083e6 Remove installer tooling from runtime images (#978) 2026-05-10 15:08:44 +01:00
Alex b038867d8d Validate Welib fallback URLs (#977) 2026-05-10 10:28:52 +01:00
Alex 472aae608b Restrict torrent prefetch to trusted origins (#976) 2026-05-10 10:22:49 +01:00
Alex 0e120abfaf Validate request policy release source (#975) 2026-05-10 09:46:31 +01:00
Alex f6357ead41 Contain remote path mappings (#974) 2026-05-10 09:29:49 +01:00
Alex d67eeace3c Harden qBittorrent fallback path joins (#973) 2026-05-10 09:19:31 +01:00
Alex e615797e69 Enforce release source availability before queueing (#971) 2026-05-10 08:52:17 +01:00
Alex 2aee1d587e Validate ABB detail URLs (#972) 2026-05-10 08:25:03 +01:00
Alex d1ab58411b Fix queue management ownership checks (#970) 2026-05-09 14:42:11 +01:00
Alex f4daf05d03 Pin Docker base image digests (#969) 2026-05-09 14:37:44 +01:00
Alex 5f9f47cc41 Redact release URLs safely (#968) 2026-05-09 14:22:25 +01:00
Alex 81b448bc9f Restrict SABnzbd NZB prefetch origins (#967) 2026-05-09 13:44:47 +01:00
Alex eee8ba0e83 Fix Tor healthcheck clear-net probe (#966) 2026-05-09 13:33:12 +01:00
Alex cecbae738e Move archive extraction from memory to stream (#965) 2026-05-09 13:19:44 +01:00
Alex f5fafd2265 Validate IRC DCC offers before download (#964) 2026-05-09 13:19:22 +01:00
Alex fbbff8f715 Require verified OIDC email for account linking (#963)
Fixes a security issue relying on plain email fields for OIDC user
linking. Requires verified email instead.
2026-05-09 07:24:31 +01:00
Alex 9b8402c9a7 Add DISABLE_LOCAL_AUTH env variable (#962)
Adds a new env var to disable local auth entirely when using OIDC
authentication

Fixes #922 #834
2026-05-08 22:11:14 +01:00
Alex 3305ec9e46 Open up hardlink requirement (#961) 2026-05-08 13:26:38 +01:00
Alex f03be02de0 Fix language string normalisation (#960)
Fixes #948
2026-05-08 12:14:44 +01:00
dependabot[bot]andAlex 7d589abc35 Bump the npm-deps group across 1 directory with 9 updates (#953)
Bumps the npm-deps group with 9 updates in the /src/frontend directory:

| Package | From | To |
| --- | --- | --- |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) |
`19.2.5` | `19.2.6` |
|
[react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom)
| `19.2.5` | `19.2.6` |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.14.2` | `7.15.0` |
|
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
| `25.6.0` | `25.6.2` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.6.2` | `6.12.1` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.46.0` | `0.48.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.61.0` | `1.63.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.21.1`
| `0.22.1` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.0.10` | `8.0.11` |


Updates `react` from 19.2.5 to 19.2.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react's
releases</a>.</em></p>
<blockquote>
<h2>19.2.6 (May 6th, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Type hardening and performance improvements
(<a
href="https://redirect.github.com/facebook/react/pull/36425">#36425</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> and
<a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/eaf3e95ca92be7a23d3c9cc8ffd6f199a40be401"><code>eaf3e95</code></a>
Version 19.2.6</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.6/packages/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-dom` from 19.2.5 to 19.2.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react-dom's
releases</a>.</em></p>
<blockquote>
<h2>19.2.6 (May 6th, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Type hardening and performance improvements
(<a
href="https://redirect.github.com/facebook/react/pull/36425">#36425</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> and
<a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/eaf3e95ca92be7a23d3c9cc8ffd6f199a40be401"><code>eaf3e95</code></a>
Version 19.2.6</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.6/packages/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-router-dom` from 7.14.2 to 7.15.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.15.0</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.15.0"><code>react-router@7.15.0</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/97c8de79c38f107acd15f74d8295c7bf75894a5d"><code>97c8de7</code></a>
Release v7.15.0 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/15018">#15018</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.15.0/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 25.6.0 to 25.6.2
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.6.2 to 6.12.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.12.1</h2>
<ul>
<li>fix: type-only imports in monorepos (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1715">#1715</a>)
(de33a2cb020f321f242bfb3884cdd597fb5f868c) - thanks <a
href="https://github.com/lishaduck"><code>@​lishaduck</code></a>!</li>
<li>Bump jiti to ^2.7.0 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1729">#1729</a>)
(0fe8dc33dc60b05a814828046aa5207051fc4b6d) - thanks <a
href="https://github.com/re-taro"><code>@​re-taro</code></a>!</li>
<li>Fix Vercel config detection (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1726">#1726</a>)
(370236d2e67058fb30c77a5f54d88b9774276eef) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Fix inferred declaration export references (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1728">#1728</a>)
(4dcd756f0903c1045a7600201243decbc7184715) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Remove stale root watch script (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1731">#1731</a>)
(2d555a18befc2576539491b5d66799e630689b38) - thanks <a
href="https://github.com/jeffrey-takuma"><code>@​jeffrey-takuma</code></a>!</li>
<li>Update sponsorships script/numbers
(c3dcc8f4fd923f87baad444c5f8e23fd7be15497)</li>
<li>Add orgs using knip (78fd581857c0b01fc2ab987bc86d888954e97a71)</li>
<li>Yolo (7e689bf60b39c6a4af46e8d68e9a6986df0e6f04)</li>
</ul>
<h2>Release 6.12.0</h2>
<ul>
<li>Use venz light/dark responsive svg img
(2354194043354b67ed9463b6998d40a8e8cbab81)</li>
<li>Fix types/path references
(4afc873801bcca933dbc71c47b5557cbab646c6b)</li>
<li>Move on to pnpm 11 (b1060652e85b8bf9a306135ca12ae22032099889)</li>
<li>Fix up ecosystem tests
(c226a72b8936397dab2fc6d30e27517c257c36ca)</li>
<li>Add shell binaries to global ignore list (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1716">#1716</a>)
(ddcf7debd820b9deac9f29d1ed904f340c0ee91e) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Fix declaration export regression and document (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1722">#1722</a>)
(3a2c22b52cda834b4d8a9956d9089b3dea9422bd)</li>
<li>Update snapshot after 3a2c22b
(8300078b75913d94ef19dbd1990e2073db8541d8)</li>
<li>Detect babel.plugins/presets in <code>@​vitejs/plugin-react</code>
via function-form defineConfig (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1723">#1723</a>)
(d56ee51c2162c29baf3564ded39639a1a258caa1)</li>
<li>Lift defineConfig-arg unwrapper to ast-helpers, route findCallArg
through it (7195b0a5f0986833a059c5d2cda9697d7d0abbf7)</li>
<li>Fix PostCSS detection for <code>@​tailwindcss/postcss</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1719">#1719</a>)
(60f84824eebeece47ec5d2683fe4db9aaa6e7d00) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Allow <code>&gt;</code> inside SFC <code>&lt;script&gt;</code>
attribute values (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1714">#1714</a>)
(9e5501f60150d0521bf7f2aa5a9af8db1285813b)</li>
<li>Resolve Cypress reporter set per testing type (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1724">#1724</a>)
(7cc4fc19ea12f4aefb55ef01a0ad5237b2dac8c4)</li>
<li>Add Vercel config plugin (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1720">#1720</a>)
(10f97c10cd3203761c6ba2f4ee335c9719d81840) - thanks <a
href="https://github.com/jakeleventhal"><code>@​jakeleventhal</code></a>!</li>
<li>Direct config hint title to stderr
(53236b5f7dc12c2e7e561448c276a0168a6367fc)</li>
<li>Some light housekeeping
(727f842709f2adf9fe7658b6ed1b66b11043d821)</li>
<li>Fix up ecosystem tests
(0db3300e4109cb184520863e98eff6c2c956a717)</li>
<li>Fix --no-exit-code condition for
<code>isTreatConfigHintsAsErrors</code>
(f27c3f4a556fdd18bfafb9b270fddc9b12c8033a)</li>
<li>A friendlier message (aab1e83baaa088b8f8730f03f0d8e6520fa48d64)</li>
<li>Mark plugin-name fallback binaries as optional in knownBinsOnly mode
(c709a5aaa473184d1a73f7cbcb8eaf0d73e072d4)</li>
</ul>
<h2>Release 6.11.0</h2>
<ul>
<li>Ignore &amp; remove uninteresting lines in snapshots
(767ebaf9b20d02f271d2a083404b60cba63119d7)</li>
<li>Flag stale <code>@internal</code> tags in production mode (resolve
<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1658">#1658</a>)
(dd1caeda80784d6070b028c781a3502b33e9765a)</li>
<li>Add compiler-extensions in tsc-files mode (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1708">#1708</a>)
(ea867ad4bb9195f556ff58dae010d0d77c57bb25)</li>
</ul>
<h2>Release 6.10.0</h2>
<ul>
<li>Ecosystem patches → snapshots
(1803f9f94d42ebe88730465c002098de54c6650a)</li>
<li>Fix unlisted pkg when only <code>@​types/pkg</code> listed (resolve
<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1707">#1707</a>)
(62082b69b382ea56d86e718da623ccadb9281a14)</li>
<li>Don't report imports matching engines.X as unlisted
(23582e0f4da7a98cfe50c065b63d38a75870911e)</li>
<li>Treat imports in .d.ts files as type-only
(84caac58d99f39fde56c664f42bad2c000d8943e)</li>
<li>Treat tsconfig compilerOptions.types as type-only
(ce18854b0a008f1060e30c660eee820eba1568e5)</li>
<li>Resolve hoisted deps from monorepo root in single-package mode
(resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1711">#1711</a>)
(23b756fb0becacaa19fbd71a0d9a0264f8647e88)</li>
</ul>
<h2>Release 6.9.0</h2>
<ul>
<li>Expose types for JSON reporter
(961b734f398b451bc26708f8d3bfa72a71983dcc)</li>
</ul>
<h2>Release 6.8.0</h2>
<ul>
<li>feat: add WXT plugin (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1703">#1703</a>)
(9167557755a0aef81947aaedfa4745805ffaa571) - thanks <a
href="https://github.com/sebastianbreguel"><code>@​sebastianbreguel</code></a>!</li>
<li>Add support for pnpm@11 new commands (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1706">#1706</a>)
(c937697a68caaf1ac224627537993b32d37cc91b) - thanks <a
href="https://github.com/PatrykWalach"><code>@​PatrykWalach</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/b255195be57173284dd313da599e7e86718c9cdb"><code>b255195</code></a>
Release knip@6.12.1</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/4dcd756f0903c1045a7600201243decbc7184715"><code>4dcd756</code></a>
Fix inferred declaration export references (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1728">#1728</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/370236d2e67058fb30c77a5f54d88b9774276eef"><code>370236d</code></a>
Fix Vercel config detection (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1726">#1726</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/0fe8dc33dc60b05a814828046aa5207051fc4b6d"><code>0fe8dc3</code></a>
Bump jiti to ^2.7.0 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1729">#1729</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/de33a2cb020f321f242bfb3884cdd597fb5f868c"><code>de33a2c</code></a>
fix: type-only imports in monorepos (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1715">#1715</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/44829fe6a9ca5cc34ea345860b912dceb1a87c51"><code>44829fe</code></a>
Release knip@6.12.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/c709a5aaa473184d1a73f7cbcb8eaf0d73e072d4"><code>c709a5a</code></a>
Mark plugin-name fallback binaries as optional in knownBinsOnly
mode</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/f27c3f4a556fdd18bfafb9b270fddc9b12c8033a"><code>f27c3f4</code></a>
Fix --no-exit-code condition for
<code>isTreatConfigHintsAsErrors</code></li>
<li><a
href="https://github.com/webpro-nl/knip/commit/727f842709f2adf9fe7658b6ed1b66b11043d821"><code>727f842</code></a>
Some light housekeeping</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/53236b5f7dc12c2e7e561448c276a0168a6367fc"><code>53236b5</code></a>
Direct config hint title to stderr</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.12.1/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.46.0 to 0.48.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/5921a25e374e7ad233fddb06ac3151e2318bd6ca"><code>5921a25</code></a>
release(apps): oxlint v1.63.0 &amp;&amp; oxfmt v0.48.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/22109">#22109</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d82f698000b0626795545c7c54278097bb9af684"><code>d82f698</code></a>
release(apps): oxlint v1.62.0 &amp;&amp; oxfmt v0.47.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21838">#21838</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.48.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.61.0 to 1.63.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.63.0] - 2026-05-05</h2>
<h3>📚 Documentation</h3>
<ul>
<li>cacbc4a linter: Fix jest settings docs. (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22127">#22127</a>)
(connorshea)</li>
</ul>
<h2>[1.62.0] - 2026-04-27</h2>
<h3>🚀 Features</h3>
<ul>
<li>348f46c linter: Add <code>respectEslintDisableDirectives</code>
option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21384">#21384</a>)
(Christian Vuerings)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>8c425db linter: Allow string for jest version in config schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21649">#21649</a>)
(camc314)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/5921a25e374e7ad233fddb06ac3151e2318bd6ca"><code>5921a25</code></a>
release(apps): oxlint v1.63.0 &amp;&amp; oxfmt v0.48.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22109">#22109</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/cacbc4a9d8e1a9a7230255573704dd62e2e52fc6"><code>cacbc4a</code></a>
docs(linter): Fix jest settings docs. (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/22127">#22127</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d177595909fb9e3be6306335dba4046a94314cab"><code>d177595</code></a>
chore(linter): Update oxlint-tsgolint peer dependency to the latest
release. ...</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/d82f698000b0626795545c7c54278097bb9af684"><code>d82f698</code></a>
release(apps): oxlint v1.62.0 &amp;&amp; oxfmt v0.47.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21838">#21838</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/348f46cfc17780c4700114ea3f2c62ef2d9fcc7f"><code>348f46c</code></a>
feat(linter): add <code>respectEslintDisableDirectives</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21384">#21384</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/8c425db635bc935dd23e49c7a5695caf5b243b50"><code>8c425db</code></a>
fix(linter): allow string for jest version in config schema (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21649">#21649</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.63.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint-tsgolint` from 0.21.1 to 0.22.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v0.22.1</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: clarify <code>AGENTS.md</code> submodule guidance by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/909">oxc-project/tsgolint#909</a></li>
<li>feat(no-unsafe-enum-comparison): implement suggestion by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/910">oxc-project/tsgolint#910</a></li>
<li>feat(no-unnecessary-template-expression): implement fix by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/911">oxc-project/tsgolint#911</a></li>
<li>chore(deps): update dependency vitest to v4.1.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/912">oxc-project/tsgolint#912</a></li>
<li>chore(deps): update github-actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/913">oxc-project/tsgolint#913</a></li>
<li>fix(prefer-optional-chain): avoid access comparison false positive
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/914">oxc-project/tsgolint#914</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.22.0...v0.22.1">https://github.com/oxc-project/tsgolint/compare/v0.22.0...v0.22.1</a></p>
<h2>v0.22.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore: convert renovate config to json by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/893">oxc-project/tsgolint#893</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/895">oxc-project/tsgolint#895</a></li>
<li>ci: replace OXC_BOT_PAT with GitHub App tokens by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/894">oxc-project/tsgolint#894</a></li>
<li>ci: add security analysis workflow by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/898">oxc-project/tsgolint#898</a></li>
<li>chore(deps): update github-actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/899">oxc-project/tsgolint#899</a></li>
<li>chore(deps): update module github.com/dlclark/regexp2 to v1.12.0 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/900">oxc-project/tsgolint#900</a></li>
<li>chore(deps): update dependency typescript to v6.0.3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/901">oxc-project/tsgolint#901</a></li>
<li>ci: make security analysis required-check friendly by <a
href="https://github.com/Boshen"><code>@​Boshen</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/902">oxc-project/tsgolint#902</a></li>
<li>feat(require-await): implement suggestions by <a
href="https://github.com/younggglcy"><code>@​younggglcy</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/896">oxc-project/tsgolint#896</a></li>
<li>fix: add warning for unsupported tsgolint CLI entrypoint by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/903">oxc-project/tsgolint#903</a></li>
<li>fix: resolve ancestor tsconfig for excluded nearest config by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/904">oxc-project/tsgolint#904</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/905">oxc-project/tsgolint#905</a></li>
<li>fix: handle UTF-16 diagnostics by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/906">oxc-project/tsgolint#906</a></li>
<li>fix(no-useless-default-assignment): make default assignment removal
a suggestion by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/907">oxc-project/tsgolint#907</a></li>
<li>fix(no-unnecessary-type-arguments): preserve shadowed type arguments
by <a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/908">oxc-project/tsgolint#908</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.21.1...v0.22.0">https://github.com/oxc-project/tsgolint/compare/v0.21.1...v0.22.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/2b933a935b1f9ed66d28efd637fec50ed91c2d78"><code>2b933a9</code></a>
fix(prefer-optional-chain): avoid access comparison false positive (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/914">#914</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/f9cb483ad787829aa9b71bcde139562678481998"><code>f9cb483</code></a>
chore(deps): update github-actions (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/913">#913</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/10a7cc2579e9327b2a68c9c4774cebb10982bce2"><code>10a7cc2</code></a>
chore(deps): update dependency vitest to v4.1.5 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/912">#912</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/73c15a285b957cfc8dd2adc01037d36b6587e785"><code>73c15a2</code></a>
feat(no-unnecessary-template-expression): implement fix (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/911">#911</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/bfa426fecdbe25adaec9d4fe2a8c8e0d9cd2fc14"><code>bfa426f</code></a>
feat(no-unsafe-enum-comparison): implement suggestion (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/910">#910</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/5985b4bf3b276c6b68ff2470b4d2e680b89aa7a2"><code>5985b4b</code></a>
fix: clarify <code>AGENTS.md</code> submodule guidance (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/909">#909</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/42a817b2ac39c364e8b054d00bd1fb0947d0aa3a"><code>42a817b</code></a>
fix(no-unnecessary-type-arguments): preserve shadowed type arguments (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/908">#908</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/05314ff06fd61cdb772903b972d801cc5edd0076"><code>05314ff</code></a>
fix(no-useless-default-assignment): make default assignment removal a
suggest...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/3858f4d55e0057501cca916272647c4c5524d257"><code>3858f4d</code></a>
fix: handle UTF-16 diagnostics (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/906">#906</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/dbfba7b88374f27bec64dd9a2738f25ece136950"><code>dbfba7b</code></a>
chore: update typescript-go submodule (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/905">#905</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.21.1...v0.22.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.0.10 to 8.0.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.11</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.0.11/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.0.10...v8.0.11">8.0.11</a>
(2026-05-07)<!-- raw HTML omitted --></h2>
<h3>Features</h3>
<ul>
<li>update rolldown to 1.0.0-rc.18 (<a
href="https://redirect.github.com/vitejs/vite/issues/22360">#22360</a>)
(<a
href="https://github.com/vitejs/vite/commit/3f80524aa1fa40bfa831f1a1bf2641c3979ba396">3f80524</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22334">#22334</a>)
(<a
href="https://github.com/vitejs/vite/commit/672c96288fd5440bbecddc65551e713edeb8d403">672c962</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22382">#22382</a>)
(<a
href="https://github.com/vitejs/vite/commit/5c0cfcb83dde2c6e25b6c3215dd622956bf29631">5c0cfcb</a>)</li>
<li><strong>glob:</strong> align hmr matcher options with glob
enumeration (<a
href="https://redirect.github.com/vitejs/vite/issues/22306">#22306</a>)
(<a
href="https://github.com/vitejs/vite/commit/30028f94516fa06dd0212567373169b3b3f6e393">30028f9</a>)</li>
<li>make separate object instance for each environment (<a
href="https://redirect.github.com/vitejs/vite/issues/22276">#22276</a>)
(<a
href="https://github.com/vitejs/vite/commit/7c2aa3b40ba00ce1299e4f31932c7929f179a80a">7c2aa3b</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>create-vite:</strong> list react-compiler templates in
README (<a
href="https://redirect.github.com/vitejs/vite/issues/22347">#22347</a>)
(<a
href="https://github.com/vitejs/vite/commit/7c3a61f42da6445904e93f0e29e9a2a838fa684a">7c3a61f</a>)</li>
<li>explain mergeConfig skips null/undefined (<a
href="https://redirect.github.com/vitejs/vite/issues/22325">#22325</a>)
(<a
href="https://github.com/vitejs/vite/commit/2151f701dc98270c905c540b209fb6d23d53d3ad">2151f70</a>)</li>
<li>mention native config loader in CLI options (<a
href="https://redirect.github.com/vitejs/vite/issues/22348">#22348</a>)
(<a
href="https://github.com/vitejs/vite/commit/0420c5d37b6049476b6e6c16662be372575dd683">0420c5d</a>)</li>
<li>update evan's x handle (<a
href="https://github.com/vitejs/vite/commit/640202a2167b0c19b94e4d3b8ff87309ae1f44d0">640202a</a>)</li>
</ul>
<h3>Miscellaneous Chores</h3>
<ul>
<li><strong>deps:</strong> update dependency tsdown to ^0.21.10 (<a
href="https://redirect.github.com/vitejs/vite/issues/22333">#22333</a>)
(<a
href="https://github.com/vitejs/vite/commit/3b51e050214c5a817c163838ab8643fe34c7d0c3">3b51e05</a>)</li>
<li><strong>deps:</strong> update rolldown-related dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22383">#22383</a>)
(<a
href="https://github.com/vitejs/vite/commit/555ff36de70a43b3b3dc22f958bf78fe75e11d67">555ff36</a>)</li>
<li><strong>deps:</strong> update transitive packages to fix npm audit
alerts (<a
href="https://redirect.github.com/vitejs/vite/issues/22316">#22316</a>)
(<a
href="https://github.com/vitejs/vite/commit/86aee6268aa879d74f68a890392c1dee973ebf05">86aee62</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>devtools integration (<a
href="https://redirect.github.com/vitejs/vite/issues/22312">#22312</a>)
(<a
href="https://github.com/vitejs/vite/commit/3c8bf064ec76e311f2d8be3a37dcfdcdd4e4253c">3c8bf06</a>)</li>
<li>remove unnecessary async (<a
href="https://redirect.github.com/vitejs/vite/issues/22296">#22296</a>)
(<a
href="https://github.com/vitejs/vite/commit/b31fd355d93eb166573362bd09c07745b9f76755">b31fd35</a>)</li>
<li>show direct path type in bad character warning (<a
href="https://redirect.github.com/vitejs/vite/issues/22339">#22339</a>)
(<a
href="https://github.com/vitejs/vite/commit/0c162e96a6545c93808e7338b9adeca2636596fa">0c162e9</a>)</li>
</ul>
<h3>Tests</h3>
<ul>
<li><strong>create-vite:</strong> use short help alias (<a
href="https://redirect.github.com/vitejs/vite/issues/22389">#22389</a>)
(<a
href="https://github.com/vitejs/vite/commit/994ab66bc4dc872278d8353d710ffc4bbd881f8d">994ab66</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/66f3194aa8e59924562575f0a98e7f4ae0acdd89"><code>66f3194</code></a>
release: v8.0.11</li>
<li><a
href="https://github.com/vitejs/vite/commit/5c0cfcb83dde2c6e25b6c3215dd622956bf29631"><code>5c0cfcb</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22382">#22382</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/555ff36de70a43b3b3dc22f958bf78fe75e11d67"><code>555ff36</code></a>
chore(deps): update rolldown-related dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22383">#22383</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/b31fd355d93eb166573362bd09c07745b9f76755"><code>b31fd35</code></a>
refactor: remove unnecessary async (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22296">#22296</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/3c8bf064ec76e311f2d8be3a37dcfdcdd4e4253c"><code>3c8bf06</code></a>
refactor: devtools integration (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22312">#22312</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/7c2aa3b40ba00ce1299e4f31932c7929f179a80a"><code>7c2aa3b</code></a>
fix: make separate object instance for each environment (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22276">#22276</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/3f80524aa1fa40bfa831f1a1bf2641c3979ba396"><code>3f80524</code></a>
feat: update rolldown to 1.0.0-rc.18 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22360">#22360</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/0c162e96a6545c93808e7338b9adeca2636596fa"><code>0c162e9</code></a>
refactor: show direct path type in bad character warning (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22339">#22339</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/672c96288fd5440bbecddc65551e713edeb8d403"><code>672c962</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22334">#22334</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/30028f94516fa06dd0212567373169b3b3f6e393"><code>30028f9</code></a>
fix(glob): align hmr matcher options with glob enumeration (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22306">#22306</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite/commits/v8.0.11/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex <25013571+alexhb1@users.noreply.github.com>
2026-05-08 12:02:57 +01:00
dependabot[bot] 84c8142b24 Bump the python-deps group across 1 directory with 5 updates (#954)
Bumps the python-deps group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [authlib](https://github.com/authlib/authlib) | `1.7.0` | `1.7.2` |
| [apprise](https://github.com/caronc/apprise) | `1.9.9` | `1.10.0` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.48.2` | `4.48.4` |
| [prek](https://github.com/j178/prek) | `0.3.10` | `0.3.13` |
| [ruff](https://github.com/astral-sh/ruff) | `0.15.11` | `0.15.12` |


Updates `authlib` from 1.7.0 to 1.7.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/authlib/authlib/releases">authlib's
releases</a>.</em></p>
<blockquote>
<h2>v1.7.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix the readme links by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/886">authlib/authlib#886</a></li>
<li>Allow non-recommended algorithms in ClientSecretJWT and PrivateKey
by <a href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/887">authlib/authlib#887</a></li>
<li>Validate BCP47 language tags with a regex by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/873">authlib/authlib#873</a></li>
<li>Fix RFC7523 signing with non RSA keys by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/884">authlib/authlib#884</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.7.1...v1.7.2">https://github.com/authlib/authlib/compare/v1.7.1...v1.7.2</a></p>
<h2>v1.7.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix authlib.jose deprecation warning poping from _joserfc_helpers by
<a href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/881">authlib/authlib#881</a></li>
<li>Fix redirecting to unvalidated <code>redirect_uri</code> on
<code>InvalidScopeError</code> in <code>OpenIDImplicitGrant</code> and
<code>OpenIDHybridGrant</code>.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.7.0...v1.7.1">https://github.com/authlib/authlib/compare/v1.7.0...v1.7.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/authlib/authlib/commit/a0b76fac3fa114d7759af2010546bfc332364b63"><code>a0b76fa</code></a>
chore: bump to 1.7.2</li>
<li><a
href="https://github.com/authlib/authlib/commit/c85c7f2b02faf2667f62b27aa60df042dbc9b4ab"><code>c85c7f2</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/884">#884</a>
from azmeuk/852-rfc7523-key-import</li>
<li><a
href="https://github.com/authlib/authlib/commit/a3b2adda43b4452ba9f384d224f95848974b4eb4"><code>a3b2add</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/873">#873</a>
from azmeuk/bcp47</li>
<li><a
href="https://github.com/authlib/authlib/commit/f2578eaa198aedbaaaf3bb00eccc451e15e45e3a"><code>f2578ea</code></a>
fix: Import RSAKey in auth.py for additional key support</li>
<li><a
href="https://github.com/authlib/authlib/commit/b57182cf46a53da19623208dd852270ddec8ebcc"><code>b57182c</code></a>
fix: fallback support RSAKey when client_secret is text</li>
<li><a
href="https://github.com/authlib/authlib/commit/4e7590292ca9f948a0766640b27025618750e6c1"><code>4e75902</code></a>
Merge branch 'main' into 852-rfc7523-key-import</li>
<li><a
href="https://github.com/authlib/authlib/commit/5eb4a860600ea2f3acc1a2a9c3e621a430da9d0f"><code>5eb4a86</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/887">#887</a>
from azmeuk/883-alg</li>
<li><a
href="https://github.com/authlib/authlib/commit/5633f37c47bd8352b962f982cb916bc8b95bb5d5"><code>5633f37</code></a>
fix: allow non-recommended algorithms in ClientSecretJWT and
PrivateKeyJWT</li>
<li><a
href="https://github.com/authlib/authlib/commit/4c8e7b381aaef68f60e2323a25ba96cdb346f82f"><code>4c8e7b3</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/886">#886</a>
from azmeuk/885-readme</li>
<li><a
href="https://github.com/authlib/authlib/commit/23b333e48a17ebf9f032a0e0f9eb3f990a06f97b"><code>23b333e</code></a>
docs: fix the readme links</li>
<li>Additional commits viewable in <a
href="https://github.com/authlib/authlib/compare/v1.7.0...v1.7.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `apprise` from 1.9.9 to 1.10.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/caronc/apprise/releases">apprise's
releases</a>.</em></p>
<blockquote>
<h2>v1.10.0</h2>
<h2>What's Changed</h2>
<p>The big wow factor of this release would be the huge effort put into
Matrix E2EE built into Apprise without adding overhead to the plugin
itself. Huge props to those that helped out. Other than that, a few more
services have been added (137 supported now 🚀 ).</p>
<p>The official documentation website (<a
href="https://appriseit.com">https://appriseit.com</a>) got a nice
cleanup; the Service listings are now searchable; some nice tweaks to
the URL Builder as well.</p>
<h3>📣 New Notification Services:</h3>
<ul>
<li>Opsgenie functionality ported to jira:// in <a
href="https://redirect.github.com/caronc/apprise/pull/1273">caronc/apprise#1273</a></li>
<li>Evolution API (WhatsApp) notification plugin by <a
href="https://github.com/opastorello"><code>@​opastorello</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1579">caronc/apprise#1579</a></li>
<li>Added blink(1) support in <a
href="https://redirect.github.com/caronc/apprise/pull/1578">caronc/apprise#1578</a></li>
<li>Exotel Support in <a
href="https://redirect.github.com/caronc/apprise/pull/782">caronc/apprise#782</a></li>
<li>Added Octopush Support in <a
href="https://redirect.github.com/caronc/apprise/pull/622">caronc/apprise#622</a></li>
<li>Added Postmark support in <a
href="https://redirect.github.com/caronc/apprise/pull/1590">caronc/apprise#1590</a></li>
</ul>
<h3>🐞  Bugfixes</h3>
<ul>
<li>ntfy:// tags= changed to xtags= in <a
href="https://redirect.github.com/caronc/apprise/pull/1555">caronc/apprise#1555</a>
<ul>
<li>this allows tags to work again correctly for those dependant on it;
previously <code>tags=</code> conflicted with <code>tags=</code> in
Apprise)</li>
</ul>
</li>
<li>XMPP server hostname can differentiate to what is found in JID in <a
href="https://redirect.github.com/caronc/apprise/pull/1560">caronc/apprise#1560</a></li>
<li>fixed issue with mailto:// when using yahoo.com in <a
href="https://redirect.github.com/caronc/apprise/pull/1561">caronc/apprise#1561</a></li>
<li>Fluxer time dependant unittest assertion optimized for slower
systems in <a
href="https://redirect.github.com/caronc/apprise/pull/1566">caronc/apprise#1566</a></li>
<li>fixed templating references impacting url generation (on <a
href="https://appriseit.com">https://appriseit.com</a>) in <a
href="https://redirect.github.com/caronc/apprise/pull/1582">caronc/apprise#1582</a></li>
<li>fixed KeyError Exception thrown when certain emoji's specified in <a
href="https://redirect.github.com/caronc/apprise/pull/1592">caronc/apprise#1592</a></li>
</ul>
<h3>💡 Features</h3>
<ul>
<li>Migrate the Dot. (Quote/0) plugin from API v1 to API v2 by <a
href="https://github.com/HerbertGao"><code>@​HerbertGao</code></a> in <a
href="https://redirect.github.com/caronc/apprise/pull/1512">caronc/apprise#1512</a>
<ul>
<li>Updated Dot. plugin to better align with Apprise in <a
href="https://redirect.github.com/caronc/apprise/pull/1588">caronc/apprise#1588</a></li>
</ul>
</li>
<li>URLs that can not be loaded are more verbose for the reasoning in <a
href="https://redirect.github.com/caronc/apprise/pull/1568">caronc/apprise#1568</a></li>
<li>Webex wxteams:// Bot API Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1567">caronc/apprise#1567</a></li>
<li>fixes parse_url() -&gt; url() -&gt; parse_url() inconsistency in <a
href="https://redirect.github.com/caronc/apprise/pull/1572">caronc/apprise#1572</a></li>
<li>Pushover Delivery Group Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1563">caronc/apprise#1563</a></li>
<li>Matrix token template cleanup in <a
href="https://redirect.github.com/caronc/apprise/pull/1573">caronc/apprise#1573</a></li>
<li>fcm:// add apns-push-type header for reliable iOS delivery by <a
href="https://github.com/AlbertoLanaro"><code>@​AlbertoLanaro</code></a>
in <a
href="https://redirect.github.com/caronc/apprise/pull/1577">caronc/apprise#1577</a></li>
<li>Home Assistant &quot;Service' Notification Support Added (extension
to what was already there) in <a
href="https://redirect.github.com/caronc/apprise/pull/1294">caronc/apprise#1294</a></li>
<li>Added attachment support to Mattermost in <a
href="https://redirect.github.com/caronc/apprise/pull/1583">caronc/apprise#1583</a></li>
<li>🔥 Matrix E2EE Support in <a
href="https://redirect.github.com/caronc/apprise/pull/1574">caronc/apprise#1574</a></li>
<li>Matrix Hookshot support added in <a
href="https://redirect.github.com/caronc/apprise/pull/1586">caronc/apprise#1586</a></li>
<li>Mastodon supports hashtag/user references in <a
href="https://redirect.github.com/caronc/apprise/pull/1587">caronc/apprise#1587</a></li>
<li>PushPlus refactored to support more options in <a
href="https://redirect.github.com/caronc/apprise/pull/1589">caronc/apprise#1589</a></li>
<li>Inproved azure:// error handling and message responses in <a
href="https://redirect.github.com/caronc/apprise/pull/1499">caronc/apprise#1499</a></li>
</ul>
<h3>❤️ Life-Cycle Support</h3>
<ul>
<li>Update LoC badge by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/caronc/apprise/pull/1554">caronc/apprise#1554</a></li>
<li>Memory-Optimized Plugin Management in <a
href="https://redirect.github.com/caronc/apprise/pull/1557">caronc/apprise#1557</a></li>
<li>Ruff linter configuration updated and applied to entire codebase in
<a
href="https://redirect.github.com/caronc/apprise/pull/1562">caronc/apprise#1562</a></li>
<li>i18n(pt_BR): add Brazilian Portuguese translation by <a
href="https://github.com/opastorello"><code>@​opastorello</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1580">caronc/apprise#1580</a></li>
<li>i18n(es): add Spanish translation by <a
href="https://github.com/opastorello"><code>@​opastorello</code></a> in
<a
href="https://redirect.github.com/caronc/apprise/pull/1581">caronc/apprise#1581</a></li>
</ul>
<h2>Installation</h2>
<p>Apprise is available <a href="https://pypi.org/project/apprise/">on
PyPI</a> through <em>pip</em>:</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/caronc/apprise/commit/343c960969477b60df580f70294ce966bb4b0ce2"><code>343c960</code></a>
bummped version to v1.10.0</li>
<li><a
href="https://github.com/caronc/apprise/commit/67b523077173bcf8c717b0e567b7d2e7251d21e1"><code>67b5230</code></a>
Inproved azure:// error handling and message responses (<a
href="https://redirect.github.com/caronc/apprise/issues/1499">#1499</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/755f17479ff20fd9473e1aa15ab1b190920041c3"><code>755f174</code></a>
bugfix: KeyError Exception thrown when certain emoji's specified (<a
href="https://redirect.github.com/caronc/apprise/issues/1592">#1592</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/a7bc56dd81ea60b1c9f59775d1e005e560a716b9"><code>a7bc56d</code></a>
PushPlus refactored to support more options (<a
href="https://redirect.github.com/caronc/apprise/issues/1589">#1589</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/9d0056b9cd4771bc752d4ff2936a1e4977e3fa81"><code>9d0056b</code></a>
Added Postmark support (<a
href="https://redirect.github.com/caronc/apprise/issues/1590">#1590</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/0617ef7ac63cc6f1e850913c055e280043360358"><code>0617ef7</code></a>
Updated Dot. plugin to better align with Apprise standards (<a
href="https://redirect.github.com/caronc/apprise/issues/1588">#1588</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/0fbe0946869fab49c330d6fd5fb89ea58cb9b6db"><code>0fbe094</code></a>
Added Octopush Support (<a
href="https://redirect.github.com/caronc/apprise/issues/622">#622</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/58d0f1e00a5e4daac928372d1b49a2886e7589f2"><code>58d0f1e</code></a>
Exotel Support (<a
href="https://redirect.github.com/caronc/apprise/issues/782">#782</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/2a8d62fad5dc1930d8f14e0775341692ff0c5aa5"><code>2a8d62f</code></a>
Mastodon supports hashtag/user references (<a
href="https://redirect.github.com/caronc/apprise/issues/1587">#1587</a>)</li>
<li><a
href="https://github.com/caronc/apprise/commit/1382633788004b515240c0f17c5b0cfe0f111554"><code>1382633</code></a>
Matrix Hookshot support added (<a
href="https://redirect.github.com/caronc/apprise/issues/1586">#1586</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/caronc/apprise/compare/v1.9.9...v1.10.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.48.2 to 4.48.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>4.48.4 - CDP Mode: Patch 104</h2>
<h2>CDP Mode: Patch 104</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a756d91999539497c8215aff59f520da7ed14633">Update
CDP Mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0e8b32f9b894cbbac546256f33630b16b08be49a">Update
CDP Mode examples</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>CDP Mode: Patch 104 by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4339">seleniumbase/SeleniumBase#4339</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.3...v4.48.4">https://github.com/seleniumbase/SeleniumBase/compare/v4.48.3...v4.48.4</a></p>
<h2>4.48.3 - Update config and dependencies</h2>
<h2>Update config and dependencies</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e5b2ffde2a9131f9e813cd97c430219648cd48e7">Update
default config in Chrome</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/163ef1b5b955df2b3daa201ca5652bb613ee1af9">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Update config and dependencies by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4338">seleniumbase/SeleniumBase#4338</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.2...v4.48.3">https://github.com/seleniumbase/SeleniumBase/compare/v4.48.2...v4.48.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9ae2c55abae90b0402e019eca3a32bf5ee81c4f8"><code>9ae2c55</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4339">#4339</a>
from seleniumbase/cdp-mode-patch-104</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/854529fb1ecefd9a3c6c1cbdc3f21b2a00efb68d"><code>854529f</code></a>
Version 4.48.4</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/0e8b32f9b894cbbac546256f33630b16b08be49a"><code>0e8b32f</code></a>
Update CDP Mode examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a756d91999539497c8215aff59f520da7ed14633"><code>a756d91</code></a>
Update CDP Mode</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7e07f81ff31ab592debfe5333d4480c9025f1cdd"><code>7e07f81</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4338">#4338</a>
from seleniumbase/update-config-and-dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/dbf29799515f5d414396199514e6f082decf4c6d"><code>dbf2979</code></a>
Version 4.48.3</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/163ef1b5b955df2b3daa201ca5652bb613ee1af9"><code>163ef1b</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/e5b2ffde2a9131f9e813cd97c430219648cd48e7"><code>e5b2ffd</code></a>
Update default config in Chrome</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/ac638ca1b1a999430ed503eb9bfc87584af5e830"><code>ac638ca</code></a>
Update examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2fe80fe4fcba890ae28c46026a8b36a3b864e03c"><code>2fe80fe</code></a>
Update CDP Mode examples</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.2...v4.48.4">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.3.10 to 0.3.13
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.3.13</h2>
<h2>Release Notes</h2>
<p>Released on 2026-05-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>Respect hook filters for message files (<a
href="https://redirect.github.com/j178/prek/pull/2049">#2049</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add Godot Engine to users in README (<a
href="https://redirect.github.com/j178/prek/pull/2047">#2047</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a href="https://github.com/Calinou"><code>@​Calinou</code></a></li>
</ul>
<h2>Install prek 0.3.13</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.3.13/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.3.13/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<pre lang="sh"><code>brew install prek
</code></pre>
<h2>Download prek 0.3.13</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-apple-darwin.tar.gz">prek-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-x86_64-apple-darwin.tar.gz">prek-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-pc-windows-msvc.zip">prek-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-i686-pc-windows-msvc.zip">prek-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-x86_64-pc-windows-msvc.zip">prek-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-unknown-linux-gnu.tar.gz">prek-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-i686-unknown-linux-gnu.tar.gz">prek-i686-unknown-linux-gnu.tar.gz</a></td>
<td>x86 Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-riscv64gc-unknown-linux-gnu.tar.gz">prek-riscv64gc-unknown-linux-gnu.tar.gz</a></td>
<td>RISCV Linux</td>
<td><a
href="https://github.com/j178/prek/releases/download/v0.3.13/prek-riscv64gc-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.3.13</h2>
<p>Released on 2026-05-06.</p>
<h3>Bug fixes</h3>
<ul>
<li>Respect hook filters for message files (<a
href="https://redirect.github.com/j178/prek/pull/2049">#2049</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add Godot Engine to users in README (<a
href="https://redirect.github.com/j178/prek/pull/2047">#2047</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
<li><a href="https://github.com/Calinou"><code>@​Calinou</code></a></li>
</ul>
<h2>0.3.12</h2>
<p>Released on 2026-05-05.</p>
<h3>Highlights</h3>
<p><code>auto_update.cooldown_days</code> is now available in both the
user-level global
config (<code>~/.config/prek/prek.toml</code> on Linux and macOS, or
<code>$XDG_CONFIG_HOME/prek/prek.toml</code> when set;
<code>%APPDATA%\prek\prek.toml</code> on
Windows) and project config. Set a user default for <code>prek
auto-update</code>, then
override it per project when a repository needs a different update
cadence.</p>
<pre lang="toml"><code>[auto_update]
cooldown_days = 7
</code></pre>
<h3>Enhancements</h3>
<ul>
<li>Add global auto-update cooldown config (<a
href="https://redirect.github.com/j178/prek/pull/2041">#2041</a>)</li>
<li>Add project auto-update cooldown config (<a
href="https://redirect.github.com/j178/prek/pull/2044">#2044</a>)</li>
<li>Support <code>language: dart</code> (<a
href="https://redirect.github.com/j178/prek/pull/1146">#1146</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Pass commit message file to workspace hooks (<a
href="https://redirect.github.com/j178/prek/pull/2043">#2043</a>)</li>
<li>Preserve non-UTF8 filenames from git (<a
href="https://redirect.github.com/j178/prek/pull/2023">#2023</a>)</li>
<li>ruby: put resolved Ruby's bin dir on <code>$PATH</code> for
<code>gem</code> invocations (<a
href="https://redirect.github.com/j178/prek/pull/2021">#2021</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Update docs with the new logo and icon (<a
href="https://redirect.github.com/j178/prek/pull/2025">#2025</a>)</li>
<li>Point schema docs to SchemaStore (<a
href="https://redirect.github.com/j178/prek/pull/2039">#2039</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/81b290ef0630d1e130dc37ae1916da0e51b8a002"><code>81b290e</code></a>
Bump version to 0.3.13 (<a
href="https://redirect.github.com/j178/prek/issues/2050">#2050</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3f5e5c6e54bdd9b1640228cdd69a449e18ddf9f8"><code>3f5e5c6</code></a>
Respect hook filters for message files (<a
href="https://redirect.github.com/j178/prek/issues/2049">#2049</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1fab88775affde4fd0c75b2f9102a5df88195efc"><code>1fab887</code></a>
Add Godot Engine to users in README (<a
href="https://redirect.github.com/j178/prek/issues/2047">#2047</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/93a71e0b730d30d2fa56f9e47f2a293beb007988"><code>93a71e0</code></a>
Remove deleted <code>dist/post/index.cjs</code> from publish prek
version workflow (<a
href="https://redirect.github.com/j178/prek/issues/2046">#2046</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/56d6d0c13ef36a4ab6a705621fba41448f2b503d"><code>56d6d0c</code></a>
Bump version to 0.3.12 (<a
href="https://redirect.github.com/j178/prek/issues/2045">#2045</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/5f94f6f8ea8e5df0fb6604b4b8ec63072e1dc8f3"><code>5f94f6f</code></a>
Add project auto-update cooldown config (<a
href="https://redirect.github.com/j178/prek/issues/2044">#2044</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c52833e9991584d03bcd7e2b6fc01fa43e1f0d09"><code>c52833e</code></a>
Add global auto-update cooldown</li>
<li><a
href="https://github.com/j178/prek/commit/8af3054dc690fd06fe91b2b0c0ca4fe8e4418051"><code>8af3054</code></a>
Pass commit message file to workspace hooks (<a
href="https://redirect.github.com/j178/prek/issues/2043">#2043</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1bf54f5fa9638ad66a7d0b160170da75de1eec81"><code>1bf54f5</code></a>
Update Rust crate serde-saphyr to 0.0.25 (<a
href="https://redirect.github.com/j178/prek/issues/2036">#2036</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/8c9761a523bcb180ff35fcfcd8e85184f87eaceb"><code>8c9761a</code></a>
Bump rand to 0.9.4 (<a
href="https://redirect.github.com/j178/prek/issues/2040">#2040</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.3.10...v0.3.13">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.11 to 0.15.12
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.12</h2>
<h2>Release Notes</h2>
<p>Released on 2026-04-24.</p>
<h3>Preview features</h3>
<ul>
<li>Implement <code>#ruff:file-ignore</code> file-level suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23599">#23599</a>)</li>
<li>Implement <code>#ruff:ignore</code> logical-line suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23404">#23404</a>)</li>
<li>Revert preview changes to displayed diagnostic severity in LSP (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24789">#24789</a>)</li>
<li>[<code>airflow</code>] Implement
<code>task-branch-as-short-circuit</code> (<code>AIR004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23579">#23579</a>)</li>
<li>[<code>flake8-bugbear</code>] Fix
<code>break</code>/<code>continue</code> handling in
<code>loop-iterator-mutation</code> (<code>B909</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24440">#24440</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLC2701</code> for type parameter
scopes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24576">#24576</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pandas-vet</code>] Suggest <code>.array</code> as well in
<code>PD011</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24805">#24805</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Respect default Unix permissions for cache files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24794">#24794</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>pylint</code>] Fix <code>PLR0124</code> description not to
claim self-comparison always returns the same value (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24749">#24749</a>)</li>
<li>[<code>pyupgrade</code>] Expand docs on reusable
<code>TypeVar</code>s and scoping (<code>UP046</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24153">#24153</a>)</li>
<li>Improve rules table accessibility (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24711">#24711</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dylwil3"><code>@​dylwil3</code></a></li>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
<li><a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a></li>
<li><a
href="https://github.com/avasis-ai"><code>@​avasis-ai</code></a></li>
<li><a href="https://github.com/Dev-iL"><code>@​Dev-iL</code></a></li>
<li><a
href="https://github.com/denyszhak"><code>@​denyszhak</code></a></li>
<li><a
href="https://github.com/ShipItAndPray"><code>@​ShipItAndPray</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/augustelalande"><code>@​augustelalande</code></a></li>
<li><a
href="https://github.com/amyreese"><code>@​amyreese</code></a></li>
<li><a
href="https://github.com/majiayu000"><code>@​majiayu000</code></a></li>
</ul>
<h2>Install ruff 0.15.12</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.15.12/ruff-installer.sh
| sh
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.12</h2>
<p>Released on 2026-04-24.</p>
<h3>Preview features</h3>
<ul>
<li>Implement <code>#ruff:file-ignore</code> file-level suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23599">#23599</a>)</li>
<li>Implement <code>#ruff:ignore</code> logical-line suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23404">#23404</a>)</li>
<li>Revert preview changes to displayed diagnostic severity in LSP (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24789">#24789</a>)</li>
<li>[<code>airflow</code>] Implement
<code>task-branch-as-short-circuit</code> (<code>AIR004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/23579">#23579</a>)</li>
<li>[<code>flake8-bugbear</code>] Fix
<code>break</code>/<code>continue</code> handling in
<code>loop-iterator-mutation</code> (<code>B909</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24440">#24440</a>)</li>
<li>[<code>pylint</code>] Fix <code>PLC2701</code> for type parameter
scopes (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24576">#24576</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pandas-vet</code>] Suggest <code>.array</code> as well in
<code>PD011</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24805">#24805</a>)</li>
</ul>
<h3>CLI</h3>
<ul>
<li>Respect default Unix permissions for cache files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24794">#24794</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>pylint</code>] Fix <code>PLR0124</code> description not to
claim self-comparison always returns the same value (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24749">#24749</a>)</li>
<li>[<code>pyupgrade</code>] Expand docs on reusable
<code>TypeVar</code>s and scoping (<code>UP046</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24153">#24153</a>)</li>
<li>Improve rules table accessibility (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24711">#24711</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a href="https://github.com/dylwil3"><code>@​dylwil3</code></a></li>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
<li><a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a></li>
<li><a
href="https://github.com/avasis-ai"><code>@​avasis-ai</code></a></li>
<li><a href="https://github.com/Dev-iL"><code>@​Dev-iL</code></a></li>
<li><a
href="https://github.com/denyszhak"><code>@​denyszhak</code></a></li>
<li><a
href="https://github.com/ShipItAndPray"><code>@​ShipItAndPray</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/augustelalande"><code>@​augustelalande</code></a></li>
<li><a
href="https://github.com/amyreese"><code>@​amyreese</code></a></li>
<li><a
href="https://github.com/majiayu000"><code>@​majiayu000</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/66f93cf7ed4d36325f35a452e4afa28268fbcd28"><code>66f93cf</code></a>
Bump 0.15.12 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24815">#24815</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/476a4d02e8e3b6c157ac39979d8b698a1b6baa91"><code>476a4d0</code></a>
[ty] Complete support for more detailed diagnostics on possibly unbound
error...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ed669eab30095d6c51fe6cdef6050fb01276bcb3"><code>ed669ea</code></a>
Implement <code>#ruff:file-ignore</code> file-level suppressions (<a
href="https://redirect.github.com/astral-sh/ruff/issues/23599">#23599</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e73d952e43feb51356ee740c5a973fce81396ff6"><code>e73d952</code></a>
[ty] Include inferred type in <code>invalid-key</code> concise
diagnostic for union/inte...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/80feb29b31cd98c093316df2e0407b0c70c01b55"><code>80feb29</code></a>
[ty] report only dead annotation-only locals as unused (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24811">#24811</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/0fbf2bc27336a3d17d39af52cf89b78dcda8c7c8"><code>0fbf2bc</code></a>
Drop deprecated license classifier (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24808">#24808</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/43b174cc7f2fcb0080bb1d4843cd4bf6b72bbe27"><code>43b174c</code></a>
[ty] Infer lambda parameter types with <code>Callable</code> type
context (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24317">#24317</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/4f449ae4a2377569330a5ab94799d389357b5a3f"><code>4f449ae</code></a>
[ty] Add error context for intersection types (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24772">#24772</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/5b4e753acb46e96ad408e4904c15308e33efe307"><code>5b4e753</code></a>
[ty] Add support for goto in literal enum member inlay hint (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24792">#24792</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e7cc76275a758ce1c636ea1c2d091fd576aac794"><code>e7cc762</code></a>
[ty] Add error context for TypedDict assignments (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24790">#24790</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.11...0.15.12">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 11:29:07 +01:00
dependabot[bot] 9bd7eae2b5 Bump github/codeql-action from 4.35.2 to 4.35.4 in the gh-actions group (#952)
Bumps the gh-actions group with 1 update:
[github/codeql-action](https://github.com/github/codeql-action).

Updates `github/codeql-action` from 4.35.2 to 4.35.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.35.4</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>v4.35.3</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.19.3 and earlier. These versions of
CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise
Server 3.15, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li>
<li>Configurations for private registries that use Cloudsmith or GCP
OIDC are now accepted. <a
href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li>
<li>Best-effort connection tests for private registries now use
<code>GET</code> requests instead of <code>HEAD</code> for better
compatibility with various registry implementations. For NuGet feeds,
the test is now always performed against the service index. <a
href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li>
<li>Fixed a bug where two diagnostics produced within the same
millisecond could overwrite each other on disk, causing one of them to
be lost. <a
href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<ul>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4">2.25.4</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3881">#3881</a></li>
</ul>
<h2>4.35.3 - 01 May 2026</h2>
<ul>
<li><em>Upcoming breaking change</em>: Add a deprecation warning for
customers using CodeQL version 2.19.3 and earlier. These versions of
CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise
Server 3.15, and will be unsupported by the next minor release of the
CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3837">#3837</a></li>
<li>Configurations for private registries that use Cloudsmith or GCP
OIDC are now accepted. <a
href="https://redirect.github.com/github/codeql-action/pull/3850">#3850</a></li>
<li>Best-effort connection tests for private registries now use
<code>GET</code> requests instead of <code>HEAD</code> for better
compatibility with various registry implementations. For NuGet feeds,
the test is now always performed against the service index. <a
href="https://redirect.github.com/github/codeql-action/pull/3853">#3853</a></li>
<li>Fixed a bug where two diagnostics produced within the same
millisecond could overwrite each other on disk, causing one of them to
be lost. <a
href="https://redirect.github.com/github/codeql-action/pull/3852">#3852</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3">2.25.3</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3865">#3865</a></li>
</ul>
<h2>4.35.2 - 15 Apr 2026</h2>
<ul>
<li>The undocumented TRAP cache cleanup feature that could be enabled
using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment
variable is deprecated and will be removed in May 2026. If you are
affected by this, we recommend disabling TRAP caching by passing the
<code>trap-caching: false</code> input to the <code>init</code> Action.
<a
href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li>
<li>The Git version 2.36.0 requirement for improved incremental analysis
now only applies to repositories that contain submodules. <a
href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li>
<li>Python analysis on GHES no longer extracts the standard library,
relying instead on models of the standard library. This should result in
significantly faster extraction and analysis times, while the effect on
alerts should be minimal. <a
href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li>
<li>Fixed a bug in the validation of OIDC configurations for private
registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li>
</ul>
<h2>4.35.1 - 27 Mar 2026</h2>
<ul>
<li>Fix incorrect minimum required Git version for <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a>: it should have been 2.36.0, not 2.11.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3781">#3781</a></li>
</ul>
<h2>4.35.0 - 27 Mar 2026</h2>
<ul>
<li>Reduced the minimum Git version required for <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> from 2.38.0 to 2.11.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3767">#3767</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1">2.25.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3773">#3773</a></li>
</ul>
<h2>4.34.1 - 20 Mar 2026</h2>
<ul>
<li>Downgrade default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a>
due to issues with a small percentage of Actions and JavaScript
analyses. <a
href="https://redirect.github.com/github/codeql-action/pull/3762">#3762</a></li>
</ul>
<h2>4.34.0 - 20 Mar 2026</h2>
<ul>
<li>Added an experimental change which disables TRAP caching when <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> is enabled, since improved incremental analysis
supersedes TRAP caching. This will improve performance and reduce
Actions cache usage. We expect to roll this change out to everyone in
March. <a
href="https://redirect.github.com/github/codeql-action/pull/3569">#3569</a></li>
<li>We are rolling out improved incremental analysis to C/C++ analyses
that use build mode <code>none</code>. We expect this rollout to be
complete by the end of April 2026. <a
href="https://redirect.github.com/github/codeql-action/pull/3584">#3584</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0">2.25.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3585">#3585</a></li>
</ul>
<h2>4.33.0 - 16 Mar 2026</h2>
<ul>
<li>
<p>Upcoming change: Starting April 2026, the CodeQL Action will skip
collecting file coverage information on pull requests to improve
analysis performance. File coverage information will still be computed
on non-PR analyses. Pull request analyses will log a warning about this
upcoming change. <a
href="https://redirect.github.com/github/codeql-action/pull/3562">#3562</a></p>
<p>To opt out of this change:</p>
<ul>
<li><strong>Repositories owned by an organization:</strong> Create a
custom repository property with the name
<code>github-codeql-file-coverage-on-prs</code> and the type
&quot;True/false&quot;, then set this property to <code>true</code> in
the repository's settings. For more information, see <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">Managing
custom properties for repositories in your organization</a>.
Alternatively, if you are using an advanced setup workflow, you can set
the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable
to <code>true</code> in your workflow.</li>
<li><strong>User-owned repositories using default setup:</strong> Switch
to an advanced setup workflow and set the
<code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable to
<code>true</code> in your workflow.</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/68bde559dea0fdcac2102bfdf6230c5f70eb485e"><code>68bde55</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3885">#3885</a>
from github/update-v4.35.4-803d9e8c3</li>
<li><a
href="https://github.com/github/codeql-action/commit/9739ad2d182c072da0d01a6887f7f39620f71b1e"><code>9739ad2</code></a>
Update changelog for v4.35.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/803d9e8c3ca8b0dd2029a1da3b541a18b6bfb076"><code>803d9e8</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3883">#3883</a>
from github/mbg/test/macro-wrapper</li>
<li><a
href="https://github.com/github/codeql-action/commit/0fd9c7d1358a7404e46ed8165f12262f56bd1434"><code>0fd9c7d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3882">#3882</a>
from github/dependabot/github_actions/dot-github/wor...</li>
<li><a
href="https://github.com/github/codeql-action/commit/922d6fb888d665134eb982b150b8912dbd48e21a"><code>922d6fb</code></a>
Use <code>makeMacro</code> instead of <code>test.macro</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/df77e87896689b5c736433984c5df14d86c63d56"><code>df77e87</code></a>
Update test macro snippet</li>
<li><a
href="https://github.com/github/codeql-action/commit/6e3f985e4fc409a188c7701b68c4dec158c9ced3"><code>6e3f985</code></a>
Add wrapper for <code>test.macro</code></li>
<li><a
href="https://github.com/github/codeql-action/commit/e7a347dfb1bfb7a858347623fcb4f650effca6b5"><code>e7a347d</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3881">#3881</a>
from github/update-bundle/codeql-bundle-v2.25.4</li>
<li><a
href="https://github.com/github/codeql-action/commit/17eabb2500031486a71e00ecbcb72c73804a6c9f"><code>17eabb2</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/aaef09c48db2dd7f0100363de1785963a34cd706"><code>aaef09c</code></a>
Bump ruby/setup-ruby</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/95e58e9a2cdfd71adc6e0353d5c52f41a045d225...68bde559dea0fdcac2102bfdf6230c5f70eb485e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=4.35.2&new-version=4.35.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 11:28:53 +01:00
Alex d6590be551 Add seedtime preferences toggle + clean up logic (#959)
Clears up seedtime logic to use user-specified seedtime only, ignore the
indexer-defaults.
Adds a toggle to enable the seedtime feature, disabled by default. 

Fixes #955
2026-05-08 11:24:50 +01:00
Alex 4c782ca92d Fix Google Books search cache failures (#958)
Recognises google error 503s as invalid results and does not add to
results cache.

Fixes #945
2026-05-08 11:17:57 +01:00
Alex b10a5a35ca Fix FUSE copy fallback (#957)
Fixes #949
2026-05-08 11:17:49 +01:00
Alex 196578fb18 Fix: Prowlarr seedtime priority (#946) 2026-05-04 14:25:05 +01:00
Alex ba62771a53 Add tor network access and bypass rules (#944) 2026-05-03 12:42:37 +01:00
Alex 7a2de1ccdd Fix SSRF access (#943) 2026-05-03 10:47:06 +01:00
Alex 4881adc19f Fix tor error retry (#941) 2026-05-01 19:30:32 +01:00
Alex ee54033d23 Fix entrypoint handling on Unraid (#939) 2026-05-01 18:41:43 +01:00
Alex 3554d01c81 Change path default for audiobooks + description fixes (#933) 2026-04-30 18:20:05 +01:00
Alex 9dd445f2af Revert image size streaming (#932) 2026-04-30 17:07:43 +01:00
Alex 4e41b1a8ec fix: hardcover author search (#929)
- Re-adds author search suggestions for Hardcover
- Correctly routes author queries to correct ID or best match
author-filtered book query.
2026-04-29 19:10:37 +01:00
Alex c7619488cd fix: re-add cwa db immutable (#928)
Fixes #926
2026-04-29 18:34:28 +01:00
Alex eba04115ae Fix internal bypasser and /home directory (#919)
- Fixed internal bypasser startup with newer Chromium/SeleniumBase by
isolating the browser helper from Gunicorn/gevent, serialising helper
failures cleanly, and cleaning up orphan processes after a failure
- Stopped using /app as runtime home state, now moved to /home/shelfmark
or /tmp/shelfmark/home as fallback.
- Added tests
2026-04-26 15:01:54 +01:00
dependabot[bot] 26bba25777 Bump the python-deps group across 1 directory with 6 updates (#900)
Bumps the python-deps group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [authlib](https://github.com/authlib/authlib) | `1.6.9` | `1.7.0` |
| [seleniumbase](https://github.com/seleniumbase/SeleniumBase) |
`4.47.9` | `4.48.2` |
| [basedpyright](https://github.com/detachhead/basedpyright) | `1.39.0`
| `1.39.3` |
| [prek](https://github.com/j178/prek) | `0.3.8` | `0.3.10` |
| [ruff](https://github.com/astral-sh/ruff) | `0.15.10` | `0.15.11` |


Updates `authlib` from 1.6.9 to 1.7.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/authlib/authlib/releases">authlib's
releases</a>.</em></p>
<blockquote>
<h2>v1.7.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Authorization and token endpoints request empty scope parameter
management by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/847">authlib/authlib#847</a></li>
<li>Support from Python 3.10 to 3.14 by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/850">authlib/authlib#850</a></li>
<li>Allow composition of AuthorizationServerMetadata by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/853">authlib/authlib#853</a></li>
<li>Make require_oauth parenthesis optional by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/855">authlib/authlib#855</a></li>
<li>Fix <code>expires_at</code> behavior when its value is 0 by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/854">authlib/authlib#854</a></li>
<li>Migration to joserfc by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/852">authlib/authlib#852</a></li>
<li>RP-initiated logout by <a
href="https://github.com/frohrlich"><code>@​frohrlich</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/849">authlib/authlib#849</a></li>
<li>Fix <code>get_jwt_config</code> by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/858">authlib/authlib#858</a></li>
<li>chore(ci): Update PyPy version from 3.10 to 3.11 by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/863">authlib/authlib#863</a></li>
<li>fix: remove &quot;none&quot; from default authlib.jose.jwt
algorithms by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/860">authlib/authlib#860</a></li>
<li>fix: normalize resolve_client_public_key method by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/861">authlib/authlib#861</a></li>
<li>Implement rfc9700 PKCE downgrade countermeasure by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/864">authlib/authlib#864</a></li>
<li>Use correct syntax for tox.requires in tox.ini by <a
href="https://github.com/alex-ball"><code>@​alex-ball</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/868">authlib/authlib#868</a></li>
<li>Set client session User-Agent when fetching server metadata and JWKs
by <a href="https://github.com/alex-ball"><code>@​alex-ball</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/867">authlib/authlib#867</a></li>
<li>fix: use the real application object for Flask by <a
href="https://github.com/nblock"><code>@​nblock</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/869">authlib/authlib#869</a></li>
<li>Accept the issuer URL as a valid audience by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/865">authlib/authlib#865</a></li>
<li>Don't nest InvalidTokenError extra attribute by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/872">authlib/authlib#872</a></li>
<li>Documentation overhaul by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/875">authlib/authlib#875</a></li>
<li>Update README.md docs.authlib.org/en/latest =&gt;
docs.authlib.org/en/stable by <a
href="https://github.com/guillett"><code>@​guillett</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/876">authlib/authlib#876</a></li>
<li>Merge release/1.6 branch by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/877">authlib/authlib#877</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/frohrlich"><code>@​frohrlich</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/849">authlib/authlib#849</a></li>
<li><a href="https://github.com/cclauss"><code>@​cclauss</code></a> made
their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/863">authlib/authlib#863</a></li>
<li><a href="https://github.com/alex-ball"><code>@​alex-ball</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/868">authlib/authlib#868</a></li>
<li><a href="https://github.com/nblock"><code>@​nblock</code></a> made
their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/869">authlib/authlib#869</a></li>
<li><a href="https://github.com/guillett"><code>@​guillett</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/876">authlib/authlib#876</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.6.10...v1.7.0">https://github.com/authlib/authlib/compare/v1.6.10...v1.7.0</a></p>
<h2>v1.6.11</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.6.10...v1.6.11">https://github.com/authlib/authlib/compare/v1.6.10...v1.6.11</a></p>
<ul>
<li>Fix CSRF issue with starlette client</li>
</ul>
<h2>v1.6.10</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.6.9...v1.6.10">https://github.com/authlib/authlib/compare/v1.6.9...v1.6.10</a></p>
<ul>
<li>Fix redirecting to unvalidated <code>redirect_uri</code> on
<code>UnsupportedResponseTypeError</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/authlib/authlib/commit/5d2e603ec5f10bd2c4bf20e2495c076370d65b74"><code>5d2e603</code></a>
chore: release 1.7.0</li>
<li><a
href="https://github.com/authlib/authlib/commit/767f08bb80ad6635beb7b54ad98ee9494b84bc26"><code>767f08b</code></a>
fix: CSRF issue with starlette client</li>
<li><a
href="https://github.com/authlib/authlib/commit/e9aaef33933717e1bb5cf77a2cc1ceeb4c948620"><code>e9aaef3</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/877">#877</a>
from authlib/merge/1.6</li>
<li><a
href="https://github.com/authlib/authlib/commit/3c8ec9a8895ce3f7c588a9c3bf8e48cdf0c5b2c3"><code>3c8ec9a</code></a>
Merge branch 'main' into merge/1.6</li>
<li><a
href="https://github.com/authlib/authlib/commit/ef09aebbba4439dedb22bd15777d1b3458b6f0ab"><code>ef09aeb</code></a>
chore: release 1.6.10</li>
<li><a
href="https://github.com/authlib/authlib/commit/3be08468201a7766a93012ce149ea12822cab096"><code>3be0846</code></a>
fix: redirecting to unvalidated redirect_uri on
UnsupportedResponseTypeError</li>
<li><a
href="https://github.com/authlib/authlib/commit/4cf6f9792c56a5d598d1525af6384380cdccc4ec"><code>4cf6f97</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/876">#876</a>
from guillett/patch-1</li>
<li><a
href="https://github.com/authlib/authlib/commit/23f67b440ca4e2283139b6a57b3c979dbb3c4a50"><code>23f67b4</code></a>
Update README.md docs.authlib.org/en/latest =&gt;
docs.authlib.org/en/stable</li>
<li><a
href="https://github.com/authlib/authlib/commit/10401635d06f59aa282d3367b38dba73574a9127"><code>1040163</code></a>
chore: prek autoupdate</li>
<li><a
href="https://github.com/authlib/authlib/commit/491209fb393c829cb38aebecd614f612191286b2"><code>491209f</code></a>
Merge pull request <a
href="https://redirect.github.com/authlib/authlib/issues/875">#875</a>
from azmeuk/doc</li>
<li>Additional commits viewable in <a
href="https://github.com/authlib/authlib/compare/v1.6.9...v1.7.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `seleniumbase` from 4.47.9 to 4.48.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seleniumbase/SeleniumBase/releases">seleniumbase's
releases</a>.</em></p>
<blockquote>
<h2>Fix unzip in powershell</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2bc7763221c6a0726010caf49476a2f5e87413d7">Fix
unzip in powershell for paths that contain spaces</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b0518dc2bbd3bf28f659a310cec12ef6e07cb4f9">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Fix unzip in powershell by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4330">seleniumbase/SeleniumBase#4330</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.1...v4.48.2">https://github.com/seleniumbase/SeleniumBase/compare/v4.48.1...v4.48.2</a></p>
<h2>4.48.1 - Browser config updates</h2>
<h2>Browser config updates</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bfb94e2fbdceea6e34f9f56297ee44eac9045c25">Update
default config for Chrome and Edge</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/77ea8fcb8c7bc355aa3b9e1a225b5545a90e4431">Refresh
Python dependencies</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Browser config updates by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4323">seleniumbase/SeleniumBase#4323</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.48.0...v4.48.1">https://github.com/seleniumbase/SeleniumBase/compare/v4.48.0...v4.48.1</a></p>
<h2>4.48.0 - Selenium and CDP updates</h2>
<h2>Selenium and CDP updates</h2>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/8123a0e674f507629264b178afa4ba9585776056">Update
CDP Mode</a>
--&gt; <code>solve_captcha()</code> now supports &quot;Friendly
Captcha&quot;
--&gt; <code>nest-asyncio</code> is patched from within to avoid
deprecation warnings on Python 3.14</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/657c7231e62ab19deef514ac002995211b7ab814">Refresh
Python dependencies</a>
--&gt; Includes a <code>selenium</code> upgrade</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9cc818b48e0cea0718421eff2dbb6ca8f924aed2">Add
an example that bypasses &quot;Friendly Captcha&quot;</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/afef6b86e848cdd699f03fe2fa4078c9893ff10d">Add
Stealthy Playwright examples for BrowserScan</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/184f079229055b845c514596ef08e284995e9823">Warn
when await is missing from async method calls</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7abc5e4f0f746bf979730a514fc2854ddb5f10fd">Support
&quot;Friendly Captcha&quot; solving in async mode</a></li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/7d0f56963af0baf69b09c1975b6b0c95b2e6855f">Add
async example of solving &quot;Friendly Captcha&quot;</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Selenium and CDP updates by <a
href="https://github.com/mdmintz"><code>@​mdmintz</code></a> in <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/pull/4319">seleniumbase/SeleniumBase#4319</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.47.9...v4.48.0">https://github.com/seleniumbase/SeleniumBase/compare/v4.47.9...v4.48.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a9605aea13b4498a8b60065a23201dae80413316"><code>a9605ae</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4330">#4330</a>
from seleniumbase/fix-unzip-in-powershell</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/3a38776ea74d463b4f605753962137401d1ce847"><code>3a38776</code></a>
Version 4.48.2</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/b0518dc2bbd3bf28f659a310cec12ef6e07cb4f9"><code>b0518dc</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/2bc7763221c6a0726010caf49476a2f5e87413d7"><code>2bc7763</code></a>
Fix unzip in powershell for paths that contain spaces</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a0aceea5080a14342fdf90919383f407d314f618"><code>a0aceea</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4323">#4323</a>
from seleniumbase/browser-config-updates</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/9dc951b431e0faab1c586e70adf9ba92a26ad721"><code>9dc951b</code></a>
Version 4.48.1</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/77ea8fcb8c7bc355aa3b9e1a225b5545a90e4431"><code>77ea8fc</code></a>
Refresh Python dependencies</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/bfb94e2fbdceea6e34f9f56297ee44eac9045c25"><code>bfb94e2</code></a>
Update default config for Chrome and Edge</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/a381c354bb1cbef92466d75cadfccd7b2f8a6cb1"><code>a381c35</code></a>
Update documentation in migration examples</li>
<li><a
href="https://github.com/seleniumbase/SeleniumBase/commit/377c3d218e5e688ddbb04aae9ebd71685e6725bf"><code>377c3d2</code></a>
Merge pull request <a
href="https://redirect.github.com/seleniumbase/SeleniumBase/issues/4319">#4319</a>
from seleniumbase/selenium-and-cdp-updates</li>
<li>Additional commits viewable in <a
href="https://github.com/seleniumbase/SeleniumBase/compare/v4.47.9...v4.48.2">compare
view</a></li>
</ul>
</details>
<br />

Updates `basedpyright` from 1.39.0 to 1.39.3
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/5f6672701c5b6a739563894256418845239be2a2"><code>5f66727</code></a>
1.39.3</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/d8741dfc88be16e11c66cceff78e6e2634ddf49b"><code>d8741df</code></a>
hopefully fix docs deployment job</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/ceb200c192bb53629b4c62fdc082ec27b108f316"><code>ceb200c</code></a>
1.39.2</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/eb7a92cacd2697acb4e36e2f3147333588c88fa7"><code>eb7a92c</code></a>
try to fix browser-basedpyright being published with nothing in it</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/dec5306e9aabbce3f9b1b9ec283981d92dd43d80"><code>dec5306</code></a>
update package-lock.json</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/6db43de5dda601e3cd83998c669c4ecbbfde26f6"><code>6db43de</code></a>
1.39.1</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/335e48619fa223fe3be0b6560d746a10934509c8"><code>335e486</code></a>
fix failing tests from merge</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/bbe71b686e84ebbff7699d35dab3376d411bb99d"><code>bbe71b6</code></a>
delete newly added github action from upstream that we don't use</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/8f2261891e8ceb278963e84658ebaf054b88e559"><code>8f22618</code></a>
update prettierignore</li>
<li><a
href="https://github.com/DetachHead/basedpyright/commit/ff1f5a4af835b14927545c8890b303f48553acac"><code>ff1f5a4</code></a>
fix compile errors from merge</li>
<li>Additional commits viewable in <a
href="https://github.com/detachhead/basedpyright/compare/v1.39.0...v1.39.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `prek` from 0.3.8 to 0.3.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">prek's
releases</a>.</em></p>
<blockquote>
<h2>0.3.10</h2>
<h2>Release Notes</h2>
<p>Released on 2026-04-21.</p>
<h3>Enhancements</h3>
<ul>
<li>Disallow rev for non-remote repos in schema (<a
href="https://redirect.github.com/j178/prek/pull/1964">#1964</a>)</li>
<li>Hide up-to-date output in non-verbose mode (<a
href="https://redirect.github.com/j178/prek/pull/1942">#1942</a>)</li>
<li>Improve merge conflict marker detection (<a
href="https://redirect.github.com/j178/prek/pull/1937">#1937</a>)</li>
<li>Keep finished hooks visible (<a
href="https://redirect.github.com/j178/prek/pull/1967">#1967</a>)</li>
<li>Preserve frozen comment spacing in auto-update (<a
href="https://redirect.github.com/j178/prek/pull/1945">#1945</a>)</li>
<li>Reimplement <code>@j178/prek</code> npm package (<a
href="https://redirect.github.com/j178/prek/pull/1973">#1973</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Prefer stable Rust toolchains (<a
href="https://redirect.github.com/j178/prek/pull/1974">#1974</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add <code>SKILL.md</code> for prek (<a
href="https://redirect.github.com/j178/prek/pull/1950">#1950</a>)</li>
<li>Document <code>gh skill install j178/prek prek</code> to install
prek skill for agents (<a
href="https://redirect.github.com/j178/prek/pull/1951">#1951</a>)</li>
<li>Improve compatibility and migration docs (<a
href="https://redirect.github.com/j178/prek/pull/1940">#1940</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Sync latest identify tags (<a
href="https://redirect.github.com/j178/prek/pull/1947">#1947</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/github-actions"><code>@​github-actions</code></a></li>
<li><a
href="https://github.com/renovate"><code>@​renovate</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>Install prek 0.3.10</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://github.com/j178/prek/releases/download/v0.3.10/prek-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://github.com/j178/prek/releases/download/v0.3.10/prek-installer.ps1
| iex&quot;
</code></pre>
<h3>Install prebuilt binaries via Homebrew</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.3.10</h2>
<p>Released on 2026-04-21.</p>
<h3>Enhancements</h3>
<ul>
<li>Disallow rev for non-remote repos in schema (<a
href="https://redirect.github.com/j178/prek/pull/1964">#1964</a>)</li>
<li>Hide up-to-date output in non-verbose mode (<a
href="https://redirect.github.com/j178/prek/pull/1942">#1942</a>)</li>
<li>Improve merge conflict marker detection (<a
href="https://redirect.github.com/j178/prek/pull/1937">#1937</a>)</li>
<li>Keep finished hooks visible (<a
href="https://redirect.github.com/j178/prek/pull/1967">#1967</a>)</li>
<li>Preserve frozen comment spacing in auto-update (<a
href="https://redirect.github.com/j178/prek/pull/1945">#1945</a>)</li>
<li>Reimplement <code>@j178/prek</code> npm package (<a
href="https://redirect.github.com/j178/prek/pull/1973">#1973</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Prefer stable Rust toolchains (<a
href="https://redirect.github.com/j178/prek/pull/1974">#1974</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Add <code>SKILL.md</code> for prek (<a
href="https://redirect.github.com/j178/prek/pull/1950">#1950</a>)</li>
<li>Document <code>gh skill install j178/prek prek</code> to install
prek skill for agents (<a
href="https://redirect.github.com/j178/prek/pull/1951">#1951</a>)</li>
<li>Improve compatibility and migration docs (<a
href="https://redirect.github.com/j178/prek/pull/1940">#1940</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Sync latest identify tags (<a
href="https://redirect.github.com/j178/prek/pull/1947">#1947</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/github-actions"><code>@​github-actions</code></a></li>
<li><a
href="https://github.com/renovate"><code>@​renovate</code></a></li>
<li><a href="https://github.com/j178"><code>@​j178</code></a></li>
</ul>
<h2>0.3.9</h2>
<p>Released on 2026-04-13.</p>
<h3>Highlight</h3>
<p><code>prek auto-update</code> is now stricter about pinned revisions
and more useful in CI.
It now keeps <code>rev</code> and <code># frozen:</code> comments in
sync, can detect
<a href="https://docs.zizmor.sh/audits/#impostor-commit">impostor
commits</a> when validating pinned SHAs,
and lets you use <code>prek auto-update --check</code> to fail on both
available updates and frozen-ref
mismatches without rewriting the config.</p>
<p>Examples:</p>
<pre lang="console"><code>$ prek auto-update
# updates revs and repairs stale `# frozen:` comments
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/1981c51f599ed9db4a428eae13e4a8baf0cb0427"><code>1981c51</code></a>
Bump version to 0.3.10</li>
<li><a
href="https://github.com/j178/prek/commit/ba745f6f407d43e70d2155c7929004a7701ca7e8"><code>ba745f6</code></a>
Prefer stable Rust toolchains (<a
href="https://redirect.github.com/j178/prek/issues/1974">#1974</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/b6c591dbbc4d9917e62b4b6c1dd65419cffeb464"><code>b6c591d</code></a>
Reimplement <code>@j178/prek</code> npm package (<a
href="https://redirect.github.com/j178/prek/issues/1973">#1973</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/fba1c85b1f2ce244e4b491ccaa0edffbdee01348"><code>fba1c85</code></a>
Keep finished hooks visible (<a
href="https://redirect.github.com/j178/prek/issues/1967">#1967</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/bce57a3415d688a9b9d893018348570b381023e3"><code>bce57a3</code></a>
Disallow rev for non-remote repos in schema (<a
href="https://redirect.github.com/j178/prek/issues/1964">#1964</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/afac10cf3ae355f6e2948c62ec25c54536bea40d"><code>afac10c</code></a>
Split <code>auto_update.rs</code> into modules (<a
href="https://redirect.github.com/j178/prek/issues/1962">#1962</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c3b9f115dabff92fde388c5edb091a10c00fb18f"><code>c3b9f11</code></a>
Update GitHub Actions (major) (<a
href="https://redirect.github.com/j178/prek/issues/1961">#1961</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6ca0443ecca17e8bc6df972740f445dd9795b4bd"><code>6ca0443</code></a>
Update Rust crate annotate-snippets to v0.12.15 (<a
href="https://redirect.github.com/j178/prek/issues/1955">#1955</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/776277e104a751634711821c10f871a95b5bcd70"><code>776277e</code></a>
Update Rust crate tokio to v1.51.1 (<a
href="https://redirect.github.com/j178/prek/issues/1957">#1957</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c2b445a722db49f6b0dfeee763c19944bc77e757"><code>c2b445a</code></a>
Update Rust crate toml_edit to v0.25.11 (<a
href="https://redirect.github.com/j178/prek/issues/1958">#1958</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.3.8...v0.3.10">compare
view</a></li>
</ul>
</details>
<br />

Updates `pytest` from 9.0.2 to 9.0.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest/releases">pytest's
releases</a>.</em></p>
<blockquote>
<h2>9.0.3</h2>
<h1>pytest 9.0.3 (2026-04-07)</h1>
<h2>Bug fixes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/12444">#12444</a>:
Fixed <code>pytest.approx</code> which now correctly takes into account
<code>~collections.abc.Mapping</code> keys order to compare them.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13634">#13634</a>:
Blocking a <code>conftest.py</code> file using the <code>-p no:</code>
option is now explicitly disallowed.</p>
<p>Previously this resulted in an internal assertion failure during
plugin loading.</p>
<p>Pytest now raises a clear <code>UsageError</code> explaining that
conftest files are not plugins and cannot be disabled via
<code>-p</code>.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13734">#13734</a>:
Fixed crash when a test raises an exceptiongroup with
<code>__tracebackhide__ = True</code>.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14195">#14195</a>:
Fixed an issue where non-string messages passed to <!-- raw HTML omitted
-->unittest.TestCase.subTest()<!-- raw HTML omitted --> were not
printed.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14343">#14343</a>:
Fixed use of insecure temporary directory (CVE-2025-71176).</p>
</li>
</ul>
<h2>Improved documentation</h2>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13388">#13388</a>:
Clarified documentation for <code>-p</code> vs
<code>PYTEST_PLUGINS</code> plugin loading and fixed an incorrect
<code>-p</code> example.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/13731">#13731</a>:
Clarified that capture fixtures (e.g. <code>capsys</code> and
<code>capfd</code>) take precedence over the <code>-s</code> /
<code>--capture=no</code> command-line options in <code>Accessing
captured output from a test function
&lt;accessing-captured-output&gt;</code>.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14088">#14088</a>:
Clarified that the default <code>pytest_collection</code> hook sets
<code>session.items</code> before it calls
<code>pytest_collection_finish</code>, not after.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest/issues/14255">#14255</a>:
TOML integer log levels must be quoted: Updating reference
documentation.</li>
</ul>
<h2>Contributor-facing changes</h2>
<ul>
<li>
<p><a
href="https://redirect.github.com/pytest-dev/pytest/issues/12689">#12689</a>:
The test reports are now published to Codecov from GitHub Actions.
The test statistics is visible <a
href="https://app.codecov.io/gh/pytest-dev/pytest/tests">on the web
interface</a>.</p>
<p>-- by <code>aleguy02</code></p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pytest-dev/pytest/commit/a7d58d7a21b78581e636bbbdea13c66ad1657c1e"><code>a7d58d7</code></a>
Prepare release version 9.0.3</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/089d98199c253d8f89a040243bc4f2aa6cd5ab22"><code>089d981</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14366">#14366</a>
from bluetech/revert-14193-backport</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/8127eaf4ab7f6b2fdd0dc1b38343ec97aeef05ac"><code>8127eaf</code></a>
Revert &quot;Fix: assertrepr_compare respects dict insertion order (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14050">#14050</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14193">#14193</a>)&quot;</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/99a7e6029e7a6e8d53e5df114b1346e035370241"><code>99a7e60</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14363">#14363</a>
from pytest-dev/patchback/backports/9.0.x/95d8423bd...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/ddee02a578da30dd43aedc39c1c1f1aaadfcee95"><code>ddee02a</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14343">#14343</a>
from bluetech/cve-2025-71176-simple</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/74eac6916fee34726cb194f16c516e96fbd29619"><code>74eac69</code></a>
doc: Update training info (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14298">#14298</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14301">#14301</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/f92dee777cfdb77d1c43633d02766ddf1f07c869"><code>f92dee7</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14267">#14267</a>
from pytest-dev/patchback/backports/9.0.x/d6fa26c62...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/7ee58acc8777c31ac6cf388d01addf5a414a7439"><code>7ee58ac</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/12378">#12378</a>
from Pierre-Sassoulas/fix-implicit-str-concat-and-d...</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/37da870d37e3a2f5177cae075c7b9ae279432bf8"><code>37da870</code></a>
Merge pull request <a
href="https://redirect.github.com/pytest-dev/pytest/issues/14259">#14259</a>
from mitre88/patch-4 (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14268">#14268</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest/commit/c34bfa3b7acb65b594707c714f1d8461b0304eed"><code>c34bfa3</code></a>
Add explanation for string context diffs (<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14257">#14257</a>)
(<a
href="https://redirect.github.com/pytest-dev/pytest/issues/14266">#14266</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest/compare/9.0.2...9.0.3">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.15.10 to 0.15.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.11</h2>
<h2>Release Notes</h2>
<p>Released on 2026-04-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Ignore <code>RUF029</code> when function is
decorated with <code>asynccontextmanager</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24642">#24642</a>)</li>
<li>[<code>airflow</code>] Implement
<code>airflow-xcom-pull-in-template-string</code> (<code>AIR201</code>)
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/23583">#23583</a>)</li>
<li>[<code>flake8-bandit</code>] Fix <code>S103</code> false positives
and negatives in mask analysis (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24424">#24424</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-async</code>] Omit overridden methods for
<code>ASYNC109</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24648">#24648</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>flake8-async</code>] Add override mention to
<code>ASYNC109</code> docs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24666">#24666</a>)</li>
<li>Update Neovim config examples to use <code>vim.lsp.config</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24577">#24577</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/augustelalande"><code>@​augustelalande</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/benberryallwood"><code>@​benberryallwood</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/Dev-iL"><code>@​Dev-iL</code></a></li>
</ul>
<h2>Install ruff 0.15.11</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-installer.ps1
| iex&quot;
</code></pre>
<h2>Download ruff 0.15.11</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/ruff/releases/download/0.15.11/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.11</h2>
<p>Released on 2026-04-16.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Ignore <code>RUF029</code> when function is
decorated with <code>asynccontextmanager</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24642">#24642</a>)</li>
<li>[<code>airflow</code>] Implement
<code>airflow-xcom-pull-in-template-string</code> (<code>AIR201</code>)
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/23583">#23583</a>)</li>
<li>[<code>flake8-bandit</code>] Fix <code>S103</code> false positives
and negatives in mask analysis (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24424">#24424</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-async</code>] Omit overridden methods for
<code>ASYNC109</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24648">#24648</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>[<code>flake8-async</code>] Add override mention to
<code>ASYNC109</code> docs (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24666">#24666</a>)</li>
<li>Update Neovim config examples to use <code>vim.lsp.config</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24577">#24577</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/augustelalande"><code>@​augustelalande</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/benberryallwood"><code>@​benberryallwood</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/Dev-iL"><code>@​Dev-iL</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/53554b1cfe837f2eb992a81794480699478f1116"><code>53554b1</code></a>
Bump 0.15.11 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24678">#24678</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/08c56c83cffbb1025cbf5bdede6c6d8be591cf47"><code>08c56c8</code></a>
Factor out the <code>mdtest</code> crate (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24616">#24616</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/725fbb736d2a999971449b61190b914abd26102a"><code>725fbb7</code></a>
[ty] Use partially qualified names when reporting diagnostics regarding
bad c...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ddd6a30ff5fa27694dc1c50d0749885a1519d0a7"><code>ddd6a30</code></a>
[ty] Do not suggest argument completion when at value of keyword
argument (<a
href="https://redirect.github.com/astral-sh/ruff/issues/2">#2</a>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/9282e61d482a36da08d66bb8271afeef50b3bc45"><code>9282e61</code></a>
Disallow <a
href="https://github.com/disjoint"><code>@​disjoint</code></a>_base on
TypedDicts and Protocols (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24671">#24671</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e9986d8e3008eefe2e387312c4dc8b9c60f6f362"><code>e9986d8</code></a>
[ty] Reject using properties with <code>Never</code> setters or deleters
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/24510">#24510</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/9cf212ff82f7b66b4a275ad6a9b1564aee1fa4a8"><code>9cf212f</code></a>
[ty] Normalize property setter and deleter wrappers (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24509">#24509</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/12a1589de4d7120cf99441ee4c14871bdc20968d"><code>12a1589</code></a>
Add override mention to ASYNC109 docs (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24666">#24666</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/dccb03d010f4442ed60624f8d2ba932706abaabb"><code>dccb03d</code></a>
[ty] Avoid panicking on overloaded <code>Callable</code> type context
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/24661">#24661</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/61f9a0a5763fb068cd2f26c0ee9d63a277fb26c2"><code>61f9a0a</code></a>
[ty] Sync vendored typeshed stubs (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24646">#24646</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.10...0.15.11">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-25 13:12:35 +01:00
dependabot[bot] 795887ae45 Bump the npm-deps group in /src/frontend with 8 updates (#914)
Bumps the npm-deps group in /src/frontend with 8 updates:

| Package | From | To |
| --- | --- | --- |
|
[@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite)
| `4.2.2` | `4.2.4` |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.14.1` | `7.14.2` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.4.1` | `6.6.2` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.45.0` | `0.46.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.60.0` | `1.61.0` |
|
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
| `4.2.2` | `4.2.4` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) |
`8.0.8` | `8.0.10` |
|
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
| `4.1.4` | `4.1.5` |

Updates `@tailwindcss/vite` from 4.2.2 to 4.2.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases"><code>@​tailwindcss/vite</code>'s
releases</a>.</em></p>
<blockquote>
<h2>v4.2.4</h2>
<h3>Fixed</h3>
<ul>
<li>Ensure imports in <code>@import</code> and <code>@plugin</code>
still resolve correctly when using Vite aliases in
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19947">#19947</a>)</li>
</ul>
<h2>v4.2.3</h2>
<h3>Fixed</h3>
<ul>
<li>Canonicalization: improve canonicalizations for
<code>tracking-*</code> utilities by preferring non-negative utilities
(e.g. <code>-tracking-tighter</code> → <code>tracking-wider</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19827">#19827</a>)</li>
<li>Fix crash due to invalid characters in candidate (exceeding valid
unicode code point range) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19829">#19829</a>)</li>
<li>Ensure query params in imports are considered unique resources when
using <code>@tailwindcss/webpack</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19723">#19723</a>)</li>
<li>Canonicalization: collapse arbitrary values into shorthand utilities
(e.g. <code>px-[1.2rem] py-[1.2rem]</code> → <code>p-[1.2rem]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19837">#19837</a>)</li>
<li>Canonicalization: collapse <code>border-{t,b}-*</code> into
<code>border-y-*</code>, <code>border-{l,r}-*</code> into
<code>border-x-*</code>, and <code>border-{t,r,b,l}-*</code> into
<code>border-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-m{t,b}-*</code> into
<code>scroll-my-*</code>, <code>scroll-m{l,r}-*</code> into
<code>scroll-mx-*</code>, and <code>scroll-m{t,r,b,l}-*</code> into
<code>scroll-m-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-p{t,b}-*</code> into
<code>scroll-py-*</code>, <code>scroll-p{l,r}-*</code> into
<code>scroll-px-*</code>, and <code>scroll-p{t,r,b,l}-*</code> into
<code>scroll-p-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overflow-{x,y}-*</code> into
<code>overflow-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overscroll-{x,y}-*</code> into
<code>overscroll-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Read from <code>--placeholder-color</code> instead of
<code>--background-color</code> for <code>placeholder-*</code> utilities
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19843">#19843</a>)</li>
<li>Upgrade: ensure files are not emptied out when killing the upgrade
process while it's running (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: use <code>config.content</code> when migrating from
Tailwind CSS v3 to Tailwind CSS v4 (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: never migrate files that are ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Add <code>.env</code> and <code>.env.*</code> to default ignored
content files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Canonicalization: migrate <code>overflow-ellipsis</code> into
<code>text-ellipsis</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>start-full</code> →
<code>inset-s-full</code>, <code>start-auto</code> →
<code>inset-s-auto</code>, <code>start-px</code> →
<code>inset-s-px</code>, and <code>start-&lt;number&gt;</code> →
<code>inset-s-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>end-full</code> →
<code>inset-e-full</code>, <code>end-auto</code> →
<code>inset-e-auto</code>, <code>end-px</code> →
<code>inset-e-px</code>, and <code>end-&lt;number&gt;</code> →
<code>inset-e-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: move the <code>-</code> sign inside the arbitrary
value <code>-left-[9rem]</code> → <code>left-[-9rem]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Canonicalization: move the <code>-</code> sign outside the arbitrary
value <code>ml-[calc(-1*var(--width))]</code> →
<code>-ml-(--width)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Improve performance when scanning JSONL / NDJSON files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19862">#19862</a>)</li>
<li>Support <code>NODE_PATH</code> environment variable in standalone
CLI (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19617">#19617</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md"><code>@​tailwindcss/vite</code>'s
changelog</a>.</em></p>
<blockquote>
<h2>[4.2.4] - 2026-04-21</h2>
<h3>Fixed</h3>
<ul>
<li>Ensure imports in <code>@import</code> and <code>@plugin</code>
still resolve correctly when using Vite aliases in
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19947">#19947</a>)</li>
</ul>
<h2>[4.2.3] - 2026-04-20</h2>
<h3>Fixed</h3>
<ul>
<li>Canonicalization: improve canonicalizations for
<code>tracking-*</code> utilities by preferring non-negative utilities
(e.g. <code>-tracking-tighter</code> → <code>tracking-wider</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19827">#19827</a>)</li>
<li>Fix crash due to invalid characters in candidate (exceeding valid
unicode code point range) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19829">#19829</a>)</li>
<li>Ensure query params in imports are considered unique resources when
using <code>@tailwindcss/webpack</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19723">#19723</a>)</li>
<li>Canonicalization: collapse arbitrary values into shorthand utilities
(e.g. <code>px-[1.2rem] py-[1.2rem]</code> → <code>p-[1.2rem]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19837">#19837</a>)</li>
<li>Canonicalization: collapse <code>border-{t,b}-*</code> into
<code>border-y-*</code>, <code>border-{l,r}-*</code> into
<code>border-x-*</code>, and <code>border-{t,r,b,l}-*</code> into
<code>border-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-m{t,b}-*</code> into
<code>scroll-my-*</code>, <code>scroll-m{l,r}-*</code> into
<code>scroll-mx-*</code>, and <code>scroll-m{t,r,b,l}-*</code> into
<code>scroll-m-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-p{t,b}-*</code> into
<code>scroll-py-*</code>, <code>scroll-p{l,r}-*</code> into
<code>scroll-px-*</code>, and <code>scroll-p{t,r,b,l}-*</code> into
<code>scroll-p-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overflow-{x,y}-*</code> into
<code>overflow-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overscroll-{x,y}-*</code> into
<code>overscroll-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Read from <code>--placeholder-color</code> instead of
<code>--background-color</code> for <code>placeholder-*</code> utilities
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19843">#19843</a>)</li>
<li>Upgrade: ensure files are not emptied out when killing the upgrade
process while it's running (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: use <code>config.content</code> when migrating from
Tailwind CSS v3 to Tailwind CSS v4 (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: never migrate files that are ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Add <code>.env</code> and <code>.env.*</code> to default ignored
content files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Canonicalization: migrate <code>overflow-ellipsis</code> into
<code>text-ellipsis</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>start-full</code> →
<code>inset-s-full</code>, <code>start-auto</code> →
<code>inset-s-auto</code>, <code>start-px</code> →
<code>inset-s-px</code>, and <code>start-&lt;number&gt;</code> →
<code>inset-s-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>end-full</code> →
<code>inset-e-full</code>, <code>end-auto</code> →
<code>inset-e-auto</code>, <code>end-px</code> →
<code>inset-e-px</code>, and <code>end-&lt;number&gt;</code> →
<code>inset-e-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: move the <code>-</code> sign inside the arbitrary
value <code>-left-[9rem]</code> → <code>left-[-9rem]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Canonicalization: move the <code>-</code> sign outside the arbitrary
value <code>ml-[calc(-1*var(--width))]</code> →
<code>-ml-(--width)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Improve performance when scanning JSONL / NDJSON files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19862">#19862</a>)</li>
<li>Support <code>NODE_PATH</code> environment variable in standalone
CLI (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19617">#19617</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/69ad7cc5ec091125842aba783c5bfce536e9c234"><code>69ad7cc</code></a>
4.2.4 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19948">#19948</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/685c19e266a6b75842747acab6fe7076e82df62d"><code>685c19e</code></a>
Fix issue around resolving paths in <code>@tailwindcss/vite</code> (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19947">#19947</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/2e3fa490a535a8341fd2853d75098f0d4dbcc825"><code>2e3fa49</code></a>
4.2.3 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19944">#19944</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/5cb1efdf416a6d37012d31cc1306c41cb35bbdc1"><code>5cb1efd</code></a>
fix(vite): resolve tsconfig paths in CSS and JS resolvers (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite/issues/19803">#19803</a>)</li>
<li>See full diff in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.2.4/packages/@tailwindcss-vite">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for <code>@​tailwindcss/vite</code> since your current
version.</p>
</details>
<br />

Updates `react-router-dom` from 7.14.1 to 7.14.2
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.14.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.14.2"><code>react-router@7.14.2</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/cf1d25003aa1217dc21c16e95d483601940ae9af"><code>cf1d250</code></a>
Release v7.14.2 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14993">#14993</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.14.2/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.4.1 to 6.6.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.6.2</h2>
<ul>
<li>Don't track typeof value refs at top of exported type alias (resolve
<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1697">#1697</a>)
(1a9904832878f5e8e4b633bdb08fb327baa17ed6)</li>
<li>Treat Props as used when Astro.props is referenced (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1629">#1629</a>)
(46cb33871b236249cf9b09679988d530a61a545f)</li>
<li>Update dependencies (dcf53157452b996f970d91d3149c4b7bb4f45edd)</li>
</ul>
<h2>Release 6.6.1</h2>
<ul>
<li>Fix website papercuts (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1696">#1696</a>)
(c6d9c436d4c0b85f8aae34bab1197e3c2b5eb139) - thanks <a
href="https://github.com/skoeva"><code>@​skoeva</code></a>!</li>
<li>fix(rslib): resolve entry points from rslib config (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1695">#1695</a>)
(af83d68d9856b3666af5111338f25dc2b4897cc7) - thanks <a
href="https://github.com/rpereira-anchor"><code>@​rpereira-anchor</code></a>!</li>
<li>Update react-email plugin for react-email@6 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1694">#1694</a>)
(200db55064811eba4a168598615417d36d77e3aa) - thanks <a
href="https://github.com/krystofspiller"><code>@​krystofspiller</code></a>!</li>
<li>Introduce Manifest wrapper with scriptNames + getMajor helpers
(6fded2f00f4e9cf8328231f9e30280d62c85e95d)</li>
</ul>
<h2>Release 6.6.0</h2>
<ul>
<li>picocolors → styleText
(e7abd6bb1a42c8997ae79555e55b7d9d19f56a48)</li>
<li><code>@​nodelib/fs</code>.walk → fdir
(6f781b84f9776d211c6fd1b0d9b280457701051a)</li>
<li>Improve performance, but only slightly
(c2c0323efd1a327936c4cdd65d335c913eb0e0ef)</li>
<li>Fix package-entry hint for bare specifier in main (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1693">#1693</a>)
(2e8cf477dada77b93c54a3717d4c21f3107f5f23)</li>
<li>Extract vite.resolve.alias from Astro config AST (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1692">#1692</a>)
(fab587198659cfc095e97699cf3a751034aa2160)</li>
<li>Add plugin-contributed source-map rules
(e11c2b1c02c7bf390f791e675fcdc3c7ec57a007)</li>
<li>Add <code>@sveltejs/package</code> plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1690">#1690</a>)
(8b2d402c9fff1a18e13512bfc08b5c3f9af891df)</li>
<li>Windows ❤️ (91964e428b44750ed0d03e3acf1560ba3ec1c202)</li>
</ul>
<h2>Release 6.5.0</h2>
<ul>
<li>Drop project-extension-redundant config hint (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1683">#1683</a>)
(f86092949d6dbd041fd621876da674fd3eac7534)</li>
<li>Add instructions to .agents/PLUGINS.md
(e2943ed8fb6d2c0ab4cf12ff04d10bd5ab9fd5f7)</li>
<li>Add a plugin for react-email (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1684">#1684</a>)
(d8ae4d3ccb810b9a9211fd43e9d1e7d7b704fcaf) - thanks <a
href="https://github.com/xaqrox"><code>@​xaqrox</code></a>!</li>
<li>Replace <code>fast-glob</code> with <code>tinyglobby</code> (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1462">#1462</a>)
(9f6b4c8aa6857fea40e66d008c905c948af10939) - thanks <a
href="https://github.com/gameroman"><code>@​gameroman</code></a>!</li>
<li>Added plugin for Serverless framework (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1478">#1478</a>)
(f885f1ded52427d984c67e7172e3141eb4e5ee29) - thanks <a
href="https://github.com/BenCrinion-IW"><code>@​BenCrinion-IW</code></a>!</li>
<li>Add args to Prettier plugin to resolve --config CLI flag (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1685">#1685</a>)
(f4658c84e714afd8a2233b72be6169da1ac3723e) - thanks <a
href="https://github.com/xaqrox"><code>@​xaqrox</code></a>!</li>
<li>fix(util): tolerate JSONC and array extends in findRootDirsBase (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1681">#1681</a>)
(f7e5464a6f70e9024a341fdb923766b5ff53a831) - thanks <a
href="https://github.com/Hoffs"><code>@​Hoffs</code></a>!</li>
<li>Format (15bd7e7a56b470096cfee1690263d5d13ddb8fb6)</li>
<li>Inherit outDir/rootDir from tsconfig project references (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1680">#1680</a>)
(b89b4f716f4c117b0106e9a212e9e5c46aa85035)</li>
<li>tsc → tsgo (a6e09ca1b65936b3790a6c3628a4646f030d18b8)</li>
<li>Update dependencies (4cb05c96a2ae7c790d29ee76ff13288c5bbb97a2)</li>
<li>Housekeep (28c56cb8bf68031b1c8e9bee75b18ee7274ec981)</li>
<li>Test test test (7eb4ab3a8a6635dcaf756bb2b4a88e1298615994)</li>
<li>Add pino plugin with <code>transportCall</code> visitor (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1480">#1480</a>)
(53a033e4ddc5036c6a4a0e55c0abc42c5c64e4f5)</li>
<li>Add signal to projects using knip
(dbedd665c1f8d735030600d3f68ef1825d9a2668)</li>
<li>Tune logos (3148f4d0485875370634b9b53c1b3aa7f6eafcc3)</li>
<li>Tweak <code>knip-run</code> tool response
(42940381a947c46996ae4055e8789f6ea39cfca4)</li>
<li>Add <code>workspace</code> option to <code>knip-run</code> tool
(64c4aaea89e3abb41d8695ebffc5538878520b21)</li>
<li>Remove old lingering <code>experimentalTags</code>
(e503d108e5535800ac6467f4d92c7dd6a9e90037)</li>
<li>Fix compiler type (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1689">#1689</a>)
(e7a69adb5e584eb6e5af9b4007820afcbcf27a08)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/2527ddddc25355407e298485435e7baf42998c94"><code>2527ddd</code></a>
Release knip@6.6.2</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/dcf53157452b996f970d91d3149c4b7bb4f45edd"><code>dcf5315</code></a>
Update dependencies</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/46cb33871b236249cf9b09679988d530a61a545f"><code>46cb338</code></a>
Treat Props as used when Astro.props is referenced (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1629">#1629</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/1a9904832878f5e8e4b633bdb08fb327baa17ed6"><code>1a99048</code></a>
Don't track typeof value refs at top of exported type alias (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1697">#1697</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/2b1b2d4ae4ca67ab42a5324deee463b61d3989f4"><code>2b1b2d4</code></a>
Release knip@6.6.1</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/6fded2f00f4e9cf8328231f9e30280d62c85e95d"><code>6fded2f</code></a>
Introduce Manifest wrapper with scriptNames + getMajor helpers</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/200db55064811eba4a168598615417d36d77e3aa"><code>200db55</code></a>
Update react-email plugin for react-email@6 (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1694">#1694</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/af83d68d9856b3666af5111338f25dc2b4897cc7"><code>af83d68</code></a>
fix(rslib): resolve entry points from rslib config (<a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1695">#1695</a>)</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/38a17d22c1bdc080fe38227dfbde04b902865e78"><code>38a17d2</code></a>
Release knip@6.6.0</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/91964e428b44750ed0d03e3acf1560ba3ec1c202"><code>91964e4</code></a>
Windows ❤️</li>
<li>Additional commits viewable in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.6.2/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.45.0 to 0.46.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this package will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0">Keep a Changelog</a>.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/f5bd1dd35f220976fb04b815b2a1d0dfbea82ccf"><code>f5bd1dd</code></a>
release(apps): oxlint v1.61.0 &amp;&amp; oxfmt v0.46.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21583">#21583</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.46.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.60.0 to 1.61.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.61.0] - 2026-04-20</h2>
<h3>🚀 Features</h3>
<ul>
<li>38d8090 linter/jest: Implemented jest <code>version</code> settings
in config file. (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21522">#21522</a>)
(Said Atrahouch)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/f5bd1dd35f220976fb04b815b2a1d0dfbea82ccf"><code>f5bd1dd</code></a>
release(apps): oxlint v1.61.0 &amp;&amp; oxfmt v0.46.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21583">#21583</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/38d809096e4fa1e6a46cf326a08845348b8b7d27"><code>38d8090</code></a>
feat(linter/jest): Implemented jest <code>version</code> settings in
config file. (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21522">#21522</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.61.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `tailwindcss` from 4.2.2 to 4.2.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/releases">tailwindcss's
releases</a>.</em></p>
<blockquote>
<h2>v4.2.4</h2>
<h3>Fixed</h3>
<ul>
<li>Ensure imports in <code>@import</code> and <code>@plugin</code>
still resolve correctly when using Vite aliases in
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19947">#19947</a>)</li>
</ul>
<h2>v4.2.3</h2>
<h3>Fixed</h3>
<ul>
<li>Canonicalization: improve canonicalizations for
<code>tracking-*</code> utilities by preferring non-negative utilities
(e.g. <code>-tracking-tighter</code> → <code>tracking-wider</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19827">#19827</a>)</li>
<li>Fix crash due to invalid characters in candidate (exceeding valid
unicode code point range) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19829">#19829</a>)</li>
<li>Ensure query params in imports are considered unique resources when
using <code>@tailwindcss/webpack</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19723">#19723</a>)</li>
<li>Canonicalization: collapse arbitrary values into shorthand utilities
(e.g. <code>px-[1.2rem] py-[1.2rem]</code> → <code>p-[1.2rem]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19837">#19837</a>)</li>
<li>Canonicalization: collapse <code>border-{t,b}-*</code> into
<code>border-y-*</code>, <code>border-{l,r}-*</code> into
<code>border-x-*</code>, and <code>border-{t,r,b,l}-*</code> into
<code>border-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-m{t,b}-*</code> into
<code>scroll-my-*</code>, <code>scroll-m{l,r}-*</code> into
<code>scroll-mx-*</code>, and <code>scroll-m{t,r,b,l}-*</code> into
<code>scroll-m-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-p{t,b}-*</code> into
<code>scroll-py-*</code>, <code>scroll-p{l,r}-*</code> into
<code>scroll-px-*</code>, and <code>scroll-p{t,r,b,l}-*</code> into
<code>scroll-p-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overflow-{x,y}-*</code> into
<code>overflow-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overscroll-{x,y}-*</code> into
<code>overscroll-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Read from <code>--placeholder-color</code> instead of
<code>--background-color</code> for <code>placeholder-*</code> utilities
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19843">#19843</a>)</li>
<li>Upgrade: ensure files are not emptied out when killing the upgrade
process while it's running (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: use <code>config.content</code> when migrating from
Tailwind CSS v3 to Tailwind CSS v4 (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: never migrate files that are ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Add <code>.env</code> and <code>.env.*</code> to default ignored
content files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Canonicalization: migrate <code>overflow-ellipsis</code> into
<code>text-ellipsis</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>start-full</code> →
<code>inset-s-full</code>, <code>start-auto</code> →
<code>inset-s-auto</code>, <code>start-px</code> →
<code>inset-s-px</code>, and <code>start-&lt;number&gt;</code> →
<code>inset-s-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>end-full</code> →
<code>inset-e-full</code>, <code>end-auto</code> →
<code>inset-e-auto</code>, <code>end-px</code> →
<code>inset-e-px</code>, and <code>end-&lt;number&gt;</code> →
<code>inset-e-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: move the <code>-</code> sign inside the arbitrary
value <code>-left-[9rem]</code> → <code>left-[-9rem]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Canonicalization: move the <code>-</code> sign outside the arbitrary
value <code>ml-[calc(-1*var(--width))]</code> →
<code>-ml-(--width)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Improve performance when scanning JSONL / NDJSON files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19862">#19862</a>)</li>
<li>Support <code>NODE_PATH</code> environment variable in standalone
CLI (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19617">#19617</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md">tailwindcss's
changelog</a>.</em></p>
<blockquote>
<h2>[4.2.4] - 2026-04-21</h2>
<h3>Fixed</h3>
<ul>
<li>Ensure imports in <code>@import</code> and <code>@plugin</code>
still resolve correctly when using Vite aliases in
<code>@tailwindcss/vite</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19947">#19947</a>)</li>
</ul>
<h2>[4.2.3] - 2026-04-20</h2>
<h3>Fixed</h3>
<ul>
<li>Canonicalization: improve canonicalizations for
<code>tracking-*</code> utilities by preferring non-negative utilities
(e.g. <code>-tracking-tighter</code> → <code>tracking-wider</code>) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19827">#19827</a>)</li>
<li>Fix crash due to invalid characters in candidate (exceeding valid
unicode code point range) (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19829">#19829</a>)</li>
<li>Ensure query params in imports are considered unique resources when
using <code>@tailwindcss/webpack</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19723">#19723</a>)</li>
<li>Canonicalization: collapse arbitrary values into shorthand utilities
(e.g. <code>px-[1.2rem] py-[1.2rem]</code> → <code>p-[1.2rem]</code>)
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19837">#19837</a>)</li>
<li>Canonicalization: collapse <code>border-{t,b}-*</code> into
<code>border-y-*</code>, <code>border-{l,r}-*</code> into
<code>border-x-*</code>, and <code>border-{t,r,b,l}-*</code> into
<code>border-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-m{t,b}-*</code> into
<code>scroll-my-*</code>, <code>scroll-m{l,r}-*</code> into
<code>scroll-mx-*</code>, and <code>scroll-m{t,r,b,l}-*</code> into
<code>scroll-m-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>scroll-p{t,b}-*</code> into
<code>scroll-py-*</code>, <code>scroll-p{l,r}-*</code> into
<code>scroll-px-*</code>, and <code>scroll-p{t,r,b,l}-*</code> into
<code>scroll-p-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overflow-{x,y}-*</code> into
<code>overflow-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Canonicalization: collapse <code>overscroll-{x,y}-*</code> into
<code>overscroll-*</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19842">#19842</a>)</li>
<li>Read from <code>--placeholder-color</code> instead of
<code>--background-color</code> for <code>placeholder-*</code> utilities
(<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19843">#19843</a>)</li>
<li>Upgrade: ensure files are not emptied out when killing the upgrade
process while it's running (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: use <code>config.content</code> when migrating from
Tailwind CSS v3 to Tailwind CSS v4 (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Upgrade: never migrate files that are ignored by git (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Add <code>.env</code> and <code>.env.*</code> to default ignored
content files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19846">#19846</a>)</li>
<li>Canonicalization: migrate <code>overflow-ellipsis</code> into
<code>text-ellipsis</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>start-full</code> →
<code>inset-s-full</code>, <code>start-auto</code> →
<code>inset-s-auto</code>, <code>start-px</code> →
<code>inset-s-px</code>, and <code>start-&lt;number&gt;</code> →
<code>inset-s-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: migrate <code>end-full</code> →
<code>inset-e-full</code>, <code>end-auto</code> →
<code>inset-e-auto</code>, <code>end-px</code> →
<code>inset-e-px</code>, and <code>end-&lt;number&gt;</code> →
<code>inset-e-&lt;number&gt;</code> as well as negative versions (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19849">#19849</a>)</li>
<li>Canonicalization: move the <code>-</code> sign inside the arbitrary
value <code>-left-[9rem]</code> → <code>left-[-9rem]</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Canonicalization: move the <code>-</code> sign outside the arbitrary
value <code>ml-[calc(-1*var(--width))]</code> →
<code>-ml-(--width)</code> (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19858">#19858</a>)</li>
<li>Improve performance when scanning JSONL / NDJSON files (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19862">#19862</a>)</li>
<li>Support <code>NODE_PATH</code> environment variable in standalone
CLI (<a
href="https://redirect.github.com/tailwindlabs/tailwindcss/pull/19617">#19617</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/69ad7cc5ec091125842aba783c5bfce536e9c234"><code>69ad7cc</code></a>
4.2.4 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19948">#19948</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/2e3fa490a535a8341fd2853d75098f0d4dbcc825"><code>2e3fa49</code></a>
4.2.3 (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19944">#19944</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/df6209ab8b957e56e6e00042a3e4080c14a072ea"><code>df6209a</code></a>
Canonicalize negative arbitrary values (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19858">#19858</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/52fd421cc941aad650db769f04b77d08c56951df"><code>52fd421</code></a>
Small refactor of canonicalization tests (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19851">#19851</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/c385fd36bcce707a02c229ebeb66ea88e12eb041"><code>c385fd3</code></a>
use <code>test.each</code> instead of manual loop</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/0d6e038889f49a809a4077ef7badc7d43184cd42"><code>0d6e038</code></a>
fix index in test name</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/88a2d22c2fdb65c5f8c3b2f68db9713f8bf2e656"><code>88a2d22</code></a>
Add more canonicalization rules for deprecated utilities (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19849">#19849</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/2c1ef9eb2564f2c83df970eb9f68c19d340c02e5"><code>2c1ef9e</code></a>
Use <code>--placeholder-color</code> instead of
<code>--background-color</code> for <code>placeholder-*</code>...</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/28d526859dfd1efe204c8f037c3fe472d9b5d08e"><code>28d5268</code></a>
Collapse more utilities by expanding their declarations (<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19842">#19842</a>)</li>
<li><a
href="https://github.com/tailwindlabs/tailwindcss/commit/b55d96002ce4516c5158ad3565229267b948c1ac"><code>b55d960</code></a>
fix(canonicalize): collapse arbitrary values into shorthand utilities
(<a
href="https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss/issues/19837">#19837</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tailwindlabs/tailwindcss/commits/v4.2.4/packages/tailwindcss">compare
view</a></li>
</ul>
</details>
<br />

Updates `vite` from 8.0.8 to 8.0.10
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.10</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.0.10/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>v8.0.9</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/v8.0.9/packages/vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.0.9...v8.0.10">8.0.10</a>
(2026-04-23)<!-- raw HTML omitted --></h2>
<h3>Features</h3>
<ul>
<li>update rolldown to 1.0.0-rc.17 (<a
href="https://redirect.github.com/vitejs/vite/issues/22299">#22299</a>)
(<a
href="https://github.com/vitejs/vite/commit/a4d06d9015167d30fe8ac63d1ce2edc146cdca31">a4d06d9</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><code>hmrClient.logger.debug</code> and
<code>hmrClient.logger.error</code> looked different from other HMR logs
(<a
href="https://redirect.github.com/vitejs/vite/issues/22147">#22147</a>)
(<a
href="https://github.com/vitejs/vite/commit/a4d828f2d5ed85440bc0774eab342e6f9a5e5f62">a4d828f</a>)</li>
<li><strong>css:</strong> show filename in CSS minification warnings for
<code>.css?inline</code> (<a
href="https://redirect.github.com/vitejs/vite/issues/22292">#22292</a>)
(<a
href="https://github.com/vitejs/vite/commit/83f0a785a2ae48d6761fb69f4b0523a24ae9342c">83f0a78</a>)</li>
<li><strong>optimizer:</strong> allow user transform.target to override
default in optimizeDeps (<a
href="https://redirect.github.com/vitejs/vite/issues/22273">#22273</a>)
(<a
href="https://github.com/vitejs/vite/commit/5c7cec69b637544ab16009d8758df7dbbf7f2674">5c7cec6</a>)</li>
<li>remove format sniffing module resolution from JS resolver (<a
href="https://redirect.github.com/vitejs/vite/issues/22297">#22297</a>)
(<a
href="https://github.com/vitejs/vite/commit/b8a21cc821c1434ac9d2b85ec53005df9edc306b">b8a21cc</a>)</li>
</ul>
<h3>Code Refactoring</h3>
<ul>
<li>enable some typecheck rules (<a
href="https://redirect.github.com/vitejs/vite/issues/22278">#22278</a>)
(<a
href="https://github.com/vitejs/vite/commit/943751801f70057ae94f9092e349c8f3fd9ccdf2">9437518</a>)</li>
<li>typecheck client directory (<a
href="https://redirect.github.com/vitejs/vite/issues/22284">#22284</a>)
(<a
href="https://github.com/vitejs/vite/commit/40a0847276502b33a3942b3cfab04b20218f3543">40a0847</a>)</li>
</ul>
<h2><!-- raw HTML omitted --><a
href="https://github.com/vitejs/vite/compare/v8.0.8...v8.0.9">8.0.9</a>
(2026-04-20)<!-- raw HTML omitted --></h2>
<h3>Features</h3>
<ul>
<li>update rolldown to 1.0.0-rc.16 (<a
href="https://redirect.github.com/vitejs/vite/issues/22248">#22248</a>)
(<a
href="https://github.com/vitejs/vite/commit/2947edd57ceb64a0b4dc43269743e8e44e68c09b">2947edd</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>allow binding when strictPort is set but wildcard port is in use (<a
href="https://redirect.github.com/vitejs/vite/issues/22150">#22150</a>)
(<a
href="https://github.com/vitejs/vite/commit/dfc8aa5057dd8ec2b1223980d1e2eeb946ac3384">dfc8aa5</a>)</li>
<li><strong>build:</strong> emptyOutDir should happen for watch rebuilds
(<a
href="https://redirect.github.com/vitejs/vite/issues/22207">#22207</a>)
(<a
href="https://github.com/vitejs/vite/commit/ee522672bb374c7ff95a347f14732491121b1cd6">ee52267</a>)</li>
<li><strong>bundled-dev:</strong> reject requests to HMR patch files in
non potentially trustworthy origins (<a
href="https://redirect.github.com/vitejs/vite/issues/22269">#22269</a>)
(<a
href="https://github.com/vitejs/vite/commit/868f1411a6f474baa4417f2d6524692dd452f760">868f141</a>)</li>
<li><strong>css:</strong> use unique key for cssEntriesMap to prevent
same-basename collision (<a
href="https://redirect.github.com/vitejs/vite/issues/22039">#22039</a>)
(<a
href="https://github.com/vitejs/vite/commit/374bb5d597fcd0485e929565c698d8ed219136f8">374bb5d</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22219">#22219</a>)
(<a
href="https://github.com/vitejs/vite/commit/4cd0d6760edd5fb0841abe86538de3c225e880a1">4cd0d67</a>)</li>
<li><strong>deps:</strong> update all non-major dependencies (<a
href="https://redirect.github.com/vitejs/vite/issues/22268">#22268</a>)
(<a
href="https://github.com/vitejs/vite/commit/c28e9c12a849f80e6fdc93f42283ad2863ab9dbc">c28e9c1</a>)</li>
<li>detect Deno workspace root (fix <a
href="https://redirect.github.com/vitejs/vite/issues/22237">#22237</a>)
(<a
href="https://redirect.github.com/vitejs/vite/issues/22238">#22238</a>)
(<a
href="https://github.com/vitejs/vite/commit/1b793c0e1726467fffd06ffad9bc81c61a840188">1b793c0</a>)</li>
<li><strong>dev:</strong> handle errors in <code>watchChange</code> hook
(<a
href="https://redirect.github.com/vitejs/vite/issues/22188">#22188</a>)
(<a
href="https://github.com/vitejs/vite/commit/fc08bdab9bba871b03689f2f6997c3a4ba4351da">fc08bda</a>)</li>
<li><strong>optimizer:</strong> handle more chars that will be sanitized
(<a
href="https://redirect.github.com/vitejs/vite/issues/22208">#22208</a>)
(<a
href="https://github.com/vitejs/vite/commit/3f24533ac4845ed22547279d1721bd82a35345e3">3f24533</a>)</li>
<li>skip fallback sourcemap generation for <code>?raw</code> imports (<a
href="https://redirect.github.com/vitejs/vite/issues/22148">#22148</a>)
(<a
href="https://github.com/vitejs/vite/commit/3ec9cdaac7936ca32d0956c4cb1eb6e172945996">3ec9cda</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>align the descriptions in READMEs (<a
href="https://redirect.github.com/vitejs/vite/issues/22231">#22231</a>)
(<a
href="https://github.com/vitejs/vite/commit/44c42b97639bb6ad777e66d752b2829cccb9a27a">44c42b9</a>)</li>
<li>fix reuses wording in dev environment comment (<a
href="https://redirect.github.com/vitejs/vite/issues/22173">#22173</a>)
(<a
href="https://github.com/vitejs/vite/commit/9163412fdfec7fb1656529713326a5b5c5e986ea">9163412</a>)</li>
<li>fix wording in sass error comment (<a
href="https://redirect.github.com/vitejs/vite/issues/22214">#22214</a>)
(<a
href="https://github.com/vitejs/vite/commit/bc5c6a7a498845dff20dc410c395355b79a4b753">bc5c6a7</a>)</li>
<li>update build CLI defaults (<a
href="https://redirect.github.com/vitejs/vite/issues/22261">#22261</a>)
(<a
href="https://github.com/vitejs/vite/commit/605bb97994678a1bb70a8de9a85c29d5f5d48c5a">605bb97</a>)</li>
</ul>
<h3>Miscellaneous Chores</h3>
<ul>
<li><strong>deps:</strong> update dependency dotenv-expand to v13 (<a
href="https://redirect.github.com/vitejs/vite/issues/22271">#22271</a>)
(<a
href="https://github.com/vitejs/vite/commit/0a3887da18812cacb254c616e4dd35631e776fda">0a3887d</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/32c29780404c353f5a7c5ba4d06fc5e676741714"><code>32c2978</code></a>
release: v8.0.10</li>
<li><a
href="https://github.com/vitejs/vite/commit/a4d06d9015167d30fe8ac63d1ce2edc146cdca31"><code>a4d06d9</code></a>
feat: update rolldown to 1.0.0-rc.17 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22299">#22299</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/a4d828f2d5ed85440bc0774eab342e6f9a5e5f62"><code>a4d828f</code></a>
fix: <code>hmrClient.logger.debug</code> and
<code>hmrClient.logger.error</code> looked different f...</li>
<li><a
href="https://github.com/vitejs/vite/commit/83f0a785a2ae48d6761fb69f4b0523a24ae9342c"><code>83f0a78</code></a>
fix(css): show filename in CSS minification warnings for
<code>.css?inline</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22292">#22292</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/b8a21cc821c1434ac9d2b85ec53005df9edc306b"><code>b8a21cc</code></a>
fix: remove format sniffing module resolution from JS resolver (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22297">#22297</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/40a0847276502b33a3942b3cfab04b20218f3543"><code>40a0847</code></a>
refactor: typecheck client directory (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22284">#22284</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/5c7cec69b637544ab16009d8758df7dbbf7f2674"><code>5c7cec6</code></a>
fix(optimizer): allow user transform.target to override default in
optimizeDe...</li>
<li><a
href="https://github.com/vitejs/vite/commit/943751801f70057ae94f9092e349c8f3fd9ccdf2"><code>9437518</code></a>
refactor: enable some typecheck rules (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22278">#22278</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/ce729f5fa1a5adca373b2adcb0e1b18099164a14"><code>ce729f5</code></a>
release: v8.0.9</li>
<li><a
href="https://github.com/vitejs/vite/commit/605bb97994678a1bb70a8de9a85c29d5f5d48c5a"><code>605bb97</code></a>
docs: update build CLI defaults (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22261">#22261</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v8.0.10/packages/vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `vitest` from 4.1.4 to 4.1.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.5</h2>
<h3>   🚀 Experimental Features</h3>
<ul>
<li><strong>coverage</strong>: Istanbul to support
<code>instrumenter</code> option  -  by <a
href="https://github.com/BartWaardenburg"><code>@​BartWaardenburg</code></a>
and <a
href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10119">vitest-dev/vitest#10119</a>
<a href="https://github.com/vitest-dev/vitest/commit/0e0ff41c7"><!-- raw
HTML omitted -->(0e0ff)<!-- raw HTML omitted --></a></li>
</ul>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li>--project negation excludes browser instances  -  by <a
href="https://github.com/felamaslen"><code>@​felamaslen</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10131">vitest-dev/vitest#10131</a>
<a href="https://github.com/vitest-dev/vitest/commit/9423dc084"><!-- raw
HTML omitted -->(9423d)<!-- raw HTML omitted --></a></li>
<li>Project color label on html reporter  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10142">vitest-dev/vitest#10142</a>
<a href="https://github.com/vitest-dev/vitest/commit/596f73986"><!-- raw
HTML omitted -->(596f7)<!-- raw HTML omitted --></a></li>
<li>Fix <code>vi.defineHelper</code> called as object method  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10163">vitest-dev/vitest#10163</a>
<a href="https://github.com/vitest-dev/vitest/commit/122c25b5b"><!-- raw
HTML omitted -->(122c2)<!-- raw HTML omitted --></a></li>
<li>Alias <code>agent</code> reporter to <code>minimal</code>  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10157">vitest-dev/vitest#10157</a>
<a href="https://github.com/vitest-dev/vitest/commit/663b99fe3"><!-- raw
HTML omitted -->(663b9)<!-- raw HTML omitted --></a></li>
<li>Respect diff config options in soft assertions  -  by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a>,
<strong>sheremet-va</strong> and <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/8696">vitest-dev/vitest#8696</a>
<a href="https://github.com/vitest-dev/vitest/commit/9787dedad"><!-- raw
HTML omitted -->(9787d)<!-- raw HTML omitted --></a></li>
<li>Respect diff config options in soft assertions &quot;  -  by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/8696">vitest-dev/vitest#8696</a>
<a href="https://github.com/vitest-dev/vitest/commit/7dc6d54fd"><!-- raw
HTML omitted -->(7dc6d)<!-- raw HTML omitted --></a></li>
<li><strong>ast-collect</strong>: Recognize _<em>vi_import</em> prefix
in static test discovery  -  by <a
href="https://github.com/Yejneshwar"><code>@​Yejneshwar</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10129">vitest-dev/vitest#10129</a>
<a href="https://github.com/vitest-dev/vitest/commit/325463ab2"><!-- raw
HTML omitted -->(32546)<!-- raw HTML omitted --></a></li>
<li><strong>coverage</strong>: Descriptive error message when reports
directory is removed during test run  -  by <a
href="https://github.com/DaveT1991"><code>@​DaveT1991</code></a> and <a
href="https://github.com/AriPerkkio"><code>@​AriPerkkio</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10117">vitest-dev/vitest#10117</a>
<a href="https://github.com/vitest-dev/vitest/commit/1413382e1"><!-- raw
HTML omitted -->(14133)<!-- raw HTML omitted --></a></li>
<li><strong>snapshot</strong>: Increase default snapshot max output
length  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> and
<strong>Codex</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10150">vitest-dev/vitest#10150</a>
<a href="https://github.com/vitest-dev/vitest/commit/21e66ff63"><!-- raw
HTML omitted -->(21e66)<!-- raw HTML omitted --></a></li>
<li><strong>ui</strong>: Fix jsx/tsx syntax highlight  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10152">vitest-dev/vitest#10152</a>
<a href="https://github.com/vitest-dev/vitest/commit/f1b1f6c7b"><!-- raw
HTML omitted -->(f1b1f)<!-- raw HTML omitted --></a></li>
<li><strong>web-worker</strong>: Support MessagePort objects referenced
inside postMessage data  -  by <a
href="https://github.com/whitphx"><code>@​whitphx</code></a> and
<strong>Claude Opus 4.6 (1M context)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/9927">vitest-dev/vitest#9927</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10124">vitest-dev/vitest#10124</a>
<a href="https://github.com/vitest-dev/vitest/commit/7ad7d39af"><!-- raw
HTML omitted -->(7ad7d)<!-- raw HTML omitted --></a></li>
<li><strong>api</strong>: Make test-specification options writable  - 
by <a
href="https://github.com/sheremet-va"><code>@​sheremet-va</code></a> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10154">vitest-dev/vitest#10154</a>
<a href="https://github.com/vitest-dev/vitest/commit/6abd557b7"><!-- raw
HTML omitted -->(6abd5)<!-- raw HTML omitted --></a></li>
</ul>
<h5>    <a
href="https://github.com/vitest-dev/vitest/compare/v4.1.4...v4.1.5">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitest-dev/vitest/commit/e399846850fedf10b8228cbe46a419628998acd9"><code>e399846</code></a>
chore: release v4.1.5</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/7dc6d54fd9dda0fe6fee2fb6451d0611a9ecb6e7"><code>7dc6d54</code></a>
Revert &quot;fix: respect diff config options in soft assertions (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/8696">#8696</a>)&quot;</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/9787dedade9896a6d3eeed7739177d6c583a68a7"><code>9787ded</code></a>
fix: respect diff config options in soft assertions (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/8696">#8696</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/325463ab292c45c3ef27aa21ec7da380c307052c"><code>325463a</code></a>
fix(ast-collect): recognize _<em>vi_import</em> prefix in static test
discovery (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10">#10</a>...</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/0e0ff41c7e86d6e2bf581f074dc216805d10d371"><code>0e0ff41</code></a>
feat(coverage): istanbul to support <code>instrumenter</code> option (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10119">#10119</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/663b99fe3e6a60fc8a7ccd2d9941d1cbe929b606"><code>663b99f</code></a>
fix: alias <code>agent</code> reporter to <code>minimal</code> (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10157">#10157</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/122c25b5b157ffd31b376561b16ab983aa23e7bc"><code>122c25b</code></a>
fix: fix <code>vi.defineHelper</code> called as object method (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10163">#10163</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/6abd557b7219156893dd13a1dbe86501d5542d2e"><code>6abd557</code></a>
feat(api): make test-specification options writable (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10154">#10154</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/596f73986abe2161a9a06f0ca03df68e82690b21"><code>596f739</code></a>
fix: project color label on html reporter (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10142">#10142</a>)</li>
<li><a
href="https://github.com/vitest-dev/vitest/commit/9423dc0841e97b6dcac8a73cdb8e656b3d6ba909"><code>9423dc0</code></a>
fix: --project negation excludes browser instances (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10131">#10131</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.5/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-25 13:12:25 +01:00
dependabot[bot] 74a466139d Bump actions/setup-node from 6.3.0 to 6.4.0 in the gh-actions group (#913)
Bumps the gh-actions group with 1 update:
[actions/setup-node](https://github.com/actions/setup-node).

Updates `actions/setup-node` from 6.3.0 to 6.4.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v6.4.0</h2>
<h2>What's Changed</h2>
<h3>Dependency updates:</h3>
<ul>
<li>Upgrade <a
href="https://github.com/actions"><code>@​actions</code></a>
dependencies by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
<li>Update Node.js versions in versions.yml and bump package to v6.4.0
by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1533">actions/setup-node#1533</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Copilot"><code>@​Copilot</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v6.4.0">https://github.com/actions/setup-node/compare/v6...v6.4.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e"><code>48b55a0</code></a>
Update Node.js versions in versions.yml and bump package to v6.4.0 (<a
href="https://redirect.github.com/actions/setup-node/issues/1533">#1533</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/ab72c7e7eba0eaa11f8cab0f5679243900c2cac9"><code>ab72c7e</code></a>
Upgrade <a href="https://github.com/actions"><code>@​actions</code></a>
dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1525">#1525</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/setup-node/compare/53b83947a5a98c8d113130e565377fae1a50d02f...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=6.3.0&new-version=6.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-25 13:12:13 +01:00
Humaid KhanandHumaid Arif Khan d6a7588d22 Remove immutable to allow wal checkpoints (#916)
Fixes https://github.com/calibrain/shelfmark/issues/915

## Description

Remove immutable=1 to allow wal checkpoints to fire and get latest auth
info.

Note db is still in readonly mode, thanks to mode=ro

## Test case

1. Run CWA/CW
2. Change Admin password from admin/admin123 to anything else
3. Run shelfmark with CWA db auth
4. Shelfmark should be able to login after password change

Co-authored-by: Humaid Arif Khan <humaid.k@tlt.local>
2026-04-25 13:08:27 +01:00
dependabot[bot]andAlex 700935ec17 Bump the npm-deps group in /src/frontend with 6 updates (#899)
Bumps the npm-deps group in /src/frontend with 6 updates:

| Package | From | To |
| --- | --- | --- |
|
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
| `7.14.0` | `7.14.1` |
| [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) |
`6.4.0` | `6.4.1` |
| [oxfmt](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt) |
`0.44.0` | `0.45.0` |
| [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) |
`1.59.0` | `1.60.0` |
| [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) | `0.20.0`
| `0.21.1` |
| [typescript](https://github.com/microsoft/TypeScript) | `6.0.2` |
`6.0.3` |

Updates `react-router-dom` from 7.14.0 to 7.14.1
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v7.14.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies:
<ul>
<li><a
href="https://github.com/remix-run/react-router/releases/tag/react-router@7.14.1"><code>react-router@7.14.1</code></a></li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/197674ba9fc1b72b452e17894e5e783bdab7a087"><code>197674b</code></a>
Release 7.14.1 (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14973">#14973</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/a87774f997d8ba497c97562840f0766250c3e4ce"><code>a87774f</code></a>
Add new release process (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14916">#14916</a>)</li>
<li>See full diff in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@7.14.1/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `knip` from 6.4.0 to 6.4.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webpro-nl/knip/releases">knip's
releases</a>.</em></p>
<blockquote>
<h2>Release 6.4.1</h2>
<ul>
<li>license (2d3d8d86ea51f18224c3558a38c28df00113f683)</li>
<li>Handle file path arguments in Bun plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1678">#1678</a>)
(cdbe298efcb226ae4baec6567a0cbb6fdf001ee8)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/webpro-nl/knip/commit/ea70d72232b13dca6338105f9fd4ea211595dfba"><code>ea70d72</code></a>
Release knip@6.4.1</li>
<li><a
href="https://github.com/webpro-nl/knip/commit/cdbe298efcb226ae4baec6567a0cbb6fdf001ee8"><code>cdbe298</code></a>
Handle file path arguments in Bun plugin (resolve <a
href="https://github.com/webpro-nl/knip/tree/HEAD/packages/knip/issues/1678">#1678</a>)</li>
<li>See full diff in <a
href="https://github.com/webpro-nl/knip/commits/knip@6.4.1/packages/knip">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxfmt` from 0.44.0 to 0.45.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxfmt/CHANGELOG.md">oxfmt's
changelog</a>.</em></p>
<blockquote>
<h2>[0.45.0] - 2026-04-13</h2>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>50c389b oxfmt: Support <code>.editorconfig</code>
<code>quote_type</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20989">#20989</a>)
(leaysgur)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/e16848eb4c29e51e2e3e2bbda36c76ede42ab974"><code>e16848e</code></a>
release(apps): oxlint v1.60.0 &amp;&amp; oxfmt v0.45.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/21375">#21375</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/50c389b64ffa65c6a889f725f53c748d7e3bc507"><code>50c389b</code></a>
fix(oxfmt): Support <code>.editorconfig</code> <code>quote_type</code>
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxfmt/issues/20989">#20989</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxfmt_v0.45.0/npm/oxfmt">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint` from 1.59.0 to 1.60.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/releases">oxlint's
releases</a>.</em></p>
<blockquote>
<h2>oxlint v1.27.0 &amp;&amp; oxfmt v0.12.0</h2>
<h1>Oxlint v1.27.0</h1>
<h3>🚀 Features</h3>
<ul>
<li>222a8f0 linter/plugins: Implement
<code>SourceCode#isSpaceBetween</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15498">#15498</a>)
(overlookmotel)</li>
<li>2f9735d linter/plugins: Implement
<code>context.languageOptions</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15486">#15486</a>)
(overlookmotel)</li>
<li>bc731ff linter/plugins: Stub out all <code>Context</code> APIs (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15479">#15479</a>)
(overlookmotel)</li>
<li>5822cb4 linter/plugins: Add <code>extend</code> method to
<code>FILE_CONTEXT</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15477">#15477</a>)
(overlookmotel)</li>
<li>7b1e6f3 apps: Add pure rust binaries and release to github (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15469">#15469</a>)
(Boshen)</li>
<li>2a89b43 linter: Introduce debug assertions after fixes to assert
validity (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15389">#15389</a>)
(camc314)</li>
<li>ad3c45a editor: Add <code>oxc.path.node</code> option (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15040">#15040</a>)
(Sysix)</li>
</ul>
<h3>🐛 Bug Fixes</h3>
<ul>
<li>6f3cd77 linter/no-var: Incorrect warning for blocks (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15504">#15504</a>)
(Hamir Mahal)</li>
<li>6957fb9 linter/plugins: Do not allow access to
<code>Context#id</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15489">#15489</a>)
(overlookmotel)</li>
<li>7409630 linter/plugins: Allow access to <code>cwd</code> in
<code>createOnce</code> in ESLint interop mode (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15488">#15488</a>)
(overlookmotel)</li>
<li>732205e parser: Reject <code>using</code> / <code>await using</code>
in a switch <code>case</code> / <code>default</code> clause (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15225">#15225</a>)
(sapphi-red)</li>
<li>a17ca32 linter/plugins: Replace <code>Context</code> class (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15448">#15448</a>)
(overlookmotel)</li>
<li>ecf2f7b language_server: Fail gracefully when tsgolint executable
not found (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15436">#15436</a>)
(camc314)</li>
<li>3c8d3a7 lang-server: Improve logging in failure case for tsgolint
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15299">#15299</a>)
(camc314)</li>
<li>ef71410 linter: Use jsx if source type is JS in fix debug assertion
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15434">#15434</a>)
(camc314)</li>
<li>e32bbf6 linter/no-var: Handle TypeScript declare keyword in fixer
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15426">#15426</a>)
(camc314)</li>
<li>6565dbe linter/switch-case-braces: Skip comments when searching for
<code>:</code> token (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15425">#15425</a>)
(camc314)</li>
<li>85bd19a linter/prefer-class-fields: Insert value after type
annotation in fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15423">#15423</a>)
(camc314)</li>
<li>fde753e linter/plugins: Block access to
<code>context.settings</code> in <code>createOnce</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15394">#15394</a>)
(overlookmotel)</li>
<li>ddd9f9f linter/forward-ref-uses-ref: Dont suggest removing wrapper
in invalid positions (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15388">#15388</a>)
(camc314)</li>
<li>dac2a9c linter/no-template-curly-in-string: Remove fixer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15387">#15387</a>)
(camc314)</li>
<li>989b8e3 linter/no-var: Only fix to <code>const</code> if the var has
an initializer (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15385">#15385</a>)
(camc314)</li>
<li>cc403f5 linter/plugins: Return empty object for unimplemented
parserServices (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15364">#15364</a>)
(magic-akari)</li>
</ul>
<h3> Performance</h3>
<ul>
<li>25d577e language_server: Start tools in parallel (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15500">#15500</a>)
(Sysix)</li>
<li>3c57291 linter/plugins: Optimize loops (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15449">#15449</a>)
(overlookmotel)</li>
<li>3166233 linter/plugins: Remove <code>Arc</code>s (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15431">#15431</a>)
(overlookmotel)</li>
<li>9de1322 linter/plugins: Lazily deserialize settings JSON (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15395">#15395</a>)
(overlookmotel)</li>
<li>3049ec2 linter/plugins: Optimize <code>deepFreezeSettings</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15392">#15392</a>)
(overlookmotel)</li>
<li>444ebfd linter/plugins: Use single object for
<code>parserServices</code> (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15378">#15378</a>)
(overlookmotel)</li>
</ul>
<h3>📚 Documentation</h3>
<ul>
<li>97d2104 linter: Update comment in lint.rs about default value for
tsconfig path (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15530">#15530</a>)
(Connor Shea)</li>
<li>2c6bd9e linter: Always refer as &quot;ES2015&quot; instead of
&quot;ES6&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15411">#15411</a>)
(sapphi-red)</li>
<li>a0c5203 linter/import/named: Update &quot;ES7&quot; comment in
examples (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15410">#15410</a>)
(sapphi-red)</li>
<li>3dc24b5 linter,minifier: Always refer as &quot;ES Modules&quot;
instead of &quot;ES6 Modules&quot; (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15409">#15409</a>)
(sapphi-red)</li>
<li>2ad77fb linter/no-this-before-super: Correct &quot;Why is this
bad?&quot; section (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15408">#15408</a>)
(sapphi-red)</li>
<li>57f0ce1 linter: Add backquotes where appropriate (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/15407">#15407</a>)
(sapphi-red)</li>
</ul>
<h1>Oxfmt v0.12.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md">oxlint's
changelog</a>.</em></p>
<blockquote>
<h2>[1.60.0] - 2026-04-13</h2>
<h3>📚 Documentation</h3>
<ul>
<li>cfd8a4f linter: Don't rely on old eslint doc for available globals
(<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21334">#21334</a>)
(Nicolas Le Cam)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/oxc/commit/e16848eb4c29e51e2e3e2bbda36c76ede42ab974"><code>e16848e</code></a>
release(apps): oxlint v1.60.0 &amp;&amp; oxfmt v0.45.0 (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21375">#21375</a>)</li>
<li><a
href="https://github.com/oxc-project/oxc/commit/cfd8a4f7a46bb056e58f6d531caca2ec487948ba"><code>cfd8a4f</code></a>
docs(linter): don't rely on old eslint doc for available globals (<a
href="https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint/issues/21334">#21334</a>)</li>
<li>See full diff in <a
href="https://github.com/oxc-project/oxc/commits/oxlint_v1.60.0/npm/oxlint">compare
view</a></li>
</ul>
</details>
<br />

Updates `oxlint-tsgolint` from 0.20.0 to 0.21.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/oxc-project/tsgolint/releases">oxlint-tsgolint's
releases</a>.</em></p>
<blockquote>
<h2>v0.21.1</h2>
<h2>What's Changed</h2>
<ul>
<li>fix(no-unnecessary-condition): handle null overlap in narrowed
generic intersections by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/891">oxc-project/tsgolint#891</a></li>
<li>revert(no-unnecessary-type-arguments): drop inference reporting by
<a href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/892">oxc-project/tsgolint#892</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.21.0...v0.21.1">https://github.com/oxc-project/tsgolint/compare/v0.21.0...v0.21.1</a></p>
<h2>v0.21.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore: migrate gen-json-schemas to TS by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/874">oxc-project/tsgolint#874</a></li>
<li>chore: update typescript-go submodule by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/879">oxc-project/tsgolint#879</a></li>
<li>chore(deps): update github-actions by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/883">oxc-project/tsgolint#883</a></li>
<li>chore(deps): update gomod by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/884">oxc-project/tsgolint#884</a></li>
<li>chore(deps): update npm packages by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/885">oxc-project/tsgolint#885</a></li>
<li>feat: improve <code>consistent-type-exports</code> diagnostics
quality by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/880">oxc-project/tsgolint#880</a></li>
<li>chore(deps): update softprops/action-gh-release action to v3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/886">oxc-project/tsgolint#886</a></li>
<li>feat: enrich the <code>no-array-delete</code> diagnostic by <a
href="https://github.com/camchenry"><code>@​camchenry</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/881">oxc-project/tsgolint#881</a></li>
<li>feat: enrich <code>no-duplicate-type-constituents</code> diagnostic
by <a href="https://github.com/camchenry"><code>@​camchenry</code></a>
in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/882">oxc-project/tsgolint#882</a></li>
<li>fix(no-meaningless-void-operator): align with typescript-eslint
union handling by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/887">oxc-project/tsgolint#887</a></li>
<li>chore(deps): update crate-ci/typos action to v1.45.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/oxc-project/tsgolint/pull/888">oxc-project/tsgolint#888</a></li>
<li>fix(no-deprecated): avoid false positive on array destructuring
bindings by <a
href="https://github.com/camc314"><code>@​camc314</code></a> in <a
href="https://redirect.github.com/oxc-project/tsgolint/pull/890">oxc-project/tsgolint#890</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/oxc-project/tsgolint/compare/v0.20.0...v0.21.0">https://github.com/oxc-project/tsgolint/compare/v0.20.0...v0.21.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/9cb95a8635bd9650759c9bb59b9d87b1d76b2a36"><code>9cb95a8</code></a>
revert(no-unnecessary-type-arguments): drop inference reporting (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/892">#892</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/f1049e402095722698f7364717b0ad03bf21edb1"><code>f1049e4</code></a>
fix(no-unnecessary-condition): handle null overlap in narrowed generic
inters...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/f9adc305c454101984c5f0886f0ce6a71e780d15"><code>f9adc30</code></a>
fix(no-deprecated): avoid false positive on array destructuring bindings
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/890">#890</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/260701f61d543d0d3fc31bb5760407d07e272ae8"><code>260701f</code></a>
chore(deps): update crate-ci/typos action to v1.45.1 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/888">#888</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/6dcc81a8ef17d2204e23ca4584a2c70248b30097"><code>6dcc81a</code></a>
fix(no-meaningless-void-operator): align with typescript-eslint union
handlin...</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/97315a7a2555edfc398ac2ef1c83d6d89ee95cc7"><code>97315a7</code></a>
feat: enrich <code>no-duplicate-type-constituents</code> diagnostic (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/882">#882</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/2b8447cde4907a7d131e85747c9289cde3a66cc2"><code>2b8447c</code></a>
feat: enrich the <code>no-array-delete</code> diagnostic (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/881">#881</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/ae6a5493416f9c348a246d9686d73a075c5b797f"><code>ae6a549</code></a>
chore(deps): update softprops/action-gh-release action to v3 (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/886">#886</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/1fe50bb1c6b381de333ca20fbd8beb12ec5b1d21"><code>1fe50bb</code></a>
feat: improve <code>consistent-type-exports</code> diagnostics quality
(<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/880">#880</a>)</li>
<li><a
href="https://github.com/oxc-project/tsgolint/commit/834bbb81049885777cbaf51670344e7df32862de"><code>834bbb8</code></a>
chore(deps): update npm packages (<a
href="https://redirect.github.com/oxc-project/tsgolint/issues/885">#885</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/oxc-project/tsgolint/compare/v0.20.0...v0.21.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `typescript` from 6.0.2 to 6.0.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/microsoft/TypeScript/releases">typescript's
releases</a>.</em></p>
<blockquote>
<h2>TypeScript 6.0.3</h2>
<!-- raw HTML omitted -->
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/microsoft/TypeScript/commit/050880ce59e30b356b686bd3144efe24f875ebc8"><code>050880c</code></a>
Bump version to 6.0.3 and LKG</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/eeae9dd0f17aa494658e4ec079dc002e02dd625e"><code>eeae9dd</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/63401">#63401</a>
(Also check package name validity in...) into release-6.0 (#...</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/ad1c695fada682764bb510dd680e8f175ae54094"><code>ad1c695</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/63368">#63368</a>
(Harden ATA package name filtering) into release-6.0 (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/63372">#63372</a>)</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/0725fb4664a1d5ec94040b6d94db77dc1cc354e4"><code>0725fb4</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/63310">#63310</a>
(Mark class property initializers as...) into release-6.0 (#...</li>
<li>See full diff in <a
href="https://github.com/microsoft/TypeScript/compare/v6.0.2...v6.0.3">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex <25013571+alexhb1@users.noreply.github.com>
2026-04-23 21:03:46 +01:00
dependabot[bot] f7f920683d Bump the gh-actions group with 2 updates (#898)
Bumps the gh-actions group with 2 updates:
[astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and
[github/codeql-action](https://github.com/github/codeql-action).

Updates `astral-sh/setup-uv` from 8.0.0 to 8.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v8.1.0 🌈 New input <code>no-project</code></h2>
<h2>Changes</h2>
<p>This add the a new boolean input <code>no-project</code>.
It only makes sense to use in combination with
<code>activate-environment: true</code> and will append <code>--no
project</code> to the <code>uv venv</code> call. This is for example
useful <a
href="https://redirect.github.com/astral-sh/setup-uv/issues/854">if you
have a pyproject.toml file with parts unparseable by uv</a></p>
<h2>🚀 Enhancements</h2>
<ul>
<li>Add input no-project in combination with activate-environment <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/856">#856</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>fix: grant contents:write to validate-release job <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/860">#860</a>)</li>
<li>Add a release-gate step to the release workflow <a
href="https://github.com/zanieb"><code>@​zanieb</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/859">#859</a>)</li>
<li>Draft commitish releases <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/858">#858</a>)</li>
<li>Add action-types.yml to instructions <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/857">#857</a>)</li>
<li>chore: update known checksums for 0.11.7 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/853">#853</a>)</li>
<li>Refactor version resolving <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/852">#852</a>)</li>
<li>chore: update known checksums for 0.11.6 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/850">#850</a>)</li>
<li>chore: update known checksums for 0.11.5 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/845">#845</a>)</li>
<li>chore: update known checksums for 0.11.4 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/843">#843</a>)</li>
<li>Add a release workflow <a
href="https://github.com/zanieb"><code>@​zanieb</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/839">#839</a>)</li>
<li>chore: update known checksums for 0.11.3 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/836">#836</a>)</li>
</ul>
<h2>📚 Documentation</h2>
<ul>
<li>Update ignore-nothing-to-cache documentation <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/833">#833</a>)</li>
<li>Pin setup-uv docs to v8 <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/829">#829</a>)</li>
</ul>
<h2>⬆️ Dependency updates</h2>
<ul>
<li>chore(deps): bump release-drafter/release-drafter from 7.1.1 to
7.2.0 @<a href="https://github.com/apps/dependabot">dependabot[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/855">#855</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/08807647e7069bb48b6ef5acd8ec9567f424441b"><code>0880764</code></a>
fix: grant contents:write to validate-release job (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/860">#860</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/717d6aba0f15312f509f5c4999e34d71ecbab8a9"><code>717d6ab</code></a>
Add a release-gate step to the release workflow (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/859">#859</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/5a911eb3a3983b5e650f2dad95c1ce698ca94378"><code>5a911eb</code></a>
Draft commitish releases (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/858">#858</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/080c31e04cd7155b0ca676d08c7bc260a4476a23"><code>080c31e</code></a>
Add action-types.yml to instructions (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/857">#857</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/b3e97d2ba1a1eed7e9d1f8456dd06c3b725bc3a6"><code>b3e97d2</code></a>
Add input no-project in combination with activate-environment (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/856">#856</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/7dd591db9557f680290587fcc578372813b9ff64"><code>7dd591d</code></a>
chore(deps): bump release-drafter/release-drafter from 7.1.1 to 7.2.0
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/855">#855</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/1541b7762698877904805605192ecd63d0e4787a"><code>1541b77</code></a>
chore: update known checksums for 0.11.7 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/853">#853</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cdfb2ee6dde255817c739680168ad81e184c4bfb"><code>cdfb2ee</code></a>
Refactor version resolving (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/852">#852</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cb84d12dc6a0d495b82fcae14fa4559b90698660"><code>cb84d12</code></a>
chore: update known checksums for 0.11.6 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/850">#850</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/1912cc65f2e839707d7a16f2372f30b57d35fd80"><code>1912cc6</code></a>
chore: update known checksums for 0.11.5 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/845">#845</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/cec208311dfd045dd5311c1add060b2062131d57...08807647e7069bb48b6ef5acd8ec9567f424441b">compare
view</a></li>
</ul>
</details>
<br />

Updates `github/codeql-action` from 4.35.1 to 4.35.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/releases">github/codeql-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.35.2</h2>
<ul>
<li>The undocumented TRAP cache cleanup feature that could be enabled
using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment
variable is deprecated and will be removed in May 2026. If you are
affected by this, we recommend disabling TRAP caching by passing the
<code>trap-caching: false</code> input to the <code>init</code> Action.
<a
href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li>
<li>The Git version 2.36.0 requirement for improved incremental analysis
now only applies to repositories that contain submodules. <a
href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li>
<li>Python analysis on GHES no longer extracts the standard library,
relying instead on models of the standard library. This should result in
significantly faster extraction and analysis times, while the effect on
alerts should be minimal. <a
href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li>
<li>Fixed a bug in the validation of OIDC configurations for private
registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's
changelog</a>.</em></p>
<blockquote>
<h1>CodeQL Action Changelog</h1>
<p>See the <a
href="https://github.com/github/codeql-action/releases">releases
page</a> for the relevant changes to the CodeQL CLI and language
packs.</p>
<h2>[UNRELEASED]</h2>
<p>No user facing changes.</p>
<h2>4.35.2 - 15 Apr 2026</h2>
<ul>
<li>The undocumented TRAP cache cleanup feature that could be enabled
using the <code>CODEQL_ACTION_CLEANUP_TRAP_CACHES</code> environment
variable is deprecated and will be removed in May 2026. If you are
affected by this, we recommend disabling TRAP caching by passing the
<code>trap-caching: false</code> input to the <code>init</code> Action.
<a
href="https://redirect.github.com/github/codeql-action/pull/3795">#3795</a></li>
<li>The Git version 2.36.0 requirement for improved incremental analysis
now only applies to repositories that contain submodules. <a
href="https://redirect.github.com/github/codeql-action/pull/3789">#3789</a></li>
<li>Python analysis on GHES no longer extracts the standard library,
relying instead on models of the standard library. This should result in
significantly faster extraction and analysis times, while the effect on
alerts should be minimal. <a
href="https://redirect.github.com/github/codeql-action/pull/3794">#3794</a></li>
<li>Fixed a bug in the validation of OIDC configurations for private
registries that was added in CodeQL Action 4.33.0 / 3.33.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3807">#3807</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2">2.25.2</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3823">#3823</a></li>
</ul>
<h2>4.35.1 - 27 Mar 2026</h2>
<ul>
<li>Fix incorrect minimum required Git version for <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a>: it should have been 2.36.0, not 2.11.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3781">#3781</a></li>
</ul>
<h2>4.35.0 - 27 Mar 2026</h2>
<ul>
<li>Reduced the minimum Git version required for <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> from 2.38.0 to 2.11.0. <a
href="https://redirect.github.com/github/codeql-action/pull/3767">#3767</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1">2.25.1</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3773">#3773</a></li>
</ul>
<h2>4.34.1 - 20 Mar 2026</h2>
<ul>
<li>Downgrade default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3">2.24.3</a>
due to issues with a small percentage of Actions and JavaScript
analyses. <a
href="https://redirect.github.com/github/codeql-action/pull/3762">#3762</a></li>
</ul>
<h2>4.34.0 - 20 Mar 2026</h2>
<ul>
<li>Added an experimental change which disables TRAP caching when <a
href="https://redirect.github.com/github/roadmap/issues/1158">improved
incremental analysis</a> is enabled, since improved incremental analysis
supersedes TRAP caching. This will improve performance and reduce
Actions cache usage. We expect to roll this change out to everyone in
March. <a
href="https://redirect.github.com/github/codeql-action/pull/3569">#3569</a></li>
<li>We are rolling out improved incremental analysis to C/C++ analyses
that use build mode <code>none</code>. We expect this rollout to be
complete by the end of April 2026. <a
href="https://redirect.github.com/github/codeql-action/pull/3584">#3584</a></li>
<li>Update default CodeQL bundle version to <a
href="https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0">2.25.0</a>.
<a
href="https://redirect.github.com/github/codeql-action/pull/3585">#3585</a></li>
</ul>
<h2>4.33.0 - 16 Mar 2026</h2>
<ul>
<li>
<p>Upcoming change: Starting April 2026, the CodeQL Action will skip
collecting file coverage information on pull requests to improve
analysis performance. File coverage information will still be computed
on non-PR analyses. Pull request analyses will log a warning about this
upcoming change. <a
href="https://redirect.github.com/github/codeql-action/pull/3562">#3562</a></p>
<p>To opt out of this change:</p>
<ul>
<li><strong>Repositories owned by an organization:</strong> Create a
custom repository property with the name
<code>github-codeql-file-coverage-on-prs</code> and the type
&quot;True/false&quot;, then set this property to <code>true</code> in
the repository's settings. For more information, see <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">Managing
custom properties for repositories in your organization</a>.
Alternatively, if you are using an advanced setup workflow, you can set
the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable
to <code>true</code> in your workflow.</li>
<li><strong>User-owned repositories using default setup:</strong> Switch
to an advanced setup workflow and set the
<code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable to
<code>true</code> in your workflow.</li>
<li><strong>User-owned repositories using advanced setup:</strong> Set
the <code>CODEQL_ACTION_FILE_COVERAGE_ON_PRS</code> environment variable
to <code>true</code> in your workflow.</li>
</ul>
</li>
<li>
<p>Fixed <a
href="https://redirect.github.com/github/codeql-action/issues/3555">a
bug</a> which caused the CodeQL Action to fail loading repository
properties if a &quot;Multi select&quot; repository property was
configured for the repository. <a
href="https://redirect.github.com/github/codeql-action/pull/3557">#3557</a></p>
</li>
<li>
<p>The CodeQL Action now loads <a
href="https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization">custom
repository properties</a> on GitHub Enterprise Server, enabling the
customization of features such as
<code>github-codeql-disable-overlay</code> that was previously only
available on GitHub.com. <a
href="https://redirect.github.com/github/codeql-action/pull/3559">#3559</a></p>
</li>
<li>
<p>Once <a
href="https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries">private
package registries</a> can be configured with OIDC-based authentication
for organizations, the CodeQL Action will now be able to accept such
configurations. <a
href="https://redirect.github.com/github/codeql-action/pull/3563">#3563</a></p>
</li>
<li>
<p>Fixed the retry mechanism for database uploads. Previously this would
fail with the error &quot;Response body object should not be disturbed
or locked&quot;. <a
href="https://redirect.github.com/github/codeql-action/pull/3564">#3564</a></p>
</li>
<li>
<p>A warning is now emitted if the CodeQL Action detects a repository
property whose name suggests that it relates to the CodeQL Action, but
which is not one of the properties recognised by the current version of
the CodeQL Action. <a
href="https://redirect.github.com/github/codeql-action/pull/3570">#3570</a></p>
</li>
</ul>
<h2>4.32.6 - 05 Mar 2026</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/github/codeql-action/commit/95e58e9a2cdfd71adc6e0353d5c52f41a045d225"><code>95e58e9</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3824">#3824</a>
from github/update-v4.35.2-d2e135a73</li>
<li><a
href="https://github.com/github/codeql-action/commit/6f31bfe060e817d81e938dbec767969d20031e25"><code>6f31bfe</code></a>
Update changelog for v4.35.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/d2e135a73a39154e3a231aeb49163c4661c5b8b1"><code>d2e135a</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3823">#3823</a>
from github/update-bundle/codeql-bundle-v2.25.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/60abb65df09fcf213c398e064c8a80db1f15cdaf"><code>60abb65</code></a>
Add changelog note</li>
<li><a
href="https://github.com/github/codeql-action/commit/5a0a562209255e956ad8aafcee303294e64eefa2"><code>5a0a562</code></a>
Update default bundle to codeql-bundle-v2.25.2</li>
<li><a
href="https://github.com/github/codeql-action/commit/65216971a11ded447a6b76263d5a144519e5eee1"><code>6521697</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3820">#3820</a>
from github/dependabot/github_actions/dot-github/wor...</li>
<li><a
href="https://github.com/github/codeql-action/commit/3c45af2dd258e1623af1898da5c86545b514e028"><code>3c45af2</code></a>
Merge pull request <a
href="https://redirect.github.com/github/codeql-action/issues/3821">#3821</a>
from github/dependabot/npm_and_yarn/npm-minor-345b93...</li>
<li><a
href="https://github.com/github/codeql-action/commit/f1c339364c12f922998186ed897e45e3b4ae8874"><code>f1c3393</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/1024fc496c87e944a93e98d8cf2c09e2c7602a30"><code>1024fc4</code></a>
Rebuild</li>
<li><a
href="https://github.com/github/codeql-action/commit/9dd4cfed96030ccdfe1af4daf7a7964322704fed"><code>9dd4cfe</code></a>
Bump the npm-minor group across 1 directory with 6 updates</li>
<li>Additional commits viewable in <a
href="https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-23 21:02:44 +01:00
Alex 819d794039 UI enhancement pass: Image streaming, dropdown UI fixes (#909)
- Added max image sizes and compression for frontend cached images
- Fixed various UI issues with dropdown placement and animation
2026-04-23 20:57:15 +01:00
Alex e0980a84d9 Fix temp filename max size (#912)
Fixes #891
2026-04-23 20:57:00 +01:00
Alex b8fdb2c841 Backend auth config check (#911)
Enforces auth config required fields, providing a warning if fields are
left empty upon save

Fixes #907
2026-04-23 20:56:45 +01:00
Alex 8bba0e28d7 Improved combined search behavior (#910)
- Added functionality to continue with a combined search if one option
is unfulfilled
- Added option to deselect currently selected release

Fixes #890
2026-04-23 20:56:32 +01:00
Alex 791ba184ee PrimaryTitle field and path template enhancements (#908)
- Added `PrimaryTitle` field for renaming templates
- Improved UI for creating a template, including live preview and custom
field picker

Fixes #905
2026-04-23 20:56:10 +01:00
Alex e35b4c47a7 Direct source refactor (#895)
- Updated mirror selection
- Removed built-in mirror options, users must provide their own
configurations
- Set Universal search to default, added ability to disable direct
source
- Updated documentation
- Updated makefile
2026-04-15 18:50:13 +01:00
blades 18a3f0bf44 Newznab capability (#867)
I've added a plugin using the same architecture as the prowlarr plugin
to enable Newznab as a source.
I've tested locally with nzbhydra2 and it all seems to work as intended.
I've added some unit tests for this feature, and found that a couple of
other unit tests weren't behaving so fixed those up while I was at it. I
also ran all of the linters in the makefile against it and fixed those
up, too, so hopefully this should be as clean and as compatible as it
can be.
2026-04-14 09:43:03 +01:00
Alex 0f7bcf8fd9 Fix lockfile (#888) 2026-04-13 11:40:41 +01:00
Alex 98f891916d Remove slash cleanup for OIDC discovery URL (#887)
Fixes #869
2026-04-13 11:21:44 +01:00
Alex a7694eb8ad Frontend tooling + Linter pass + React rule enforcement (#886)
- Added `oxlint`, `oxfmt`, `vitest`, `knip`
- Configured oxlint rules including react best practices (e.g. for
effect usage)
- Full linting pass on frontend code
- Full react rules pass on effect usage
- Full reformatting using oxfmt
- Full dead code cleanup using knip
2026-04-13 10:56:09 +01:00
Alex 87d5f127d6 Add prek + pytest-cov (#873) 2026-04-12 12:39:15 +01:00
Alex d7b9f2e67f Backend test hardening + quality enforcement (#872)
- Reworked many tests
- Enforcing lint + type checking for test suite
- Fixed various issues surfaced by the new tests
- CI tweaks
2026-04-12 12:01:52 +01:00
Alex 41c4aa1d72 Updated permissions model and non-root support (#871)
- Adds a non-root startup path at user 1000:1000 - skips privilege
escalation and ownership checks. Works e.g. for kubernetes deployments
(user 1000:1000 and runAsNonRoot enabled).
- Remove startup check/chown commands for user-owned folders. Checks can
be done with a "Test destination" button in settings which performs a
test write. Users are responsible for fixing their own permissions.
- Update docs
2026-04-12 08:22:32 +01:00
Alex 704da62202 Typecheck enforcement (#870)
All BasedPyright standard rules enforced and corrected
2026-04-12 07:35:36 +01:00
Alex 8d98e122ec Linter followup (#868)
Expanded Ruff rules and completed fixes
2026-04-11 16:18:52 +01:00
Alex 28eef75de0 Update path handling errors (#864) 2026-04-11 08:29:21 +01:00
Alex b3b8f34a13 Fix JSON script blocking behavior + tests (#862)
Fixes #859
2026-04-10 20:46:07 +01:00
Alex 8e78fea947 Add BasedPyright + Makefile commands (#858) 2026-04-10 17:12:54 +01:00
Alex 7bc6a9f8c6 Switch dev builds to nightly schedule (#856)
- `dev` images generated on a nightly schedule if new commits exist
- lite container smoke test added to PR CI checks
2026-04-10 15:12:23 +01:00
Alex 962e0ec68b Regenerate frontend lockfile (#855) 2026-04-10 14:33:47 +01:00
Alex 3d68b5eb2f Bump Vite to 8.0.8 + Typescript to 6.0.2 (#854) 2026-04-10 14:26:14 +01:00
dependabot[bot] ba4090aee2 Bump ruff from 0.15.9 to 0.15.10 (#848)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.9 to 0.15.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.15.10</h2>
<h2>Release Notes</h2>
<p>Released on 2026-04-09.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-logging</code>] Allow closures in except handlers
(<code>LOG004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24464">#24464</a>)</li>
<li>[<code>flake8-self</code>] Make <code>SLF</code> diagnostics robust
to non-self-named variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24281">#24281</a>)</li>
<li>[<code>flake8-simplify</code>] Make the fix for
<code>collapsible-if</code> safe in <code>preview</code>
(<code>SIM102</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24371">#24371</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Avoid emitting multi-line f-string elements before Python 3.12 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24377">#24377</a>)</li>
<li>Avoid syntax error from <code>E502</code> fixes in f-strings and
t-strings (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24410">#24410</a>)</li>
<li>Strip form feeds from indent passed to <code>dedent_to</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24381">#24381</a>)</li>
<li>[<code>pyupgrade</code>] Fix panic caused by handling of octals
(<code>UP012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24390">#24390</a>)</li>
<li>Reject multi-line f-string elements before Python 3.12 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24355">#24355</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>ruff</code>] Treat f-string interpolation as potential side
effect (<code>RUF019</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24426">#24426</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Add support for custom file extensions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24463">#24463</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document adding fixes in CONTRIBUTING.md (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24393">#24393</a>)</li>
<li>Fix JSON typo in settings example (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24517">#24517</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/dylwil3"><code>@​dylwil3</code></a></li>
<li><a
href="https://github.com/silverstein"><code>@​silverstein</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/shizukushq"><code>@​shizukushq</code></a></li>
<li><a href="https://github.com/zanieb"><code>@​zanieb</code></a></li>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
</ul>
<h2>Install ruff 0.15.10</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.15.10/ruff-installer.sh
| sh
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.15.10</h2>
<p>Released on 2026-04-09.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>flake8-logging</code>] Allow closures in except handlers
(<code>LOG004</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24464">#24464</a>)</li>
<li>[<code>flake8-self</code>] Make <code>SLF</code> diagnostics robust
to non-self-named variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24281">#24281</a>)</li>
<li>[<code>flake8-simplify</code>] Make the fix for
<code>collapsible-if</code> safe in <code>preview</code>
(<code>SIM102</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24371">#24371</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Avoid emitting multi-line f-string elements before Python 3.12 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24377">#24377</a>)</li>
<li>Avoid syntax error from <code>E502</code> fixes in f-strings and
t-strings (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24410">#24410</a>)</li>
<li>Strip form feeds from indent passed to <code>dedent_to</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24381">#24381</a>)</li>
<li>[<code>pyupgrade</code>] Fix panic caused by handling of octals
(<code>UP012</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24390">#24390</a>)</li>
<li>Reject multi-line f-string elements before Python 3.12 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24355">#24355</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>ruff</code>] Treat f-string interpolation as potential side
effect (<code>RUF019</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24426">#24426</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Add support for custom file extensions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24463">#24463</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Document adding fixes in CONTRIBUTING.md (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24393">#24393</a>)</li>
<li>Fix JSON typo in settings example (<a
href="https://redirect.github.com/astral-sh/ruff/pull/24517">#24517</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a href="https://github.com/dylwil3"><code>@​dylwil3</code></a></li>
<li><a
href="https://github.com/silverstein"><code>@​silverstein</code></a></li>
<li><a
href="https://github.com/anishgirianish"><code>@​anishgirianish</code></a></li>
<li><a
href="https://github.com/shizukushq"><code>@​shizukushq</code></a></li>
<li><a href="https://github.com/zanieb"><code>@​zanieb</code></a></li>
<li><a
href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/252f76102a618bff6537b6c53c316ca3837f4abf"><code>252f761</code></a>
Bump 0.15.10 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24519">#24519</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/37a1ec8bb8e30955787b0cdf6e97f7f2254dba7f"><code>37a1ec8</code></a>
[ty] Fix assignability of intersections with bounded typevars (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24502">#24502</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/f518cc9ca0c830773dd49c3964eb5e49d52c8aed"><code>f518cc9</code></a>
[ty] Allow partially stringified <code>type[…]</code> annotations (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24518">#24518</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/16c4090d0a711b9c0523b932014f3daf140f35bc"><code>16c4090</code></a>
docs: fix JSON typo in settings example (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24517">#24517</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/99d97bd72f1934ac2af93e52468c10ef1c7a1a4e"><code>99d97bd</code></a>
[ty] Tighten up a few edge cases in <code>Concatenate</code>
type-expression parsing (<a
href="https://redirect.github.com/astral-sh/ruff/issues/2">#2</a>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/2714e345bdd64a5baae3844c0d25db7b0b9fe330"><code>2714e34</code></a>
[ty] Enable <code>pull-diagnostics</code> by default in E2E tests (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24516">#24516</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/d8bc700722ab1b7272a4d724839da7c569b349d4"><code>d8bc700</code></a>
LSP: Add support for custom extensions (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24463">#24463</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/a45f96d65dbd4f958b07accd718f8d2af48cb956"><code>a45f96d</code></a>
[ty] stop special-casing str constructor (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24514">#24514</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/87a0f01cfd016e0297ef05ab638cde006bf8d947"><code>87a0f01</code></a>
[ruff] Treat f-string interpolation as potential side effect in RUF019
(<a
href="https://redirect.github.com/astral-sh/ruff/issues/24426">#24426</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/e9ba8489b8d1f1fd5fd66887a74d5f2f58f733d4"><code>e9ba848</code></a>
[ty] Fix excess subscript argument inference for non-generic types (<a
href="https://redirect.github.com/astral-sh/ruff/issues/24354">#24354</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.15.9...0.15.10">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ruff&package-manager=uv&previous-version=0.15.9&new-version=0.15.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-10 13:40:28 +01:00
dependabot[bot] 03ec7d1c06 Bump the gh-actions group across 1 directory with 2 updates (#851)
Bumps the gh-actions group with 2 updates in the / directory:
[docker/build-push-action](https://github.com/docker/build-push-action)
and [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv).

Updates `docker/build-push-action` from 7.0.0 to 7.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.1.0</h2>
<ul>
<li>Git context <a
href="https://docs.docker.com/build/concepts/context/#url-queries">query
format</a> support by <a
href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in <a
href="https://redirect.github.com/docker/build-push-action/pull/1505">docker/build-push-action#1505</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.79.0 to 0.87.0 by
<a href="https://github.com/crazy-max"><code>@​crazy-max</code></a> in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1505">docker/build-push-action#1505</a></li>
<li>Bump brace-expansion from 1.1.12 to 1.1.13 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1500">docker/build-push-action#1500</a></li>
<li>Bump fast-xml-parser from 5.4.2 to 5.5.7 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1489">docker/build-push-action#1489</a></li>
<li>Bump flatted from 3.3.3 to 3.4.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1491">docker/build-push-action#1491</a></li>
<li>Bump glob from 10.3.12 to 10.5.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1490">docker/build-push-action#1490</a></li>
<li>Bump handlebars from 4.7.8 to 4.7.9 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1497">docker/build-push-action#1497</a></li>
<li>Bump lodash from 4.17.23 to 4.18.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1510">docker/build-push-action#1510</a></li>
<li>Bump picomatch from 4.0.3 to 4.0.4 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1496">docker/build-push-action#1496</a></li>
<li>Bump undici from 6.23.0 to 6.24.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1486">docker/build-push-action#1486</a></li>
<li>Bump vite from 7.3.1 to 7.3.2 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1509">docker/build-push-action#1509</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.0.0...v7.1.0">https://github.com/docker/build-push-action/compare/v7.0.0...v7.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/build-push-action/commit/bcafcacb16a39f128d818304e6c9c0c18556b85f"><code>bcafcac</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1509">#1509</a>
from docker/dependabot/npm_and_yarn/vite-7.3.2</li>
<li><a
href="https://github.com/docker/build-push-action/commit/18e62f1158d9c45a4a84a58a6828d21f8ed3644b"><code>18e62f1</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1510">#1510</a>
from docker/dependabot/npm_and_yarn/lodash-4.18.1</li>
<li><a
href="https://github.com/docker/build-push-action/commit/46580d2c9d43b0888270cb6fa90956e483de56fc"><code>46580d2</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/3f80b252ca2331f6ec3e890f4346b5506ee1dc81"><code>3f80b25</code></a>
chore(deps): Bump lodash from 4.17.23 to 4.18.1</li>
<li><a
href="https://github.com/docker/build-push-action/commit/efeec9557c40a646afe433e39a1e94ca689103f0"><code>efeec95</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1505">#1505</a>
from crazy-max/refactor-git-context</li>
<li><a
href="https://github.com/docker/build-push-action/commit/ddf04b08eb12882258ed936fea4a2806754ff349"><code>ddf04b0</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1511">#1511</a>
from docker/dependabot/github_actions/crazy-max-dot-...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/db08d97a08e4a0d15f85d1c4e64dfd5f88cbe1a9"><code>db08d97</code></a>
chore(deps): Bump the crazy-max-dot-github group with 2 updates</li>
<li><a
href="https://github.com/docker/build-push-action/commit/ef1fb9688fc3626d0fd5e462f502cbbdc6456feb"><code>ef1fb96</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1508">#1508</a>
from docker/dependabot/github_actions/docker/login-a...</li>
<li><a
href="https://github.com/docker/build-push-action/commit/2d8f2a1a378a5c302dcd7b2b4326cefa24180bb1"><code>2d8f2a1</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/build-push-action/commit/919ac7bd7d1aa8cb13fe4de76545abea8d8b5ed2"><code>919ac7b</code></a>
fix test since secrets are not written to temp path anymore</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/build-push-action/compare/d08e5c354a6adb9ed34480a06d141179aa583294...bcafcacb16a39f128d818304e6c9c0c18556b85f">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 7.3.1 to 8.0.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.0 🌈 Immutable releases and secure tags</h2>
<h1>This is the first immutable release of <code>setup-uv</code> 🥳</h1>
<p>All future releases are also immutable, if you want to know more
about what this means checkout <a
href="https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases">the
docs</a>.</p>
<p>This release also has two breaking changes</p>
<h2>New format for <code>manifest-file</code></h2>
<p>The previously deprecated way of defining a custom version manifest
to control which <code>uv</code> versions are available and where to
download them from got removed. The functionality is still there but you
have to use the <a
href="https://github.com/astral-sh/setup-uv/blob/main/docs/customization.md#format">new
format</a>.</p>
<h2>No more major and minor tags</h2>
<p>To increase <strong>security</strong> even more we will <strong>stop
publishing minor tags</strong>. You won't be able to use
<code>@v8</code> or <code>@v8.0</code> any longer. We do this because
pinning to major releases opens up users to supply chain attacks like
what happened to <a
href="https://unit42.paloaltonetworks.com/github-actions-supply-chain-attack/">tj-actions</a>.</p>
<blockquote>
<p>[!TIP]
Use the immutable tag as a version
<code>astral-sh/setup-uv@v8.0.0</code>
Or even better the githash
<code>astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57</code></p>
</blockquote>
<h2>🚨 Breaking changes</h2>
<ul>
<li>Remove update-major-minor-tags workflow <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/826">#826</a>)</li>
<li>Remove deprecrated custom manifest <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/813">#813</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>Shortcircuit latest version from manifest <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/828">#828</a>)</li>
<li>Simplify inputs.ts <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/827">#827</a>)</li>
<li>Bump release-drafter to v7.1.1 <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/825">#825</a>)</li>
<li>Refactor inputs <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/823">#823</a>)</li>
<li>Replace inline compile args with tsconfig <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/824">#824</a>)</li>
<li>chore: update known checksums for 0.11.2 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/821">#821</a>)</li>
<li>chore: update known checksums for 0.11.1 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/817">#817</a>)</li>
<li>chore: update known checksums for 0.11.0 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/815">#815</a>)</li>
<li>Fix latest-version workflow check <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/812">#812</a>)</li>
<li>chore: update known checksums for 0.10.11/0.10.12 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/811">#811</a>)</li>
</ul>
<h2>v7.6.0 🌈 Fetch uv from Astral's mirror by default</h2>
<h2>Changes</h2>
<p>We now default to download uv from <code>releases.astral.sh</code>.
This means by default we don't hit the GitHub API at all and shouldn't
see any rate limits and timeouts any more.</p>
<h2>🚀 Enhancements</h2>
<ul>
<li>Fetch uv from Astral's mirror by default <a
href="https://github.com/zsol"><code>@​zsol</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/809">#809</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>Switch to ESM for source and test, use CommonJS for dist <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/806">#806</a>)</li>
<li>chore: update known checksums for 0.10.10 @<a
href="https://github.com/apps/github-actions">github-actions[bot]</a>
(<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/804">#804</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cec208311dfd045dd5311c1add060b2062131d57"><code>cec2083</code></a>
Shortcircuit latest version from manifest (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/828">#828</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/4dd8ab45206a76f8c1dfe399fa88df10a7264f27"><code>4dd8ab4</code></a>
Simplify inputs.ts (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/827">#827</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/7fdbe7cf0c8ef50cfd0878eed7b5180abc6b53c7"><code>7fdbe7c</code></a>
Remove update-major-minor-tags workflow (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/826">#826</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/485abd05e5c74a247f0a309e333d2433ab9a353a"><code>485abd0</code></a>
Bump release-drafter to v7.1.1 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/825">#825</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f82eb19c06057c455674b2602e0139fd906f1428"><code>f82eb19</code></a>
Refactor inputs (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/823">#823</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/868d1f74d9d862d7b40219546bfe35299c6dd452"><code>868d1f7</code></a>
Replace inline compile args with tsconfig (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/824">#824</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/447e6d02b15d65b3247cce2d6019f11957285d11"><code>447e6d0</code></a>
chore: update known checksums for 0.11.2 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/821">#821</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/5c62c5926145985eec91f09e2e0a75f40daed929"><code>5c62c59</code></a>
chore: update known checksums for 0.11.1 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/817">#817</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e1a7373adb857afd2a70b971e8ebdacc64ed27d0"><code>e1a7373</code></a>
chore: update known checksums for 0.11.0 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/815">#815</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/89709315bb3bd4bf0f4b1db4b710e99009087ab5"><code>8970931</code></a>
Remove deprecrated custom manifest (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/813">#813</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/5a095e7a2014a4212f075830d4f7277575a9d098...cec208311dfd045dd5311c1add060b2062131d57">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-10 13:40:18 +01:00
dependabot[bot] 71ee56b7b7 Bump the npm-deps group across 1 directory with 4 updates (#852)
Bumps the npm-deps group with 4 updates in the /src/frontend directory:
[react](https://github.com/facebook/react/tree/HEAD/packages/react),
[react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom),
[@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)
and [postcss](https://github.com/postcss/postcss).

Updates `react` from 19.2.4 to 19.2.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react's
releases</a>.</em></p>
<blockquote>
<h2>19.2.5 (April 8th, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Add more cycle protections (<a
href="https://redirect.github.com/facebook/react/pull/36236">#36236</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> and
<a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/23f4f9f30da9e9af2108c18bb197bae75ab584ea"><code>23f4f9f</code></a>
19.2.5</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.5/packages/react">compare
view</a></li>
</ul>
</details>
<br />

Updates `react-dom` from 19.2.4 to 19.2.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/facebook/react/releases">react-dom's
releases</a>.</em></p>
<blockquote>
<h2>19.2.5 (April 8th, 2026)</h2>
<h2>React Server Components</h2>
<ul>
<li>Add more cycle protections (<a
href="https://redirect.github.com/facebook/react/pull/36236">#36236</a>
by <a href="https://github.com/eps1lon"><code>@​eps1lon</code></a> and
<a
href="https://github.com/unstubbable"><code>@​unstubbable</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/facebook/react/commit/23f4f9f30da9e9af2108c18bb197bae75ab584ea"><code>23f4f9f</code></a>
19.2.5</li>
<li>See full diff in <a
href="https://github.com/facebook/react/commits/v19.2.5/packages/react-dom">compare
view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 25.5.0 to 25.6.0
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />

Updates `postcss` from 8.5.8 to 8.5.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/releases">postcss's
releases</a>.</em></p>
<blockquote>
<h2>8.5.9</h2>
<ul>
<li>Speed up source map encoding paring in case of the error.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/blob/main/CHANGELOG.md">postcss's
changelog</a>.</em></p>
<blockquote>
<h2>8.5.9</h2>
<ul>
<li>Speed up source map encoding paring in case of the error.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/postcss/postcss/commit/fe88ac29c06b7b218be32994cdc6ca1525bdf2c9"><code>fe88ac2</code></a>
Release 8.5.9 version</li>
<li><a
href="https://github.com/postcss/postcss/commit/c551632496b87ab3f1965bfda5dc386b6c71963e"><code>c551632</code></a>
Avoid RegExp when we can use simple JS</li>
<li><a
href="https://github.com/postcss/postcss/commit/89a6b744060eb8dee743351c785a9fbe37d4525a"><code>89a6b74</code></a>
Move SECURITY.txt for docs folder to keep GitHub page cleaner</li>
<li><a
href="https://github.com/postcss/postcss/commit/6ceb8a46af9f9de821faee98f861bdf84617347b"><code>6ceb8a4</code></a>
Create SECURITY.md</li>
<li><a
href="https://github.com/postcss/postcss/commit/02ccae6bc359ee386f84d8fbc36eb423acbdbc3f"><code>02ccae6</code></a>
Another way to fix CI with .ts ext in tests on old Node.js</li>
<li><a
href="https://github.com/postcss/postcss/commit/2c36658c7cd4ffee4d42fafd0a501b9c13b63a52"><code>2c36658</code></a>
Another way to fix CI with TS on old Node.js</li>
<li><a
href="https://github.com/postcss/postcss/commit/b90600361f33a3834fd708831819cb1106590908"><code>b906003</code></a>
Another way to fix CI with old Node.js</li>
<li><a
href="https://github.com/postcss/postcss/commit/04d32cdc69ac598fcd33d3d748de12c4c32e83fb"><code>04d32cd</code></a>
Fix another issue with Node.js 10 on CI</li>
<li><a
href="https://github.com/postcss/postcss/commit/df86cdfff016205260901394432574ecd2a2fa65"><code>df86cdf</code></a>
Try to fix Node.js 10 on CI</li>
<li><a
href="https://github.com/postcss/postcss/commit/82bec0dd8e194f653743f606e6a2b7e27cde9088"><code>82bec0d</code></a>
Move to oxfmt</li>
<li>Additional commits viewable in <a
href="https://github.com/postcss/postcss/compare/8.5.8...8.5.9">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-10 13:40:08 +01:00
Alex e3d5bd91fc Bump node to 24 LTS (#853) 2026-04-10 13:29:48 +01:00
Alex af38540991 Group dependabot PRs (#849) 2026-04-10 13:07:59 +01:00
Alex 3a3a3ce449 Add new python tooling + apply ruff linter cleanup (#845)
- Adds `uv`, `ruff`, `pyright`, `vulture` and `pytest-xdist`
- Move project, lockfile, docker build etc to uv
- Align python tooling on 3.14
- Huge bulk of ruff linter fixes applied. Still in progress but all the
core types are now enforced
- Update CI and test helpers
2026-04-10 13:03:25 +01:00
Alex ff094bed56 Fix: Orchestrator timeout and exception handling (#832)
Fixes #823
2026-04-03 09:38:58 +01:00
Alex c1143f808a Batch dependency updates (#831)
- github/codeql-action 3.32.6 → 4.35.1
- seleniumbase 4.47.3 → 4.47.9
- react-router-dom 7.13.1 → 7.14.0
- docker/login-action 3.7.0 → 4.1.0
- tailwindcss 4.2.1 → 4.2.2
- @tailwindcss/vite 4.2.1 → 4.2.2
- @tailwindcss/postcss 4.2.1 → 4.2.2
- actions/setup-python 5.6.0 → 6.2.0
- docker/setup-buildx-action 3.12.0 → 4.0.0
2026-04-03 09:36:31 +01:00
Alex 9bfcf828ea Fixes: Env variable config usage, retry availability, Entrypoint permissions (#817)
- Clean up a few uses of config options that may miss the env variable
if this is set
- Add enhanced retry availability utilising the DB to persist download
errors / retries across restarts, request failures, and pass Prowlarr
detail through the download task to maintain retry data.
- Strip back entrypoint permissions for less intensive chown operations.

Fixes #796
2026-03-29 16:39:40 +01:00
Alex 678c54cba2 Fixes: Entrypoint, seedtime, request policy flow (#805)
- Added a path for rootless permissions in the entrypoint script
- Routed prowlarr searches through torznab for seedtime info
- Added additional request flow for download permissions
2026-03-25 18:34:42 +00:00
Alex 019d36b27e Rename Booklore to Grimmory 2 (#792) 2026-03-21 15:48:06 +00:00
Alex 698eb07e71 Rename Booklore to Grimmory (#791) 2026-03-21 15:38:38 +00:00
Alex 8f949a73d5 Remove audible provider (#778) 2026-03-18 18:29:13 +00:00
Alex 2c6f46fc88 Combined mode follow-up (#777) 2026-03-18 18:27:39 +00:00
Alex 3f90c3805f Use title+author query for whitelisted indexers (#774) 2026-03-16 19:52:43 +00:00
Alex cb093f61c6 Feature: Combined book+audiobook downloads (#773)
- Adds a combined search option in the search bar selector
- Choose both a book and audiobook file in a two-step release modal, and
download both simultaneously from a single search result.
- Works for requests. Request both a book+audiobook at once, or works
seamlessly with request policies that differ between book + audiobook
(E.g. automatically download the ebook portion, while the audiobook gets
sent as a request)
- Hidden for users who have book or audiobooks blocked. 

Closes #611
2026-03-16 18:34:46 +00:00
Alex b464d62672 Fix entrypoint gosu test write (#772)
- Let gosu run the full test write
- Delete stale compose

Fixes #771 - gosu pipe broken on Proxmox LXC installs
2026-03-15 18:04:41 +00:00
Alex f3f26488b1 Fix TS error (#770) 2026-03-15 10:27:03 +00:00
Alex fec9d31c8a Frontend improvements for Audible provider (#769)
- Added square artwork support
- Added dedicated length and narrator icons
- Added audiobook info to release and details modals
- Moved search options button to accommodate larger Audible search
fields
2026-03-15 10:17:37 +00:00
cadric 3295be82a7 Add Audible metadata provider via Audimeta (#762)
Closes #515

  ## Summary

This adds a new `audible` metadata provider backed by the Audimeta API.

  The provider supports:
  - Audible/Audimeta metadata lookup without authentication
- region selection (`us`, `ca`, `uk`, `au`, `fr`, `de`, `jp`, `it`,
`in`, `es`, `br`)
  - ASIN book lookup
  - ISBN lookup with fallback search
  - series suggestions and series-order browsing
- richer audiobook metadata such as narrators, runtime, rating,
subtitle, cover, publisher, and series info
- configurable Audimeta base URL, timeout, cache usage, default sort,
and unreleased filtering

  ## Notes

  A few Audimeta-specific integration details were needed:
- send a meaningful `User-Agent`, otherwise Audimeta rejects requests
with `403`
  - send the `cache` parameter in the format Audimeta expects
- use `keywords` for general search instead of `query`, which gave
poor/irrelevant results for title-style
  searches

  ## Validation

  Tested locally with:
  - `python -m py_compile shelfmark/metadata_providers/audible.py`
  - `python -m pytest tests/metadata/test_audible.py -v`
- `python -m pytest
tests/metadata/test_metadata_provider_capabilities.py -v`

  Also verified manually in a Podman test container:
  - searching for `Discount Dan` returns Audible title `B0DXLXRNGG`
  - book details and series metadata load correctly

  ## Scope

This PR intentionally keeps the change localized to the provider layer
and docs:
  - new Audible provider
  - provider registration
  - provider docs
  - generated environment variable docs
2026-03-15 10:09:24 +00:00
Alex fff0fd07a1 Fix stale activity dismiss handling (#768)
Fixes #764
2026-03-15 10:08:45 +00:00
Alexanddependabot[bot] 3f1a14843b Update to React 19 (#766)
Supersedes the React dependabot patches
- `react`
- `react-dom`
- `@types/react`
- `@types/react-dom`

Left out Vite / tooling updates

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-13 18:46:56 +00:00
Alexanddependabot[bot] 21a11b06b9 Dependency updates roll-up (#765)
Supersedes the dependabot PRs after testing: 
- `actions/attest-build-provenance`
- `docker/build-push-action`
- `actions/checkout`
- `seleniumbase`
- `docker/metadata-action`
- `actions/setup-node`
- `python:3.14-slim`
- `@types/node`
- `postcss`
- `react-router-dom`

Left out for now: 
- `node:25-alpine`
- `vite@8`
- `@vitejs/plugin-react@6`

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-13 18:41:02 +00:00
Alex 0d856a3ef5 CodeQL fixes (#763)
- Block SSRF in image cover proxy (validate URL scheme and reject
private IPs)
- Sanitize settings tab name to prevent path traversal
2026-03-13 17:47:34 +00:00
Alex ebf4312174 Repo spring cleaning (#746)
- Add CI workflow (pytest + frontend typecheck/tests) on PRs
- Add CodeQL static analysis for Python and JS/TS
- Add Dependabot for pip, npm, Docker, and GitHub Actions
- Tighten workflow permissions
2026-03-13 17:09:49 +00:00
Alex 685c35d552 Hardcover list separation + Browser download fix (#745)
- Added full Hardcover reading status types into the list selector
- Split reading status entries from dedicated lists
- Added option to disable the automatic removal of books when downloaded
from a Hardcover list
- Fixed browser download not firing when the completed state was
triggered in specific cases
2026-03-13 14:33:10 +00:00
Alex 3d72f9e258 Various requested small features (#741)
- Added torrent removal option
- Pass Prowlarr seedtimes to download clients (excluding rTorrent)
- Split default release source option by content type
- Split download to browser option by content type
- Add "hide links" option
2026-03-12 17:36:07 +00:00
Alex 7f79da11e6 Activity routes logging (#736)
- Added specific logging for activity routes errors
- Fixed scrollbars
2026-03-11 19:59:12 +00:00
Alex c59ea46540 Frontend update + Misc fixes (#735)
- Updated frontend CSS to Tailwind v4
- Reverted socket IO origin restriction
- Fixed search queries not persisting after auth redirect
- Move advanced search options to left UI selector
- Unlock IRC source to be used for audiobook content_type
- Tweaked security settings env var syncing to be prioritised
- Fix AA "all languages" query generation
- Added language-free AA query as second fallback in case of no results
- Testing moving SeleniumBase scratch files to /tmp via symlink
- Added enhanced logging for activity dismissals and other events
- Removed iFrame restrictions
2026-03-11 18:16:34 +00:00
Alex a2a5a22324 Fix theming bug (#722) 2026-03-07 19:13:28 +00:00
Alex a7db7f04e9 Hardcover tweaks (#720) 2026-03-07 18:16:40 +00:00
Alex 9d08bb3ef1 Expanded Hardcover list features (#719)
- Adds full interaction with Hardcover lists, including adding and
removing from lists + want to read status
- List selection exposed in search results, details modal and release
modal
- Added automatic list dropdown when selecting "list" search
- Added auto-removal of books from a list when downloading from that
specific list page
- Changed search selector to hover-activated
2026-03-07 15:33:46 +00:00
Alex 80aa289a64 Misc fixes (#718)
- Update file movement to prefer copy
- Improved mirror config overwriting on app updates
- Request / user DB hardening
2026-03-07 10:30:47 +00:00
Alex edb437e905 Fix sorting + update readme (#715)
- Harden default sort preference use + fix series ordering use
- Update readme with contribution and project scope disclaimers
2026-03-06 17:06:20 +00:00
Alex 72464e32b8 Update makefile test (#713) 2026-03-06 15:00:05 +00:00
Alex 60893b19c6 Search UI revamp, series search and search suggestions (#712)
- Restructured search field options into the left-hand selector.
Includes dynamic options for each provider.
- Moved Hardcover list and manual search mode into the left hand
selector
- Added search mode and metadata provider into the search options area
- Added new Hardcover series API query and live series suggestions
- Added live Hardcover author and title suggestions
2026-03-06 14:44:55 +00:00
Alex 8bb188c903 Refactor direct source to use universal API (#711) 2026-03-06 12:59:37 +00:00
Alex d6d10a450e Enhance Hardcover lists (#710) 2026-03-06 10:45:15 +00:00
Alex 4b0d1aef13 Download history refactor pt3 (#706)
- Added canonical per-user visibility of requests and downloads via new
activity view table. Users get fully independent activity and history
views, while admins still see all.
- Replaces janky frontend + backend combination
2026-03-05 19:53:22 +00:00
Giovanni Scieri 447ed1a924 fix(search): include default language in search query filters (#704)
## Bug description

When a default language was configured, it was **not passed as a search
filter**.
This occurred regardless of configuration via UI or environment
variables.

## Fix

Updated filter logic so that the default language is always applied when
no explicit filter is provided:

```python
for value in filters.lang if filters.lang else config.BOOK_LANGUAGE or []:
    if value and value != "all":
        filters_query += f"&lang={quote(value)}"
```

This ensures:
- the default language is used when available
- empty or invalid values are ignored
- "all" does not apply a language filter

## Testing
- default language via UI → search filters correctly
- default language via environment variable → search filters correctly
- "all" value → no language filter applied
2026-03-05 16:25:19 +00:00
Alex ba92ad90bc Refine UI and adjust content type settings (#705)
- Tweak manual search toggle position
- Refinements to the Hardcover list dropdown behavior
- Hide the content type dropdown when a content type is blocked for a
user
- Fixes to Hardcover author parsing to strip out initialed names
- Remove `env_supported=false` for security config options.
2026-03-05 16:24:03 +00:00
Alex cce2c10704 Download history refactor pt.2 (#703)
Two-phase download history: downloads are now recorded in the DB at
queue time (not just at terminal time), eliminating the need to
reconstruct metadata in the terminal hook and removing the
`_is_graduated_request_download()` request-scan mess
2026-03-05 13:06:34 +00:00
Alex fbe25725d3 Download history refactor (#700)
- Much simpler handling of downloads in the activity sidebar, and
improved storage, persistence and UI behavior.
- Replace `ActivityService` with direct storage on
`DownloadHistoryService` and `download_requests` and removes the
activity_log/activity_dismissals tables
- Simplify no-auth mode by removing the fake user row pattern, handled
internally
- Add local download fallback so history entries can still serve files
after tasks leave the queue
- Downloads, requests and history are now entirely persistent between
updates / restarts, and correctly tied to each user.
2026-03-04 19:10:06 +00:00
Alex bd65bccf52 Fix: Refresh mirrors (#695) 2026-03-03 22:14:18 +00:00
Alex 71900e00db Feature: Hardcover list search (#694)
- Adds the functionality to search Hardcover lists, either public lists
or user's private lists
- Paste a list URL into the search box to view results
- Select a specific list from user's collection from advanced fields
dropdown
- Fixes content_type parameter in URL search query to use book/audiobook
2026-03-03 21:53:43 +00:00
Alex de18f2b9fe Fix: File movement trigger event (#691)
Creates IN_MOVED_TO event, fixes CWA ingest folder detection when file
movement fallback occurs
2026-03-03 18:00:48 +00:00
Alex 6718848cfb Feature: Manual search option (#687)
- Adds a toggle to advanced search fields to search sources manually
instead of using metadata
- Hidden for users when "Request Book" or "Blocked" default policy is in
effect.
2026-03-02 18:41:03 +00:00
Alex 7d992c3918 User DB cleanup and refactor (#686)
- Refactored user and request code to avoid any database conflicts
- Fix threading behavior with custom script execution
- Harden the no_auth activity user filtering
- Add a hint to add local admin if none is created
- Added secret key to persist login states across updates / restarts
2026-03-02 15:41:15 +00:00
Alex 9593c040b0 Misc features: Retries, user search config, sort by format, admin download control (#679)
- Added the manual retry option for failed downloads
- Added the ability to retry failed post-processing using existing
downloaded file
- Added admin-visible "Download as" selector, admin chooses a user to
download on-behalf of - inherits their output preferences.
- Added search mode and default metadata provider / release source
options to User Preferences and My Account settings.
- Added sort by format option in release results
- Added {OriginalName} renaming field option, to retain the exact
downloaded filename
- Frontend dependency updates - fixes rollup vulnerability from this
week

Closes #662 #656 #649 #562
2026-03-01 19:47:57 +00:00
Alex ea0d06ae08 Further notification tweaks (#671)
- Improved multi-URL notification handling
- Tweak Apprise validation to catch errors earlier
- Much improved notification logging and UI response
- More robust notification tests
2026-02-28 10:16:01 +00:00
Alex 0f3a06bc9c Fix: User DB hardening and apprise tweak (#668) 2026-02-27 21:06:39 +00:00
Alex d78aad066b Fix: Apprise logging and no_auth hardening (#667)
- Passes apprise logging into shelfmark logs
- Update UI activity dismissal when no authentication is active
2026-02-27 15:49:14 +00:00
Alex e7d2845235 Fixes: Auth edge cases, apprise logging, scoring and release refactors (#665)
- Added migration for builtin auth users who used dev builds during
multi-user development
- Display apprise errors in logging
- Fix user provisioning in reverse proxy auth setups
- Refactor scoring and release modal utils
2026-02-27 10:21:06 +00:00
Alex ac36d539c8 Patch: Various fixes (#660)
Various fixes from the last couple days: 

- Add manual approval option for book/audiobook requests (#651)
- Add flagged HTTP headers 
- Add filesystem fallback - copy + delete when hardlink/move fails
across filesystems (#647)
- Dependency updates
- Tweak frontend test config (simplified tsconfig for tests)
- Fix overlapping sort scoring in release modal - duplicate scoring keys
caused incorrect release ordering (#654 )
- Fix stale search session after download - search state was not
refreshed when returning from a download (#659)
- Fix multi-format release filtering - releases with multiple formats
were incorrectly excluded by the format filter (#658)
- Fix config persistence when action button is used - clicking "Test
connection" reset unsaved settings (#657)
- Fix request grid text positioning in admin request policy panel 
- Fix rTorrent path discovery (#653)
- Fix `/login` API check (#650)
2026-02-25 18:44:46 +00:00
Alex 91cbd51b67 Fix flask version (#646) 2026-02-23 10:09:16 +00:00
Alex c80c88676c Fix direct search request flow (#644)
Fixes #643
2026-02-23 09:27:55 +00:00
Alex 0d271f1f69 Patch: Certificate validation setting + Misc fixes (#642)
- Add certificate validation setting
- Fix some OIDC providers not linking emails to local users
- Reintroduce sort by peers option for prowlarr results
- Fix "All languages" search query reverting to default language
- Fix download/request dismissal with multiple admin users
- Fix download / request behavior on details modal
2026-02-22 23:07:55 +00:00
Alex 014fc38b48 Patch: OIDC polish (#636)
- Added two env vars for OIDC login: 
- HIDE_LOCAL_AUTH - Remove the "password" option on login page when OIDC
enabled
  - OIDC_AUTO_REDIRECT - Immediately launch OIDC provider page
- Improved UX for initial OIDC setup, including creating a local admin
user
- Added callback URL label to OIDC setup page
- Fix Qbittorrent save path bug
2026-02-21 11:51:11 +00:00
Alex fdd46852f2 Add new docs (#633) 2026-02-20 18:07:43 +00:00
Alex a57d081caa Fix OIDC name fallback with limited responses (#632) 2026-02-20 16:24:37 +00:00
684 changed files with 111367 additions and 32683 deletions
+1
View File
@@ -1,6 +1,7 @@
.git
.github
.vscode
.local
.mypy_cache
README_images
.gitignore
+4 -4
View File
@@ -11,9 +11,9 @@ assignees: ''
## Steps To Reproduce
<!-- Steps to reproduce the behavior -->
1.
2.
3.
1.
2.
3.
## Expected Behavior
<!-- A clear and concise description of what you expected to happen -->
@@ -34,4 +34,4 @@ When running in debug mode, a DEBUG button will appear in the interface. Please
<!-- If applicable, please provide your full docker-compose (redacted from any secrets) -->
## Additional Context
<!-- Add any other context about the problem here -->
<!-- Add any other context about the problem here -->
+87
View File
@@ -0,0 +1,87 @@
version: 2
updates:
# Python dependencies
# Dependabot supports uv version updates, but GitHub currently lists uv
# security updates as "Not applicable"; daily checks keep uv.lock moving
# while repo-level Dependabot alerts/security updates cover supported ecosystems.
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "daily"
time: "05:00"
timezone: "Europe/London"
cooldown:
default-days: 3
open-pull-requests-limit: 10
groups:
python-deps:
patterns: ["*"]
update-types: ["minor", "patch"]
# Frontend npm dependencies
- package-ecosystem: "npm"
directory: "/src/frontend"
schedule:
interval: "weekly"
cooldown:
default-days: 3
open-pull-requests-limit: 10
groups:
npm-deps:
patterns: ["*"]
update-types: ["minor", "patch"]
# Dockerfile base image digests. When a tag stays the same, Dependabot titles
# can only show digest prefixes, so keep the group name explicit.
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 3
open-pull-requests-limit: 5
groups:
docker-base-image-digests:
# Exclude python from the group on purpose. Dependabot's Docker
# pre-release filter is bypassed for *grouped* updates
# (dependabot-core#9496), so a grouped python update proposes pre-release
# tags like python:3.15.0b2 as if they were a normal stable minor bump.
# node + uv stay grouped into a single digest PR.
patterns: ["*"]
exclude-patterns: ["python"]
ignore:
# Node.js: block major-version bumps so dependabot never proposes
# moving from one LTS line to a non-LTS "Current" release (e.g. 24 -> 25).
# Node LTS is even-numbered only; major bumps should be deliberate.
- dependency-name: "node"
update-types: ["version-update:semver-major"]
# Python: block minor/major bumps. Ungrouping python (above) is NOT enough
# to keep pre-releases out — dependabot-core#13815 rewrote the Docker
# pre-release heuristic to catch PEP 440 tags like 3.15.0a2 / 3.5.0b3, but
# the suffixed real tag still slipped through as PR #1169
# (python:3.14.6-slim -> python:3.15.0b3-slim). CPython spells
# pre-releases without a separator, so tag parsing reads 3.15.0b3 as an
# ordinary version that sorts above 3.14.6.
#
# A minor-version ignore blocks it regardless of spelling. Patch bumps
# (3.14.6 -> 3.14.7) and same-tag digest refreshes still land automatically.
# Moving the runtime to a new Python minor is a manual, deliberate change:
# bump the tag here and confirm C-extension wheels (greenlet/gevent) exist
# for it — a source build against a pre-release ABI boots an app that binds
# its port but never serves, which wedges e2e for the full 6h job limit.
- dependency-name: "python"
update-types:
["version-update:semver-major", "version-update:semver-minor"]
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 3
open-pull-requests-limit: 5
groups:
gh-actions:
patterns: ["*"]
@@ -1,11 +1,13 @@
name: Create and publish Docker images
on:
push:
branches:
- 'main'
tags:
- 'v*'
# Also dispatched on main by dev-image-debounce.yml, once main has been
# quiet for an hour, to publish the dev image.
workflow_dispatch:
permissions: read-all
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/shelfmark
@@ -27,20 +29,26 @@ jobs:
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for ${{ matrix.target }} image
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
env:
# Annotate both the per-platform manifests and the multi-arch image
# index. The index level is what manifest-list consumers (Renovate's
# minimumReleaseAge soak check, provenance/SBOM tooling) read for the
# standard org.opencontainers.image.* annotations, including `created`.
DOCKER_METADATA_ANNOTATIONS_LEVELS: index,manifest
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.image_name_suffix }}
tags: |
@@ -50,13 +58,13 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=sha
type=ref,event=tag
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
- name: Build and push ${{ matrix.target }} Docker image
id: push
uses: docker/build-push-action@v5
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
platforms: linux/amd64,linux/arm64
context: .
@@ -67,10 +75,11 @@ jobs:
RELEASE_VERSION=${{ github.ref_name }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
- name: Generate artifact attestation for ${{ matrix.target }} image
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v2
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.image_name_suffix }}
subject-digest: ${{ steps.push.outputs.digest }}
@@ -89,14 +98,14 @@ jobs:
LEGACY_NAME: calibre-web-automated-book-downloader
steps:
- name: Log in to registry
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
- name: Create legacy aliases
run: |
+158
View File
@@ -0,0 +1,158 @@
name: CI
on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
python-quality:
name: Python Quality
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install uv and Python
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
version: "0.11.3"
python-version: "3.14"
enable-cache: true
- name: Sync dependencies
run: make install-python-dev
- name: Lint
run: make python-lint
- name: Check formatting
run: make python-format
- name: Check dead code
run: make python-dead-code
python-typechecks:
name: Python Typechecks
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install uv and Python
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
version: "0.11.3"
python-version: "3.14"
enable-cache: true
- name: Sync dependencies
run: make install-python-dev
- name: Typecheck
run: make python-typecheck
python-tests:
name: Python Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Install uv and Python
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
version: "0.11.3"
python-version: "3.14"
enable-cache: true
- name: Sync dependencies
run: make install-python-dev
- name: Run tests
run: make python-test
docker-build-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
- name: Build shelfmark-lite image
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
target: shelfmark-lite
platforms: linux/amd64
push: false
build-args: |
BUILD_VERSION=pr-${{ github.sha }}
RELEASE_VERSION=pr-${{ github.event.pull_request.number }}
frontend-quality:
name: Frontend Quality
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: "npm"
cache-dependency-path: src/frontend/package-lock.json
- name: Install dependencies
run: make install-ci
- name: Lint
run: make frontend-lint
- name: Check formatting
run: make frontend-format
frontend-typechecks:
name: Frontend Typechecks
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: "npm"
cache-dependency-path: src/frontend/package-lock.json
- name: Install dependencies
run: make install-ci
- name: Typecheck
run: make frontend-typecheck
frontend-tests:
name: Frontend Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: "npm"
cache-dependency-path: src/frontend/package-lock.json
- name: Install dependencies
run: make install-ci
- name: Unit tests
run: make frontend-test
+38
View File
@@ -0,0 +1,38 @@
name: CodeQL
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "0 6 * * 1" # Weekly on Monday at 6am UTC
permissions:
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
language: [python, javascript-typescript]
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Initialize CodeQL
uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v3
with:
category: "/language:${{ matrix.language }}"
+51
View File
@@ -0,0 +1,51 @@
name: Debounce dev image
# A burst of merges to main should publish one dev image, not one per commit.
# Each push to main waits out the 60-minute wait timer on the
# dev-image-debounce environment (Settings → Environments; waiting holds no
# runner), then dispatches the Docker workflow only if main still points at
# its commit. So only the last push of a burst builds, and the Docker
# workflow's history holds real builds only.
on:
push:
branches:
- main
permissions: {}
jobs:
debounce:
runs-on: ubuntu-latest
environment:
name: dev-image-debounce
deployment: false
permissions:
actions: write # dispatch the build, delete finished debounce runs
contents: read
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
steps:
- name: Dispatch the dev build if main is still at this commit
env:
CURRENT_SHA: ${{ github.sha }}
run: |
HEAD_SHA=$(gh api "repos/${GH_REPO}/git/ref/heads/main" --jq '.object.sha')
echo "This run's commit: ${CURRENT_SHA}"
echo "main HEAD now: ${HEAD_SHA}"
if [[ "$HEAD_SHA" == "$CURRENT_SHA" ]]; then
echo "No newer commits on main — dispatching the dev build."
gh workflow run build-and-publish-docker-image.yml --ref main
else
echo "main has moved on — the newer push's run will build it."
fi
# A finished debounce run is noise: it either did nothing or its build
# run is the record. Best effort, since runs from the same burst race to
# delete the same runs.
- name: Delete finished debounce runs
run: |
# On an HTTP error gh prints the error body to stdout, so bail out
# rather than loop over it.
ids=$(gh api "repos/${GH_REPO}/actions/workflows/dev-image-debounce.yml/runs?status=success&per_page=100" --jq '.workflow_runs[].id') || exit 0
for id in $ids; do
gh api -X DELETE "repos/${GH_REPO}/actions/runs/${id}" || true
done
+135
View File
@@ -0,0 +1,135 @@
name: E2E Platform
# Hermetic end-to-end matrix: boots the app under test against mock
# Anna's Archive / Cloudflare / bypasser / DNS / proxy / Tor / real torrent
# clients and runs the cluster suite under each config profile.
#
# On a PR that touches relevant code, this runs a fast core subset *and* the heavy
# `full` profile (real Chrome solving Cloudflare + DoH + real qBittorrent). The
# `e2e-required` job aggregates them into ONE status check — make that check a
# required status check in branch protection to block merges on any e2e failure
# (see tests/e2e/platform/README.md "Gating PRs").
on:
pull_request:
schedule:
- cron: "0 4 * * *" # nightly full matrix
workflow_dispatch:
concurrency:
group: e2e-platform-${{ github.ref }}
cancel-in-progress: true
jobs:
# Detect whether anything that affects the e2e platform changed. This lets the
# required check always report (never stuck "pending") while only spending CI on
# PRs that can actually break the e2e stack.
changes:
runs-on: ubuntu-latest
outputs:
relevant: ${{ steps.filter.outputs.relevant }}
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v4.0.3
id: filter
with:
filters: |
relevant:
- 'shelfmark/**'
- 'entrypoint.sh'
- 'tor.sh'
- 'Dockerfile'
- 'tests/e2e/platform/**'
- '.github/workflows/e2e-platform.yml'
select-profiles:
needs: changes
if: needs.changes.outputs.relevant == 'true' || github.event_name != 'pull_request'
runs-on: ubuntu-latest
outputs:
profiles: ${{ steps.pick.outputs.profiles }}
steps:
- id: pick
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo 'profiles=["baseline","bypasser-external","dns-blocked"]' >> "$GITHUB_OUTPUT"
else
echo 'profiles=["baseline","bypasser-external","bypasser-disabled","dns-manual","dns-blocked","dns-doh","proxy-http","proxy-socks","tor","client-transmission","client-deluge","client-qbittorrent-delayed"]' >> "$GITHUB_OUTPUT"
fi
e2e:
needs: select-profiles
runs-on: ubuntu-latest
# A wedged app under test must not burn GitHub's 6h max job limit. A healthy
# profile run finishes in ~3-5 min; anything past 25 is hung, not slow.
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
profile: ${{ fromJSON(needs.select-profiles.outputs.profiles) }}
name: e2e (${{ matrix.profile }})
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Install uv and Python
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
python-version: "3.14"
enable-cache: true
- name: Sync dependencies
run: make install-python-dev
- name: Run e2e platform (${{ matrix.profile }})
run: tests/e2e/platform/run-e2e.sh env/${{ matrix.profile }}.env
- name: Dump shelfmark logs on failure
if: failure()
run: cat tests/e2e/platform/.state/shelfmark.${{ matrix.profile }}.log || true
# Heavy "everything real" job: real Chrome internal bypasser solving Cloudflare +
# DoH + real qBittorrent webseed download. Runs on relevant PRs and nightly.
e2e-full:
needs: changes
if: needs.changes.outputs.relevant == 'true' || github.event_name != 'pull_request'
runs-on: ubuntu-latest
# Real Chrome + qBittorrent is the slowest profile; still nowhere near 40 min.
timeout-minutes: 40
name: e2e (full — real Chrome + qBittorrent)
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Install uv and Python
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
with:
python-version: "3.14"
enable-cache: true
- name: Sync dependencies
run: make install-python-dev
- name: Run full pipeline
run: tests/e2e/platform/run-e2e.sh env/full.env
- name: Dump logs on failure
if: failure()
run: |
cat tests/e2e/platform/.state/shelfmark.full.log || true
docker logs e2e-qbittorrent || true
# Single aggregated gate. ALWAYS runs (so a required check never hangs "pending"
# on unrelated PRs) and FAILS if any e2e job failed/was cancelled. Make THIS the
# required status check in branch protection.
e2e-required:
name: e2e required
needs: [e2e, e2e-full]
if: always()
runs-on: ubuntu-latest
steps:
- name: Aggregate e2e results
run: |
matrix='${{ needs.e2e.result }}'
full='${{ needs.e2e-full.result }}'
echo "e2e matrix=$matrix, e2e-full=$full"
# success or skipped (unrelated PR) is OK; failure/cancelled blocks.
for r in "$matrix" "$full"; do
if [ "$r" = "failure" ] || [ "$r" = "cancelled" ]; then
echo "::error::An e2e platform job did not pass — blocking."
exit 1
fi
done
echo "All e2e platform jobs passed (or were skipped as not relevant)."
+8
View File
@@ -74,6 +74,7 @@ pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
src/frontend/coverage/
htmlcov/
.tox/
.nox/
@@ -165,6 +166,10 @@ ENV/
env.bak/
venv.bak/
# ...but the e2e platform test profiles live in an env/ dir and must be tracked
!tests/e2e/platform/env/
!tests/e2e/platform/env/*.env
# Spyder project settings
.spyderproject
.spyproject
@@ -231,5 +236,8 @@ pyrightconfig.json
*.local.*
AGENTS.md
.claude/
CLAUDE.md
.nvmrc
.playwright-mcp/
frontend-dist/
node_modules/
+23
View File
@@ -0,0 +1,23 @@
repos:
- repo: builtin
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.10
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: local
hooks:
- id: oxfmt
name: oxfmt
entry: npx --prefix src/frontend oxfmt --config src/frontend/.oxfmtrc.json
language: system
types_or: [javascript, jsx, ts, tsx, css, json]
files: ^src/frontend/
exclude: package-lock\.json
+1 -1
View File
@@ -61,4 +61,4 @@
]
}
]
}
}
+117 -34
View File
@@ -4,7 +4,7 @@ ARG BUILDPLATFORM
ARG BUILDARCH
# Frontend build stage.
FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend-builder
FROM --platform=$BUILDPLATFORM node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 AS frontend-builder
# Helpful debug output to see what platforms BuildKit thinks it's using
RUN echo "BUILDPLATFORM=$BUILDPLATFORM BUILDARCH=$BUILDARCH TARGETPLATFORM=$TARGETPLATFORM TARGETARCH=$TARGETARCH"
@@ -24,8 +24,14 @@ COPY src/frontend/ ./
# Build the frontend
RUN npm run build
# uv is a build-time tool only, so it is mounted into the RUNs that need it rather
# than copied into the image. A COPY here would land ~24 MB in a `base` layer that
# every published image inherits, and a later `rm` cannot take it back out again --
# a RUN adds a layer, it does not rewrite the one underneath.
FROM ghcr.io/astral-sh/uv:0.12.16@sha256:adc68cd785ca65ea25c0611043b0a00b4ea3a22e1b54102fc084406d888082ee AS uv
# Use python-slim as the base image
FROM python:3.10-slim AS base
FROM python:3.14.7-slim@sha256:cad9a2c871761c413caa6fdd6441c783451e740a48aaeba60ae62a8b53525ef6 AS base
# Add build argument for version
ARG BUILD_VERSION
@@ -39,13 +45,12 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Consistent environment variables grouped together
ENV DEBIAN_FRONTEND=noninteractive \
DOCKERMODE=true \
UV_LINK_MODE=copy \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONIOENCODING=UTF-8 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_DEFAULT_TIMEOUT=100 \
NAME=Shelfmark \
PATH=/app/.venv/bin:$PATH \
PYTHONPATH=/app \
# PUID/PGID will be handled by entrypoint script, but TZ/Locale are still needed
LANG=en_US.UTF-8 \
@@ -56,9 +61,13 @@ ENV DEBIAN_FRONTEND=noninteractive \
ENV FLASK_PORT=8084
# Configure locale, timezone, and perform initial cleanup in a single layer
# User/group creation is removed
RUN apt-get update && \
apt-get install -y --no-install-recommends \
# For building C-extensions (cffi, gevent, etc.)
gcc \
g++ \
libffi-dev \
python3-dev \
# For locale
locales tzdata \
# For healthcheck
@@ -68,11 +77,16 @@ RUN apt-get update && \
# For debug
zip iputils-ping \
# For user switching
sudo \
gosu \
# --- Tor support (activated via USING_TOR=true) ---
tor \
supervisor \
iptables && \
iptables \
# --- WireGuard support (activated via USING_WIREGUARD=true) ---
wireguard-tools \
iproute2 \
procps \
ca-certificates && \
# Configure iptables alternatives for tor.sh compatibility
update-alternatives --set iptables /usr/sbin/iptables-legacy && \
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy && \
@@ -88,15 +102,30 @@ RUN apt-get update && \
echo "LC_ALL=en_US.UTF-8" >> /etc/environment && \
echo "LANG=en_US.UTF-8" > /etc/locale.conf
# Create a fixed runtime user/group so hardened Docker/Kubernetes deployments
# can start the container directly as a non-root user with a passwd entry.
RUN groupadd -g 1000 shelfmark && \
useradd -u 1000 -g shelfmark -d /home/shelfmark -s /usr/sbin/nologin shelfmark && \
mkdir -p /home/shelfmark && \
chown 1000:1000 /home/shelfmark
# Set working directory
WORKDIR /app
# Install Python dependencies using pip
# Copying requirements files separately leverages build cache
# Cache mount persists pip cache between builds for faster installs
COPY requirements-base.txt requirements-shelfmark.txt ./
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements-base.txt
# Install core Python dependencies first for better layer caching
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv sync --locked --no-default-groups
# Runtime dependencies are installed into /app/.venv during the build. Remove the
# base image's system pip so stale installer CVEs do not ship in the final image.
RUN rm -rf \
/usr/local/bin/pip \
/usr/local/bin/pip3 \
/usr/local/bin/pip3.* \
/usr/local/lib/python*/site-packages/pip \
/usr/local/lib/python*/site-packages/pip-*.dist-info
# Copy application code *after* dependencies are installed
COPY . .
@@ -104,19 +133,33 @@ COPY . .
# Copy built frontend from frontend-builder stage
COPY --from=frontend-builder /frontend/dist /app/frontend-dist
# Final setup: permissions and directories in one layer
# Only creating directories and setting executable bits.
# Ownership will be handled by the entrypoint script.
RUN mkdir -p /var/log/shelfmark /books && \
chmod +x /app/entrypoint.sh /app/tor.sh /app/genDebug.sh
# Final setup: create image-owned runtime paths for the fixed non-root user.
# Root/PUID mode still re-homes ownership at startup when needed.
RUN mkdir -p \
/config \
/books \
/var/log/shelfmark \
/tmp/shelfmark/seleniumbase/downloaded_files \
/tmp/shelfmark/seleniumbase/archived_files && \
rm -rf /app/downloaded_files /app/archived_files && \
ln -s /tmp/shelfmark/seleniumbase/downloaded_files /app/downloaded_files && \
ln -s /tmp/shelfmark/seleniumbase/archived_files /app/archived_files && \
chown -R 1000:1000 /config /books /home/shelfmark /tmp/shelfmark /var/log/shelfmark && \
chmod -R a+rX /app && \
chmod +x /app/entrypoint.sh /app/tor.sh /app/wireguard.sh /app/genDebug.sh
# Expose the application port
EXPOSE ${FLASK_PORT}
# Add healthcheck for container status
# Uses /api/health which doesn't require authentication
HEALTHCHECK --interval=60s --timeout=60s --start-period=60s --retries=3 \
CMD curl -s http://localhost:${FLASK_PORT}/api/health > /dev/null || exit 1
# Uses /api/health which doesn't require authentication.
# curl needs -f so an HTTP error status fails the probe instead of passing it:
# plain `curl -s` exits 0 on a 500, which reported a broken app as healthy.
# timeout stays well under interval so a hung probe cannot occupy a whole cycle.
# --start-interval matches the daemon default (5s), made explicit so startup
# probing does not depend on that default staying put.
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --start-interval=5s --retries=3 \
CMD curl -fsS http://localhost:${FLASK_PORT}/api/health > /dev/null || exit 1
# Use dumb-init as the entrypoint to handle signals properly
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
@@ -124,21 +167,39 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
FROM base AS shelfmark
RUN apt-get update && \
apt-get install -y --no-install-recommends \
# --- Chromium (PINNED to 149.0.7827.196) ---
# Debian's chromium 150.0.7871.46-1~deb13u1 security update (trixie-security,
# 2026-07-05) no longer opens the DevTools remote-debugging TCP port at all
# (no listener, no DevToolsActivePort file, even with a custom --user-data-dir;
# the RemoteDebuggingAllowed policy does not restore it). The SeleniumBase
# Pure-CDP driver connects through that port (/json/version), so with 150 every
# internal bypass dies with "Pure CDP browser startup failed" and all
# CF-gated downloads fail. Install the last working version from
# snapshot.debian.org until the bypasser can talk to Chromium >= 150 (e.g.
# pipe-based DevTools / UC mode) or seleniumbase ships a fix.
# Chrome 144+ requires --enable-unsafe-swiftshader for WebGL in Docker.
# This flag is set in internal_bypasser.py _get_browser_args()
ARG CHROMIUM_VERSION=149.0.7827.196-1~deb13u1
ARG CHROMIUM_SNAPSHOT=20260704T000000Z
RUN echo "deb [check-valid-until=no] https://snapshot.debian.org/archive/debian-security/${CHROMIUM_SNAPSHOT}/ trixie-security main" \
> /etc/apt/sources.list.d/chromium-pin-snapshot.list && \
apt-get update -o Acquire::Retries=5 && \
apt-get install -y --no-install-recommends -o Acquire::Retries=5 \
# For dumb display
xvfb \
# For screen recording
ffmpeg \
# --- Chromium (unpinned - uses latest from Debian repos) ---
# Chrome 144+ requires --enable-unsafe-swiftshader for WebGL in Docker.
# This flag is set in internal_bypasser.py _get_browser_args()
chromium \
chromium-common \
chromium=${CHROMIUM_VERSION} \
chromium-common=${CHROMIUM_VERSION} \
# For tkinter (pyautogui)
python3-tk \
# For RAR extraction
unrar-free && \
# Keep apt from "upgrading" chromium past the pin inside derived images
printf 'Package: chromium chromium-common\nPin: version %s\nPin-Priority: 1001\n' "${CHROMIUM_VERSION}" \
> /etc/apt/preferences.d/chromium-pin && \
rm /etc/apt/sources.list.d/chromium-pin-snapshot.list && \
# Create symlink so rarfile library can find unrar
ln -sf /usr/bin/unrar-free /usr/bin/unrar && \
# Cleanup APT cache
@@ -146,13 +207,35 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install additional dependencies (requirements file already copied in base stage)
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements-shelfmark.txt
# Install the browser automation stack used by the full image
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv sync --locked --no-default-groups --extra browser
# Deterministically resolve the Xlib namespace collision.
# pyautogui/mouseinfo pull the stale `python3-xlib` (0.15, 2014), while the
# `--extra browser` set pulls `python-xlib` (0.33). Both packages install into
# the same top-level `Xlib/` namespace, so whichever lands last wins. When the
# 2014 build wins, `Xlib.X` is missing `FamilyServerInterpreted`, which the
# SeleniumBase Pure-CDP driver requires at browser startup -> every bypass fails
# with "module 'Xlib.X' has no attribute 'FamilyServerInterpreted'" and no
# Cloudflare/DDoS-Guard protected download can complete. Drop the stale package
# and force python-xlib 0.33 to own the namespace. pyautogui runs fine against
# 0.33 (superset API).
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv pip uninstall --python /app/.venv/bin/python python3-xlib && \
uv pip install --python /app/.venv/bin/python --reinstall python-xlib==0.33 && \
/app/.venv/bin/python -c "import Xlib.X; assert hasattr(Xlib.X, 'FamilyServerInterpreted'), 'Xlib.X.FamilyServerInterpreted missing after fix'; print('Xlib namespace OK:', Xlib.__version__)"
# Keep SeleniumBase's bundled driver cache writable for the fixed non-root user.
RUN SELENIUMBASE_DRIVERS_DIR=$(/app/.venv/bin/python -c "import pathlib, seleniumbase; print(pathlib.Path(seleniumbase.__file__).resolve().parent / 'drivers')") && \
chown -R 1000:1000 "${SELENIUMBASE_DRIVERS_DIR}" && \
chmod -R u+rwX,go+rX "${SELENIUMBASE_DRIVERS_DIR}" && \
if [ -f "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" ]; then chmod +x "${SELENIUMBASE_DRIVERS_DIR}/uc_driver"; fi
# Grant read/execute permissions to others
RUN chmod -R o+rx /usr/bin/chromium && \
chmod -R o+rwx /usr/local/lib/python3.10/site-packages/seleniumbase/drivers/
RUN chmod -R o+rx /usr/bin/chromium
# Default command to run the application entrypoint script
CMD ["/app/entrypoint.sh"]
+136 -3
View File
@@ -1,4 +1,4 @@
.PHONY: help install dev build preview typecheck clean up down docker-build refresh restart
.PHONY: help install install-ci install-python-dev dev build preview frontend-typecheck frontend-lint frontend-format frontend-format-fix frontend-checks frontend-test clean up down docker-build refresh restart build-serve python-lint python-lint-fix python-format python-format-fix python-typecheck python-dead-code python-checks python-test python-test-cov e2e-platform e2e-platform-profile e2e-platform-matrix e2e-platform-full e2e-platform-build checks fix
# Frontend directory
FRONTEND_DIR := src/frontend
@@ -10,12 +10,38 @@ COMPOSE_FILE := docker-compose.dev.yml
help:
@echo "Available targets:"
@echo ""
@echo "Quality:"
@echo " checks - Run ALL static analysis checks (frontend + Python)"
@echo " fix - Auto-fix lint + format issues (frontend + Python)"
@echo ""
@echo "Frontend:"
@echo " install - Install frontend dependencies"
@echo " dev - Start development server"
@echo " build - Build frontend for production"
@echo " build-serve - Build and serve via Flask (test prod build without Docker)"
@echo " preview - Preview production build"
@echo " typecheck - Run TypeScript type checking"
@echo " frontend-typecheck - Run TypeScript type checking"
@echo " frontend-lint - Run Oxlint against frontend code"
@echo " frontend-format - Check frontend formatting with Oxfmt"
@echo " frontend-format-fix - Format frontend code with Oxfmt"
@echo " frontend-checks - Run all frontend static analysis checks"
@echo " frontend-test - Run frontend unit tests"
@echo ""
@echo "Python:"
@echo " install-python-dev - Sync Python runtime + dev tooling with uv"
@echo " python-lint - Run Ruff against Python code (backend + tests)"
@echo " python-lint-fix - Run Ruff with safe auto-fixes"
@echo " python-format - Check Python formatting with Ruff"
@echo " python-format-fix - Format Python code with Ruff"
@echo " python-typecheck - Run BasedPyright against backend + tests"
@echo " python-dead-code - Run Vulture against backend code"
@echo " python-checks - Run all Python static analysis checks"
@echo " python-test - Run unit tests"
@echo " python-test-cov - Run unit tests with coverage report"
@echo " e2e-platform - Run e2e docker platform (baseline profile)"
@echo " e2e-platform-profile PROFILE=<name> - Run e2e platform for one profile"
@echo " e2e-platform-matrix - Run e2e platform across all config profiles"
@echo " e2e-platform-full - Run heavy 'full' profile (real Chrome bypasser + DoH + real qBittorrent)"
@echo " clean - Remove node_modules and build artifacts"
@echo ""
@echo "Backend (Docker):"
@@ -30,6 +56,17 @@ install:
@echo "Installing frontend dependencies..."
cd $(FRONTEND_DIR) && npm install
install-ci:
@echo "Installing frontend dependencies (CI, lockfile-strict)..."
cd $(FRONTEND_DIR) && npm ci
# Install Python development dependencies
install-python-dev:
@echo "Syncing Python runtime and dev tooling with uv..."
uv sync --locked --extra browser
@echo "Installing prek git hooks..."
uv run prek install
# Start development server
dev:
@echo "Starting development server..."
@@ -40,16 +77,112 @@ build:
@echo "Building frontend for production..."
cd $(FRONTEND_DIR) && npm run build
# Build frontend and sync to frontend-dist for the running container to serve
build-serve: build
@echo "Syncing build to frontend-dist..."
@mkdir -p frontend-dist
rsync -a --delete $(FRONTEND_DIR)/dist/ frontend-dist/
@echo "Done. Hit the Flask backend (port 8084) to test the production build."
# Preview production build
preview:
@echo "Previewing production build..."
cd $(FRONTEND_DIR) && npm run preview
# Type checking
typecheck:
frontend-typecheck:
@echo "Running TypeScript type checking..."
cd $(FRONTEND_DIR) && npm run typecheck
# Python linting (backend + tests)
python-lint:
@echo "Running Ruff..."
uv run ruff check shelfmark tests
python-lint-fix:
@echo "Running Ruff with safe auto-fixes..."
uv run ruff check shelfmark tests --fix
python-format:
@echo "Checking Python formatting with Ruff..."
uv run ruff format --check shelfmark tests
python-format-fix:
@echo "Formatting Python code with Ruff..."
uv run ruff format shelfmark tests
python-typecheck:
@echo "Running BasedPyright..."
uv run basedpyright
@echo "Running BasedPyright against tests..."
uv run basedpyright tests --skipunannotated
python-dead-code:
@echo "Running Vulture..."
uv run vulture shelfmark
python-checks: python-lint python-format python-typecheck python-dead-code
python-test:
@echo "Running tests..."
uv run pytest tests/ -x --tb=short -m "not integration and not e2e"
python-test-cov:
@echo "Running tests with coverage..."
uv run pytest tests/ -x --tb=short -m "not integration and not e2e" --cov --cov-report=term-missing
# E2E docker platform: hermetic stack (mock AA/Cloudflare/bypasser/DNS/proxy/Tor)
# exercised across config profiles. See tests/e2e/platform/README.md.
E2E_PLATFORM_DIR := tests/e2e/platform
e2e-platform:
@echo "Running e2e platform (baseline profile)..."
cd $(E2E_PLATFORM_DIR) && ./run-e2e.sh env/baseline.env
e2e-platform-profile:
@echo "Running e2e platform (profile=$(PROFILE))..."
cd $(E2E_PLATFORM_DIR) && ./run-e2e.sh env/$(PROFILE).env
e2e-platform-matrix:
@echo "Running e2e platform matrix (all profiles)..."
cd $(E2E_PLATFORM_DIR) && ./run-matrix.sh
e2e-platform-build:
@echo "Pre-building e2e platform images once (reused across profiles)..."
cd $(E2E_PLATFORM_DIR) && ./build-images.sh
e2e-platform-full:
@echo "Running e2e platform FULL profile (real Chrome bypasser + DoH + real qBittorrent)..."
cd $(E2E_PLATFORM_DIR) && ./run-e2e.sh env/full.env
# Frontend linting
frontend-lint:
@echo "Running Oxlint..."
cd $(FRONTEND_DIR) && npm run lint
# Frontend formatting
frontend-format:
@echo "Checking frontend formatting with Oxfmt..."
cd $(FRONTEND_DIR) && npm run format:check
frontend-format-fix:
@echo "Formatting frontend code with Oxfmt..."
cd $(FRONTEND_DIR) && npm run format
# All frontend static analysis
frontend-checks: frontend-lint frontend-format frontend-typecheck
# Run frontend unit tests
frontend-test:
@echo "Running frontend unit tests..."
cd $(FRONTEND_DIR) && npm run test:unit
# All static analysis checks (frontend + Python)
checks: frontend-checks python-checks
# Auto-fix lint + format issues (frontend + Python)
fix: python-lint-fix python-format-fix frontend-format-fix
# Clean build artifacts and dependencies
clean:
@echo "Cleaning build artifacts and dependencies..."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 KiB

After

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

+2 -1
View File
@@ -1,6 +1,7 @@
services:
shelfmark-lite:
image: ghcr.io/calibrain/shelfmark-lite:latest
container_name: shelfmark-lite
environment:
# EXT_BYPASSER_URL: http://flaresolverr:8191 #If using Flaresolverr
PUID: 1000
@@ -12,4 +13,4 @@ services:
- /path/to/books:/books # Default destination for book downloads
- /path/to/config:/config # App configuration
# Required for torrent / usenet - path must match your download client's volume exactly
# - /path/to/downloads:/path/to/downloads
# - /path/to/downloads:/path/to/downloads
+1 -1
View File
@@ -1,4 +1,4 @@
# Routes all traffic through Tor - requires NET_ADMIN capability
# Routes all traffic through Tor - requires root startup
services:
shelfmark-tor:
image: ghcr.io/calibrain/shelfmark:latest
+43
View File
@@ -0,0 +1,43 @@
# Routes all traffic through a WireGuard tunnel - requires root startup.
#
# Mount your wg-quick config at /config/wg0.conf (read-only is fine). All
# non-LAN egress is forced through the tunnel by an iptables kill-switch, so if
# the tunnel drops, external traffic fails closed. LAN ranges (WebUI + internal
# download clients like Prowlarr / qBittorrent) stay reachable off-tunnel.
services:
shelfmark-wireguard:
image: ghcr.io/calibrain/shelfmark:latest
environment:
FLASK_PORT: 8084
# Quoted so it is passed as the literal string "true": entrypoint.sh compares
# $USING_WIREGUARD against "true", and some Compose implementations stringify
# a bare YAML boolean as "True", which would silently NOT enable WireGuard.
USING_WIREGUARD: "true"
# Path to the mounted wg-quick config (default shown).
WIREGUARD_CONFIG: /config/wg0.conf
# CIDRs kept OFF the tunnel so the WebUI and internal clients stay reachable.
LAN_NETWORK: 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
PUID: 1000
PGID: 1000
cap_add:
- NET_ADMIN
- NET_RAW
# WireGuard needs the module/kernel routing; NET_ADMIN covers wg-quick.
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
# Disable IPv6 in the container so the kill-switch can guarantee no IPv6
# leak path on kernels/containers without a usable ip6tables. wireguard.sh
# fails closed if IPv6 is neither kill-switched nor disabled. If your host
# DOES have a working ip6tables you may omit these (an ip6tables kill-switch
# is installed instead); or set WIREGUARD_ALLOW_IPV6_LEAK=true only if the
# container genuinely has no IPv6 connectivity.
- net.ipv6.conf.all.disable_ipv6=1
- net.ipv6.conf.default.disable_ipv6=1
ports:
- 8084:8084
restart: unless-stopped
volumes:
- /path/to/books:/books # Default destination for book downloads
- /path/to/config:/config # App configuration (put wg0.conf here)
# Required for torrent / usenet - path must match your download client's volume exactly
# - /path/to/downloads:/path/to/downloads
+61 -54
View File
@@ -1,72 +1,79 @@
[
{ "language": "English", "code": "en" },
{ "language": "Chinese", "code": "zh" },
{ "language": "Russian", "code": "ru" },
{ "language": "Spanish", "code": "es" },
{ "language": "French", "code": "fr" },
{ "language": "German", "code": "de" },
{ "language": "Italian", "code": "it" },
{ "language": "Portuguese", "code": "pt" },
{ "language": "Polish", "code": "pl" },
{ "language": "Bulgarian", "code": "bg" },
{ "language": "Dutch", "code": "nl" },
{ "language": "Japanese", "code": "ja" },
{ "language": "Arabic", "code": "ar" },
{ "language": "Hebrew", "code": "he" },
{ "language": "Turkish", "code": "tr" },
{ "language": "Hungarian", "code": "hu" },
{ "language": "Latin", "code": "la" },
{ "language": "Czech", "code": "cs" },
{ "language": "Korean", "code": "ko" },
{ "language": "Ukrainian", "code": "uk" },
{ "language": "Indonesian", "code": "id" },
{ "language": "Romanian", "code": "ro" },
{ "language": "Swedish", "code": "sv" },
{ "language": "Greek", "code": "el" },
{ "language": "Lithuanian", "code": "lt" },
{ "language": "Bangla", "code": "bn" },
{ "language": "Traditional Chinese", "code": "zhHant" },
{ "language": "Afrikaans", "code": "af" },
{ "language": "Catalan", "code": "ca" },
{ "language": "Danish", "code": "da" },
{ "language": "Thai", "code": "th" },
{ "language": "Hindi", "code": "hi" },
{ "language": "Irish", "code": "ga" },
{ "language": "Latvian", "code": "lv" },
{ "language": "English", "code": "en", "aliases": ["eng"] },
{ "language": "Chinese", "code": "zh", "aliases": ["chi", "zho"] },
{ "language": "Russian", "code": "ru", "aliases": ["rus"] },
{ "language": "Spanish", "code": "es", "aliases": ["spa"] },
{ "language": "French", "code": "fr", "aliases": ["fra", "fre"] },
{ "language": "German", "code": "de", "aliases": ["deu", "ger"] },
{ "language": "Italian", "code": "it", "aliases": ["ita"] },
{ "language": "Portuguese", "code": "pt", "aliases": ["por"] },
{ "language": "Polish", "code": "pl", "aliases": ["pol"] },
{ "language": "Bulgarian", "code": "bg", "aliases": ["bul"] },
{ "language": "Dutch", "code": "nl", "aliases": ["dut", "nld"] },
{ "language": "Japanese", "code": "ja", "aliases": ["jap", "jpn"] },
{ "language": "Arabic", "code": "ar", "aliases": ["ara"] },
{ "language": "Hebrew", "code": "he", "aliases": ["heb"] },
{ "language": "Turkish", "code": "tr", "aliases": ["tur"] },
{ "language": "Hungarian", "code": "hu", "aliases": ["hun"] },
{ "language": "Latin", "code": "la", "aliases": ["lat"] },
{ "language": "Czech", "code": "cs", "aliases": ["ces", "cze"] },
{ "language": "Korean", "code": "ko", "aliases": ["kor"] },
{ "language": "Ukrainian", "code": "uk", "aliases": ["ukr"] },
{ "language": "Indonesian", "code": "id", "aliases": ["ind"] },
{ "language": "Romanian", "code": "ro", "aliases": ["rom", "ron"] },
{ "language": "Swedish", "code": "sv", "aliases": ["swe"] },
{ "language": "Greek", "code": "el", "aliases": ["ell", "gre"] },
{ "language": "Lithuanian", "code": "lt", "aliases": ["lit"] },
{ "language": "Bangla", "code": "bn", "aliases": ["ben", "bengali"] },
{ "language": "Traditional Chinese", "code": "zh-Hant", "aliases": ["zhHant"] },
{ "language": "Afrikaans", "code": "af", "aliases": ["afr"] },
{ "language": "Catalan", "code": "ca", "aliases": ["cat"] },
{ "language": "Danish", "code": "da", "aliases": ["dan"] },
{ "language": "Thai", "code": "th", "aliases": ["tha"] },
{ "language": "Hindi", "code": "hi", "aliases": ["hin"] },
{ "language": "Irish", "code": "ga", "aliases": ["gle"] },
{ "language": "Latvian", "code": "lv", "aliases": ["lav"] },
{ "language": "Tibetan", "code": "bo" },
{ "language": "Kannada", "code": "kn" },
{ "language": "Serbian", "code": "sr" },
{ "language": "Persian", "code": "fa" },
{ "language": "Croatian", "code": "hr" },
{ "language": "Kannada", "code": "kn", "aliases": ["kan"] },
{ "language": "Serbian", "code": "sr", "aliases": ["srp"] },
{ "language": "Persian", "code": "fa", "aliases": ["farsi", "fas", "per"] },
{ "language": "Croatian", "code": "hr", "aliases": ["hrv"] },
{ "language": "Slovak", "code": "sk" },
{ "language": "Javanese", "code": "jv" },
{ "language": "Vietnamese", "code": "vi" },
{ "language": "Urdu", "code": "ur" },
{ "language": "Finnish", "code": "fi" },
{ "language": "Norwegian", "code": "no" },
{ "language": "Javanese", "code": "jv", "aliases": ["jav"] },
{ "language": "Vietnamese", "code": "vi", "aliases": ["vie"] },
{ "language": "Urdu", "code": "ur", "aliases": ["urd"] },
{ "language": "Finnish", "code": "fi", "aliases": ["fin"] },
{ "language": "Norwegian", "code": "no", "aliases": ["nor"] },
{ "language": "Kinyarwanda", "code": "rw" },
{ "language": "Tamil", "code": "ta" },
{ "language": "Tamil", "code": "ta", "aliases": ["tam"] },
{ "language": "Belarusian", "code": "be" },
{ "language": "Kazakh", "code": "kk" },
{ "language": "Mongolian", "code": "mn" },
{ "language": "Georgian", "code": "ka" },
{ "language": "Slovenian", "code": "sl" },
{ "language": "Slovenian", "code": "sl", "aliases": ["slv"] },
{ "language": "Esperanto", "code": "eo" },
{ "language": "Galician", "code": "gl" },
{ "language": "Marathi", "code": "mr" },
{ "language": "Filipino", "code": "fil" },
{ "language": "Gujarati", "code": "gu" },
{ "language": "Malayalam", "code": "ml" },
{ "language": "Marathi", "code": "mr", "aliases": ["mar"] },
{ "language": "Filipino", "code": "fil", "aliases": ["tagalog", "tgl"] },
{ "language": "Gujarati", "code": "gu", "aliases": ["guj"] },
{ "language": "Malayalam", "code": "ml", "aliases": ["mal"] },
{ "language": "Kyrgyz", "code": "ky" },
{ "language": "Azerbaijani", "code": "az" },
{ "language": "Quechua", "code": "qu" },
{ "language": "Swahili", "code": "sw" },
{ "language": "Bashkir", "code": "ba" },
{ "language": "Punjabi", "code": "pa" },
{ "language": "Malay", "code": "ms" },
{ "language": "Telugu", "code": "te" },
{ "language": "Punjabi", "code": "pa", "aliases": ["pan"] },
{ "language": "Malay", "code": "ms", "aliases": ["may", "msa"] },
{ "language": "Telugu", "code": "te", "aliases": ["tel"] },
{ "language": "Albanian", "code": "sq" },
{ "language": "Uyghur", "code": "ug" },
{ "language": "Armenian", "code": "hy" },
{ "language": "Shan", "code": "shn" }
]
{ "language": "Shan", "code": "shn" },
{ "language": "Bosnian", "code": "bs", "aliases": ["bos"] },
{ "language": "Burmese", "code": "my", "aliases": ["bur", "mya"] },
{ "language": "Estonian", "code": "et", "aliases": ["est"] },
{ "language": "Icelandic", "code": "is", "aliases": ["ice", "isl"] },
{ "language": "Manx", "code": "gv", "aliases": ["glv"] },
{ "language": "Scottish Gaelic", "code": "gd", "aliases": ["gla"] },
{ "language": "Sanskrit", "code": "sa", "aliases": ["san"] }
]
-39
View File
@@ -1,39 +0,0 @@
# Bypass testing - switch between dev build and v1.0.1
# Usage:
# Test dev build: docker compose -f docker-compose.bypass-test.yml up shelfmark-dev
# Test v1.0.1: docker compose -f docker-compose.bypass-test.yml up shelfmark-stable
# Pull latest dev: docker compose -f docker-compose.bypass-test.yml build shelfmark-dev
# Pull v1.0.1: docker compose -f docker-compose.bypass-test.yml pull shelfmark-stable
services:
# Dev image from registry
shelfmark-dev:
image: ghcr.io/calibrain/shelfmark:dev
container_name: shelfmark-bypass-dev
environment:
PUID: 1000
PGID: 1000
DEBUG: true
ports:
- 8084:8084
volumes:
- ./.local/bypass-test/config-dev:/config
- ./.local/bypass-test/books:/books
- ./.local/bypass-test/log-dev:/var/log/shelfmark
- ./.local/bypass-test/tmp:/tmp/shelfmark
# Stable v1.0.1 for comparison
shelfmark-stable:
image: ghcr.io/calibrain/shelfmark:1.0.1
container_name: shelfmark-bypass-stable
environment:
PUID: 1000
PGID: 1000
DEBUG: true
ports:
- 8085:8084
volumes:
- ./.local/bypass-test/config-stable:/config
- ./.local/bypass-test/books:/books
- ./.local/bypass-test/log-stable:/var/log/shelfmark
- ./.local/bypass-test/tmp:/tmp/shelfmark
+25
View File
@@ -0,0 +1,25 @@
# Local development - WireGuard variant
services:
shelfmark-wireguard-dev:
extends:
file: ./compose/docker-compose.wireguard.yml
service: shelfmark-wireguard
build:
context: .
dockerfile: Dockerfile
target: shelfmark
environment:
# Quoted so they are passed as the literal string "true" (entrypoint.sh and
# the app compare against "true"); a bare YAML boolean can be stringified as
# "True" by some Compose variants, silently disabling the feature.
DEBUG: "true"
USING_WIREGUARD: "true"
WIREGUARD_CONFIG: /config/wg0.conf
volumes:
- ./.local/config:/config
- ./.local/books:/books
- ./.local/log:/var/log/shelfmark
- ./.local/tmp:/tmp/shelfmark
# Place your wg-quick config at ./.local/config/wg0.conf
# Required for torrent / usenet - path must match your download client's volume exactly
# - /path/to/downloads:/path/to/downloads
+3
View File
@@ -12,11 +12,14 @@ services:
- SYS_PTRACE
environment:
DEBUG: true
# HIDE_LOCAL_AUTH: true
OIDC_AUTO_REDIRECT: true
volumes:
- ./.local/config:/config
- ./.local/books:/books
- ./.local/log:/var/log/shelfmark
- ./.local/tmp:/tmp/shelfmark
- ./shelfmark:/app/shelfmark:ro
- ./frontend-dist:/app/frontend-dist:ro
# Required for torrent / usenet - path must match your download client's volume exactly
# - /path/to/downloads:/path/to/downloads
+19
View File
@@ -13,6 +13,7 @@
# - Transmission: http://localhost:9091 (admin / admin)
# - Deluge: http://localhost:8112 (password: deluge)
# - NZBGet: http://localhost:6789 (nzbget / tegbzn6789)
# - NZBHydra: http://localhost:5076 (no auth by default)
# - SABnzbd: http://localhost:8085 (complete setup wizard for API key)
# - rTorrent: http://localhost:8000 (admin / admin - if auth enabled)
#
@@ -35,6 +36,7 @@ services:
# - Transmission: http://transmission:9091
# - Deluge Web UI: http://deluge:8112
# - NZBGet: http://nzbget:6789
# - NZBHydra: http://nzbhydra:5076
# - SABnzbd: http://sabnzbd:8080
# - rTorrent: http://rtorrent:80 (XMLRPC via HTTP) or rtorrent (port 5000 for SCGI)
ports:
@@ -54,11 +56,13 @@ services:
# Mount tests for running pytest in container
- ./tests:/app/tests:ro
- ./pyproject.toml:/app/pyproject.toml:ro
- ./uv.lock:/app/uv.lock:ro
# Mount client configs for integration tests to read credentials
- ./.local/test-clients/qbittorrent/config:/qbittorrent-config:ro
- ./.local/test-clients/sabnzbd/config:/sabnzbd-config:ro
depends_on:
- nzbget
- nzbhydra
- sabnzbd
- qbittorrent
- transmission
@@ -179,3 +183,18 @@ services:
- "50000:50000" # Incoming connections
- "6881:6881/udp"
restart: unless-stopped
nzbhydra:
image: lscr.io/linuxserver/nzbhydra2:latest
container_name: nzbhydra
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
volumes:
- ./.local/test-clients/nzbhydra/config:/config
- ./.local/test-clients/downloads:/downloads
ports:
- 5076:5076
restart: unless-stopped
+72
View File
@@ -0,0 +1,72 @@
# API access with an API key
Shelfmark's web interface is driven entirely by a JSON API under `/api/`. Set
the `SHELFMARK_API_KEY` environment variable and scripts, dashboards and assistants can
call the same API without a browser session. Browser logins keep working
exactly as before: it is cookie **or** key.
## Set the key
```yaml
environment:
SHELFMARK_API_KEY: "a-long-random-secret"
```
Generate something long and random (for example `openssl rand -base64 32`).
A request carrying the key acts as an **admin**: the first admin user in
Shelfmark's user database. Create an admin before relying on the key in any
install that has none yet (for example an OIDC-only install). Without an
admin user, the key still authenticates as an admin identity with no user
row, and routes that need one (requests, activity) answer 403. To rotate,
change the variable and restart. Unset it and the feature is off. When the
instance runs with no authentication configured (`AUTH_METHOD=none`), the
key is simply unnecessary.
## Send the key
Either header works, and both are checked, so the key can be sent in
`X-Api-Key` behind a reverse proxy that sets its own `Authorization` header.
```bash
curl -s -H "Authorization: Bearer $SHELFMARK_API_KEY" https://shelfmark.example.com/api/downloads/active
curl -s -H "X-Api-Key: $SHELFMARK_API_KEY" https://shelfmark.example.com/api/downloads/active
```
A request that carries the key is authenticated by the key alone. Session
cookies are ignored and none are set. A bearer value that is not the configured
key is ignored and the request continues with normal session authentication,
so reverse proxies that forward their own tokens are unaffected; without a valid
session such a request gets the usual `401 {"error": "Unauthorized"}`. A
database error while resolving the admin returns
`500 {"error": "Authentication error"}` — never anonymous access.
`/api/auth/check` reflects the browser session only and ignores the key, so
use `/api/status` to verify a key.
## Examples
Search, then look up releases, then queue one (the same calls the web UI makes):
```bash
curl -s -H "Authorization: Bearer $SHELFMARK_API_KEY" \
"https://shelfmark.example.com/api/metadata/search?query=dune%20frank%20herbert"
# -> {"books":[{"provider":"hardcover","provider_id":"427363", ...}]}
curl -s -H "Authorization: Bearer $SHELFMARK_API_KEY" \
"https://shelfmark.example.com/api/releases?provider=hardcover&book_id=427363&content_type=ebook"
# -> {"releases":[{"source":"direct_download","source_id":"...", ...}], ...}
curl -s -X POST -H "Authorization: Bearer $SHELFMARK_API_KEY" -H "Content-Type: application/json" \
-d @release.json https://shelfmark.example.com/api/releases/download
# release.json = one object from "releases" (source and source_id are required)
curl -s -H "Authorization: Bearer $SHELFMARK_API_KEY" https://shelfmark.example.com/api/status
```
## Security notes
- The key is compared in constant time and is never logged.
- Keyed requests never set cookies and ignore any cookie sent with them.
- WebSocket (live activity) connections do not accept the key; poll `/api/status` instead.
- The key is a root-equivalent credential: an admin can configure a custom
post-download script that the server executes, so treat it like a root
password and send it only over HTTPS.
+13 -3
View File
@@ -18,9 +18,9 @@ Prowlarr -> Download client saves to <client path>
Key point: For torrent and usenet downloads, Shelfmark must see the same file path that your download client reports. The container path must match in both containers.
## Direct Download Setup
## Direct Download Volume Setup
Direct downloads do not use an external download client. A simple two-folder setup is enough.
If you plan to use Direct Download, it does not use an external download client. A simple two-folder setup is enough.
Required volumes:
@@ -43,7 +43,12 @@ services:
Notes:
- Point `/books` to your library ingest folder (Calibre-Web, Booklore, Audiobookshelf, etc) for automatic import.
- If you set Books Output Mode to Booklore (API), books are uploaded via API instead of written to `/books`. Audiobooks still use a destination folder.
- Ensure `PUID`/`PGID` (or legacy `UID`/`GID`) match the owner of the host directories to avoid permission errors.
- Ensure `PUID`/`PGID` (or legacy `UID`/`GID`) match the owner of the host directories.
- For non-root mode, start the container as `1000:1000`.
- On Kubernetes, set `runAsUser: 1000`, `runAsGroup: 1000`, and `runAsNonRoot: true` together.
- `PUID`/`PGID` keep the default root startup flow.
- In non-root mode, mounted paths must already be writable by `1000:1000`.
- `USING_TOR=true` requires root startup.
## Torrent / Usenet Setup
@@ -86,6 +91,10 @@ Example:
- Shelfmark can see the same files at `/downloads/books/...`
- Add a mapping from Remote Path `/data/torrents` to Local Path `/downloads`
If the files are copied or synced into Shelfmark on a delay, increase **Completed Path Wait (seconds)**
in Settings -> Advanced. The default is 60 seconds; seedbox or remote-sync setups may need a value
longer than the sync interval.
## File Processing Options
### Transfer Method (Torrent / Usenet Only)
@@ -113,6 +122,7 @@ Configure templates in Settings -> Downloads. Template syntax details are docume
- "Download failed - file not found": Path mismatch between Shelfmark and the download client. Ensure container paths match or use Remote Path Mappings.
- "Permission denied": `PUID`/`PGID` do not match the host directories. Ensure Shelfmark can read the client path and write to the destination.
- "Permission denied" in non-root Docker/Kubernetes mode: ensure the mounted path is writable by UID/GID `1000:1000`, or switch back to root startup with `PUID`/`PGID`.
- "Hardlinks not working" or "Files being copied instead": Source and destination are on different filesystems. Move the destination or accept copy fallback.
- "Downloads work but library does not see them": Destination does not point to the library ingest folder. Check Settings -> Downloads -> Destination.
- CIFS/SMB shares: Use the `nobrl` mount option to avoid database lock errors. Example: `//server/share /mnt/share cifs nobrl,... 0 0`
+17 -6
View File
@@ -121,15 +121,26 @@ Example payload shape:
}
```
Example (bash + jq) (JSON payload must be enabled):
Example (bash + python3) (JSON payload must be enabled):
```bash
payload="$(cat)"
mode="$(echo "$payload" | jq -r '.output.mode')"
title="$(echo "$payload" | jq -r '.task.title')"
final_paths="$(echo "$payload" | jq -r '.paths.final_paths[]')"
echo "mode=$mode title=$title" >&2
echo "$final_paths" >&2
target="$1"
PAYLOAD="$payload" TARGET="$target" python3 - <<'PY'
import json
import os
import sys
payload = json.loads(os.environ["PAYLOAD"])
print(f"target={os.environ['TARGET']}", file=sys.stderr)
print(
f"mode={payload['output']['mode']} title={payload['task']['title']}",
file=sys.stderr,
)
for path in payload["paths"]["final_paths"]:
print(path, file=sys.stderr)
PY
```
Example (Python) (works whether JSON payload is enabled or not):
+21
View File
@@ -276,6 +276,27 @@ class DownloadHandler(ABC):
pass
```
### Optional: Listing Files Before Download
Some releases bundle several books (a whole-series torrent). Shelfmark inspects a
release before queueing it so the user can review how it will be split into books.
Override `list_files` when your source can enumerate a release's files without
downloading it; the default returns `None`, which the UI reports as "can't inspect":
```python
from shelfmark.download.postprocess.packs import PackFile
def list_files(self, release_data: dict[str, Any]) -> list[PackFile] | None:
"""Return the release's files (release-relative paths + sizes), or None."""
torrent_bytes = ... # e.g. fetch the .torrent, or scrape the indexer's detail page
return extract_file_list_from_torrent(torrent_bytes) # from download.clients.torrent_utils
```
`release_data` is the same payload the frontend sends to `/api/releases/download`
(`source_id`, `download_url`, `content_type`, `series_name`, ...). Built-in examples:
Prowlarr parses the `.torrent` it already fetches (magnet-only releases return
`None`), and AudiobookBay reads the file table off its detail page.
### Download Method Parameters
| Parameter | Type | Description |
File diff suppressed because it is too large Load Diff
+22 -1
View File
@@ -1,3 +1,24 @@
# Shelfmark Documentation
TODO
Shelfmark is a self-hosted interface for searching, requesting, and delivering books and audiobooks through the sources and services you choose to configure.
Use the guides below to set up the app, connect your library tools, and understand the main configuration areas.
## Getting Started
- [Installation](installation.md)
- [Directory and Volume Setup](configuration.md)
- [Environment Variables](environment-variables.md)
## Core Guides
- [Users & Requests](users-and-requests.md)
- [Reverse Proxy](reverse-proxy.md)
- [OIDC](oidc.md)
- [API Access](api-access.md)
- [URL Search Parameters](url-search-parameters.md)
- [Custom Scripts](custom-scripts.md)
## Help
- [Troubleshooting](troubleshooting.md)
+31 -1
View File
@@ -1,3 +1,33 @@
# Installation
TODO
Shelfmark is typically deployed with Docker Compose.
## Quick Start
1. Download the compose file from the repository:
```bash
curl -O https://raw.githubusercontent.com/calibrain/shelfmark/main/compose/docker-compose.yml
```
2. Start the service:
```bash
docker compose up -d
```
3. Open `http://localhost:8084`
4. Configure the sources, metadata providers, and delivery settings you want to use
## Next Steps
- For volume and path setup, see [Directory and Volume Setup](configuration.md)
- For environment-based setup, see [Environment Variables](environment-variables.md)
- For authentication and user management, see [Users & Requests](users-and-requests.md) and [OIDC](oidc.md)
## Notes
- Universal search is the default mode for new installs
- Direct Download is optional and must be enabled and configured before it can be used
- Torrent and usenet setups require matching download paths between Shelfmark and your download client
+65
View File
@@ -0,0 +1,65 @@
# OpenID Connect (OIDC) Authentication
## Callback URL
```
https://<your-shelfmark-domain>/api/auth/oidc/callback
```
With a subpath (`URL_BASE=/shelfmark/`):
```
https://<your-shelfmark-domain>/shelfmark/api/auth/oidc/callback
```
The callback URL is constructed from the incoming request, so your reverse proxy must forward `X-Forwarded-Proto` and `X-Forwarded-Host` correctly, including the external port when it is not the protocol default. PKCE (S256) is used automatically.
## Settings
Configure in **Settings → Security → Authentication Method → OIDC**.
| Setting | Description | Default |
|---------|-------------|---------|
| Discovery URL | `/.well-known/openid-configuration` endpoint | — |
| Client ID | OAuth2 client ID | — |
| Client Secret | OAuth2 client secret | — |
| Scopes | Scopes to request. The group claim is added automatically when admin group authorization is enabled | `openid email profile` |
| Group Claim Name | Claim containing user groups | `groups` |
| Admin Group Name | Group granted admin access. Leave empty for database-only roles | — |
| Use Admin Group for Authorization | Toggle group-based admin detection | `true` |
| Auto-Provision Users | Create accounts on first login | `true` |
| Login Button Label | Custom text for the sign-in button | — |
Use **Test Connection** to verify discovery, client configuration, and the provider's token signing keys (JWKS) before attempting login.
> **Authentik users:** make sure your provider has a **Signing Key** selected (e.g. the default self-signed certificate). Without one, Authentik serves an empty JWKS document and every login fails with an OIDC callback error, even though the discovery document looks healthy.
## Account Linking
On login, Shelfmark matches the OIDC identity to a user account in this order:
1. **OIDC subject** — a user who has logged in through this provider before.
2. **Email** — a local account with the same (unique) email address. This only happens when the provider also asserts `email_verified: true` for the address; an unverified email would let anyone claim a local account by registering its address at the IdP.
3. Otherwise, a new account is created when **Auto-Provision Users** is enabled (username conflicts get a numeric suffix), or the login is rejected with "Account not found" when it is disabled.
If the `email_verified` claim is missing or `false`, email linking is silently skipped — a common surprise when the address was never verified at the identity provider (e.g. Keycloak's **Email verified** toggle on the user, or Authentik accounts created without email verification). Make sure the `email` scope is requested and the address is marked verified in your IdP.
## Environment Variables
These optional environment variables control login page behavior when OIDC is enabled.
| Variable | Description | Default |
|----------|-------------|---------|
| `HIDE_LOCAL_AUTH` | Hide the username/password login option, so only the OIDC button is shown | `false` |
| `DISABLE_LOCAL_AUTH` | Disable username/password login and remove the local-admin prerequisite for OIDC. Implies `HIDE_LOCAL_AUTH`; with `AUTH_METHOD=builtin`, everyone is locked out until auth env vars are changed. | `false` |
| `OIDC_AUTO_REDIRECT` | Automatically redirect to the OIDC provider instead of showing the login page | `false` |
If `DISABLE_LOCAL_AUTH` and `OIDC_AUTO_REDIRECT` are both enabled, users are redirected straight to the OIDC provider. On failure they return to the login page with an error message but no password fallback.
## Troubleshooting
- **No token signing keys (empty JWKS)** — The provider's JWKS endpoint returned no keys, so ID tokens can't be verified. In Authentik this happens when the provider has no **Signing Key** selected; pick one (e.g. the default self-signed certificate) and try again.
- **Issuer validation failed** — The issuer in the token doesn't match the discovery document. Check your provider's external URL / issuer configuration.
- **Callback URL mismatch** — Reverse proxy isn't forwarding `X-Forwarded-Proto` or `X-Forwarded-Host`, so the constructed callback URL doesn't match what's registered in the provider.
- **Account not found** — Auto-provision is disabled and the user hasn't been pre-created by an admin. If you pre-created the account with a matching email, see [Account Linking](#account-linking): the provider must send `email_verified: true` for linking to happen.
- **Login created a duplicate account instead of linking to my local one** — Email linking requires a verified email; see [Account Linking](#account-linking). With `DEBUG=true`, the log notes when linking is skipped because the address isn't verified.
+32 -8
View File
@@ -6,6 +6,15 @@ Shelfmark can run behind a reverse proxy at the root path (recommended) or under
If you can serve Shelfmark at the root path (`https://shelfmark.example.com/`), leave `URL_BASE` empty. This is the simplest option and avoids extra subpath configuration.
Define this once in your Nginx `http` block so websocket upgrades are only sent when the client actually requests them:
```nginx
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
```
```nginx
server {
listen 443 ssl;
@@ -14,12 +23,13 @@ server {
location / {
proxy_pass http://shelfmark:8084;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection $connection_upgrade;
}
}
```
@@ -47,13 +57,13 @@ All Shelfmark paths (UI, API, assets, Socket.IO) are served under the base path.
location /shelfmark/ {
proxy_pass http://shelfmark:8084/shelfmark/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
proxy_buffering off;
@@ -77,6 +87,7 @@ Configure in Settings → Security:
| Proxy Auth Logout URL | `https://auth.example.com/logout` |
| Proxy Auth Admin Group Header | `Remote-Groups` |
| Proxy Auth Admin Group Name | `admins` (or your admin group) |
| Proxy Auth Default Role | `User` — first-time users are regular users; the very first account is still made admin. Only consulted when no admin group is set |
#### Nginx Configuration with Authelia
@@ -127,13 +138,13 @@ location /shelfmark/ {
proxy_pass http://shelfmark:8084/shelfmark/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
proxy_buffering off;
@@ -142,6 +153,19 @@ location /shelfmark/ {
---
## Troubleshooting false network errors
If login, settings saves, or downloads appear to fail in the browser but the action still completes on the server, check your proxy headers first.
- Do not force `Connection: upgrade` on every request. That can break normal `POST` and `PUT` responses while the backend still processes them.
- If your proxy UI does not support conditional websocket headers, remove the forced websocket headers entirely and let Shelfmark fall back to polling.
- Keep the standard forwarded headers: `Host`, `X-Forwarded-For`, `X-Forwarded-Proto`, and `X-Forwarded-Host` when using a subpath or OIDC.
- Preserve the original port in `Host` and `X-Forwarded-Host` by using `$http_host` rather than `$host` when Shelfmark is exposed on a custom port.
This is especially relevant for Nginx Proxy Manager or custom advanced config snippets that add websocket headers globally.
---
## Health checks
Health checks work at `/shelfmark/api/health` when using a subpath configuration.
+59 -22
View File
@@ -1,75 +1,112 @@
# URL Search Parameters
You can trigger searches directly via URL by adding query parameters. This enables bookmarking searches and sharing links.
You can trigger searches directly via URL. This enables bookmarking searches and sharing links.
Parameters live in the URL **hash** (`#…`), so they stay in the browser and are never sent to
the server. Shelfmark also keeps the hash in sync as you search, so the address bar always
holds a shareable link to what you're looking at.
## Basic Usage
```
http://your-server:8084/?q=harry+potter
http://your-server:8084/#q=harry+potter
```
Older query-string links (`/?q=harry+potter`) still work: they're read once on load and
rewritten to the hash form.
## Supported Parameters
| Parameter | Description | Example |
|-----------|-------------|---------|
| `q` or `query` | Main search query | `/?q=dune` |
| `author` | Filter by author name | `/?author=frank+herbert` |
| `title` | Filter by book title | `/?title=foundation` |
| `isbn` | Filter by ISBN | `/?isbn=978-0747532699` |
| `lang` | Filter by language (ISO 639-1 code) | `/?lang=en` |
| `format` | Filter by file format | `/?format=epub` |
| `content` | Filter by content type | `/?content=fiction` |
| `sort` | Sort order for results | `/?sort=newest` |
| `q` or `query` | Main search query | `/#q=dune` |
| `author` | Filter by author name | `/#author=frank+herbert` |
| `title` | Filter by book title | `/#title=foundation` |
| `isbn` | Filter by ISBN | `/#isbn=978-0747532699` |
| `lang` | Filter by language (ISO 639-1 code) | `/#lang=en` |
| `format` | Filter by file format | `/#format=epub` |
| `content` | Filter by content type | `/#content=fiction` |
| `content_type` | Select media type (`ebook`, `audiobook`, or `combined`) in Universal mode only | `/#q=dune&content_type=audiobook` |
| `sort` | Sort order for results | `/#sort=newest` |
| `search_by` | "Search By" target the query applies to (`general`, `author`, `title`, `isbn`, a metadata provider field like `series`, or `manual`) | `/#search_by=author&q=frank+herbert` |
## Multiple Values
Some parameters support multiple values by repeating the parameter:
```
/?lang=en&lang=de&lang=fr
/?format=epub&format=mobi&format=azw3
/#lang=en&lang=de&lang=fr
/#format=epub&format=mobi&format=azw3
```
## Examples
**Simple search:**
```
/?q=lord+of+the+rings
/#q=lord+of+the+rings
```
**Search with author filter:**
```
/?q=dune&author=frank+herbert
/#q=dune&author=frank+herbert
```
**Search with format and language:**
```
/?q=harry+potter&format=epub&lang=en
/#q=harry+potter&format=epub&lang=en
```
**Author search with multiple formats:**
```
/?author=stephen+king&format=epub&format=mobi
/#author=stephen+king&format=epub&format=mobi
```
**Search with sort order:**
```
/?q=science+fiction&sort=newest
/#q=science+fiction&sort=newest
```
**Universal search as audiobook:**
```
/#q=dune&content_type=audiobook
```
**Universal search forcing combined (ebook + audiobook):**
```
/#q=dune&content_type=combined
```
## Search Mode Behavior
### Direct Download Mode (default)
### Direct Mode
All parameters are used to filter results from the direct download source.
When Search Mode is set to Direct, all parameters are used to filter results from the configured direct source.
`content_type` is ignored in Direct mode.
### Universal Mode
Only `q` and `sort` are used. Other parameters (author, title, format, etc.) are silently ignored since metadata providers have their own search capabilities.
`q`, `search_by`, `sort`, and `content_type` are used. Other parameters (author, title, format, etc.) are silently ignored since metadata providers have their own search capabilities — except when `search_by` names one of the provider's own search fields, in which case `q` is sent as that field's value.
`content_type=combined` forces combined mode (search ebook and audiobook providers together), overriding the last-used preference. It is silently ignored if combined mode is unavailable (e.g. the combined selector is disabled in settings, or either content type is blocked by request policy).
## Search By
`search_by` picks which target the `q` value is applied to, matching the selector next to the
search box. It can be deep-linked on its own (`/#search_by=manual`) to open the app in that
mode with an empty query.
`search_by=manual` fills the search box but does not auto-run: manual search opens the release
browser from an explicit submit.
A `search_by` naming a target that isn't available (wrong search mode, or a metadata provider
that doesn't offer that field) is ignored, and the query falls back to a general search.
## Notes
- URL parameters are read once on page load
- The URL is not updated when you perform searches manually
- URL parameters are read once on page load, and again if the hash is replaced in an open tab
(e.g. pasting a shared link into the address bar)
- The hash is kept in sync with the search box, Search By target and filters as you search
- Spaces should be encoded as `+` or `%20`
- Invalid or unknown parameters are silently ignored
- Your last-used Search By target is remembered in browser storage and used when a link
doesn't specify one
+107
View File
@@ -0,0 +1,107 @@
# Users & Requests
Configure in **Settings → Users & Requests**.
## Authentication Methods
Shelfmark supports four authentication methods, configured in **Settings → Security**.
### Local
You create user accounts directly in Shelfmark with a username and password. At least one local admin account must exist before this mode can be enabled.
### Proxy Authentication
Your reverse proxy handles authentication and passes the username to Shelfmark via a header (e.g. `Remote-User`). Accounts are created automatically on first sign-in. If a local user with the same username already exists, the proxy identity will be linked to that account rather than creating a duplicate. Admin status can optionally be derived from a groups header.
### OIDC (OpenID Connect)
Users sign in through your identity provider. Accounts are created automatically on first login (unless auto-provisioning is disabled, in which case you need to pre-create them). If a local user with a matching verified email already exists, the OIDC identity will be linked to that account on first sign-in. Admin status can optionally be derived from a group claim.
A local admin account is required as a fallback. See [OIDC](oidc.md) for provider setup.
### Calibre-Web Database
User accounts are synced from your Calibre-Web `app.db`. If a local user with a matching email already exists, the CWA identity will be linked to that account. Roles are kept in sync with CWA. Users removed from CWA are cleaned up on the next sync.
Requires mounting your Calibre-Web `app.db` to `/auth/app.db`.
## Per-User Settings
Admins can configure per-user settings by editing a user in the user management panel. Non-admin users can also edit their own settings through **My Account** (accessible from the user menu). Admins control which sections are visible in My Account via the **Visible Self-Settings Sections** option.
There are four categories of per-user settings:
### Delivery Preferences
Override where a user's downloads are sent. Options depend on the global output mode configuration:
- **Output mode** — Folder, Email (SMTP), or BookLore (API)
- **Destination** — A custom folder path for this user's ebook downloads
- **Audiobook destination** — A custom folder path for audiobook downloads
- **BookLore library/path** — Per-user BookLore target (when using BookLore output mode)
- **Email recipient** — Per-user email address (when using Email output mode)
### Search Preferences
Override how a user searches, on top of the global search defaults:
- **Search mode** — Direct or Universal for this user
- **Default book languages** — The languages a user's searches fall back to when they don't pick one themselves. Useful for a shared instance where readers want different languages.
- **Metadata providers** — Book, audiobook, and combined-mode provider for this user
- **Default release sources** — The release tab opened first for books and audiobooks
### Notifications
Users can configure personal notification routes, separate from the global notification settings. Each route targets a URL (e.g. an Apprise-compatible endpoint) and can be scoped to specific event types or all events.
### Request Policy (admin-only)
Admins can override the default ebook/audiobook modes and request rules for individual users. See [Per-User Overrides](#per-user-overrides) below.
---
## Requests
The request system controls whether users can download directly or need admin approval first.
### Policy Modes
Each content type (ebook, audiobook) has a default mode that sets the baseline:
| Mode | Behaviour |
|------|-----------|
| **Download** | Users download directly, no approval needed |
| **Request Release** | Users pick a specific release, then submit it for admin approval |
| **Request Book** | Users request the book itself — an admin picks the release and fulfils it |
| **Blocked** | No downloads or requests allowed |
### Settings
| Setting | Description | Default |
|---------|-------------|---------|
| Enable Requests | Master toggle. When off, everyone downloads directly | Off |
| Default Ebook Mode | Baseline mode for all ebook sources | Download |
| Default Audiobook Mode | Baseline mode for all audiobook sources | Download |
| Request Rules | Per-source overrides (see below) | None |
| Max Pending Requests Per User | Open request limit per user | 20 |
| Allow Notes on Requests | Let users attach a note when submitting | On |
### Request Rules
The rules matrix lets you override the mode for specific source + content type combinations. Rules can only be **equal to or more restrictive** than the content-type default — they cannot grant more access than the baseline.
For example, if the default ebook mode is "Download", a rule can restrict a specific source to "Request Release" or "Blocked", but not the other way around. If no rule matches, the content-type default applies.
### Per-User Overrides
Admins can override the default ebook/audiobook modes and request rules for individual users. Per-user rules are overlaid on the global rules, not replacing them.
### Request Lifecycle
1. User submits a request (book or release level, depending on the resolved policy mode)
2. Request appears in the admin request queue as **pending**
3. Admin either **fulfils** (queues a download) or **rejects** the request
4. For fulfilled requests, delivery state is tracked through the download pipeline
5. If delivery fails, an admin can reopen the request to try a different release
6. Users can cancel their own pending requests
+389 -142
View File
@@ -1,5 +1,7 @@
#!/bin/bash
set -e
is_truthy() {
case "${1,,}" in
true|yes|1|y) return 0 ;;
@@ -11,6 +13,16 @@ ENABLE_LOGGING_VALUE="${ENABLE_LOGGING:-true}"
LOG_PIPE_DIR=""
LOG_PIPE=""
TEE_PID=""
FILE_LOGGING_ENABLED="false"
CURRENT_UID=$(id -u)
CURRENT_GID=$(id -g)
RUN_AS_NON_ROOT="false"
RUNTIME_TMP_DIR="${TMP_DIR:-/tmp/shelfmark}"
DEFAULT_RUNTIME_HOME="${RUNTIME_TMP_DIR}/home"
if [ "$CURRENT_UID" != "0" ]; then
RUN_AS_NON_ROOT="true"
fi
start_file_logging() {
local logfile="$1"
@@ -43,30 +55,84 @@ stop_file_logging() {
if is_truthy "$ENABLE_LOGGING_VALUE"; then
LOG_DIR=${LOG_ROOT:-/var/log/}/shelfmark
mkdir -p "$LOG_DIR"
LOG_FILE="${LOG_DIR}/shelfmark_entrypoint.log"
if mkdir -p "$LOG_DIR" 2>/dev/null; then
LOG_FILE="${LOG_DIR}/shelfmark_entrypoint.log"
# Keep the previous entrypoint log instead of deleting all history on boot.
rotation_ok="true"
if [ -f "${LOG_FILE}.prev" ] && ! rm -f "${LOG_FILE}.prev"; then
echo "Warning: could not remove previous entrypoint log ${LOG_FILE}.prev, continuing without file logging" >&2
rotation_ok="false"
fi
if [ "$rotation_ok" = "true" ] && [ -f "$LOG_FILE" ] && ! mv "$LOG_FILE" "${LOG_FILE}.prev"; then
echo "Warning: could not rotate entrypoint log $LOG_FILE, continuing without file logging" >&2
rotation_ok="false"
fi
# Cleanup any existing files or folders in the log directory
rm -rf "$LOG_DIR"/*
if [ "$rotation_ok" = "true" ]; then
FILE_LOGGING_ENABLED="true"
else
ENABLE_LOGGING_VALUE="false"
export ENABLE_LOGGING="false"
fi
else
echo "Warning: could not create log directory $LOG_DIR, continuing without file logging" >&2
ENABLE_LOGGING_VALUE="false"
export ENABLE_LOGGING="false"
fi
fi
(
if [ "$USING_TOR" = "true" ]; then
./tor.sh
fi
)
# Egress modes are mutually exclusive. Check this BEFORE starting either one so
# we never run tor.sh and then abort, leaving a half-configured network stack.
if [ "$USING_TOR" = "true" ] && [ "$USING_WIREGUARD" = "true" ]; then
echo "USING_TOR and USING_WIREGUARD are mutually exclusive; enable only one egress mode." >&2
exit 1
fi
if is_truthy "$ENABLE_LOGGING_VALUE"; then
if [ "$USING_TOR" = "true" ]; then
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
echo "USING_TOR=true requires the container to start as root." >&2
echo "Non-root mode skips the privileged filesystem and network setup Tor depends on." >&2
exit 1
fi
./tor.sh
fi
if [ "$USING_WIREGUARD" = "true" ]; then
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
echo "USING_WIREGUARD=true requires the container to start as root." >&2
echo "Non-root mode skips the privileged network setup WireGuard depends on." >&2
exit 1
fi
./wireguard.sh
fi
if [ "$FILE_LOGGING_ENABLED" = "true" ]; then
start_file_logging "$LOG_FILE"
fi
echo "Starting entrypoint script"
if is_truthy "$ENABLE_LOGGING_VALUE"; then
if [ "$FILE_LOGGING_ENABLED" = "true" ]; then
echo "Log file: $LOG_FILE"
else
echo "File logging disabled (ENABLE_LOGGING=$ENABLE_LOGGING_VALUE)"
fi
set -e
PYTHON_BIN="/app/.venv/bin/python"
if [ ! -x "$PYTHON_BIN" ]; then
PYTHON_BIN="python3"
fi
# Defensive: some orchestrators (e.g. Unraid Dockhand templates) inject a default
# PATH that drops the venv bin directory baked in by the Dockerfile. Prepend it
# so subprocesses launched without an absolute path still resolve correctly.
case ":${PATH}:" in
*":/app/.venv/bin:"*) ;;
*) export PATH="/app/.venv/bin:${PATH}" ;;
esac
GUNICORN_BIN="/app/.venv/bin/gunicorn"
if [ ! -x "$GUNICORN_BIN" ]; then
GUNICORN_BIN="gunicorn"
fi
# Print build version
echo "Build version: $BUILD_VERSION"
@@ -74,67 +140,133 @@ echo "Release version: $RELEASE_VERSION"
# Configure timezone
if [ "$TZ" ]; then
echo "Setting timezone to $TZ"
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
echo "TZ is set to $TZ (non-root mode leaves /etc/localtime unchanged)"
else
echo "Setting timezone to $TZ"
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
fi
fi
# Determine user ID with proper precedence:
# 1. PUID (LinuxServer.io standard - recommended)
# 2. UID (legacy, for backward compatibility with existing installs)
# 3. Default to 1000
#
# Note: $UID is a bash builtin that's always set. We use `printenv` to detect
# if UID was explicitly set as an environment variable (e.g., via docker-compose).
if [ -n "$PUID" ]; then
RUN_UID="$PUID"
echo "Using PUID=$RUN_UID"
elif printenv UID >/dev/null 2>&1; then
RUN_UID="$(printenv UID)"
echo "Using UID=$RUN_UID (legacy - consider migrating to PUID)"
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
RUN_UID="$CURRENT_UID"
RUN_GID="$CURRENT_GID"
USERNAME=$(getent passwd "$RUN_UID" 2>/dev/null | cut -d: -f1 || true)
if [ -z "$USERNAME" ]; then
USERNAME="$RUN_UID"
echo "No passwd entry found for UID $RUN_UID; using numeric identity"
fi
TARGET_USER_SPEC="${RUN_UID}:${RUN_GID}"
else
RUN_UID=1000
echo "Using default UID=$RUN_UID"
# Determine user ID with proper precedence:
# 1. PUID (LinuxServer.io standard - recommended)
# 2. UID (legacy, for backward compatibility with existing installs)
# 3. Default to 1000
#
# Note: $UID is a bash builtin that's always set. We use `printenv` to detect
# if UID was explicitly set as an environment variable (e.g., via docker-compose).
if [ -n "$PUID" ]; then
RUN_UID="$PUID"
echo "Using PUID=$RUN_UID"
elif printenv UID >/dev/null 2>&1; then
RUN_UID="$(printenv UID)"
echo "Using UID=$RUN_UID (legacy - consider migrating to PUID)"
else
RUN_UID=1000
echo "Using default UID=$RUN_UID"
fi
# Determine group ID with proper precedence:
# 1. PGID (LinuxServer.io standard - recommended)
# 2. GID (legacy, for backward compatibility with existing installs)
# 3. Default to 1000
if [ -n "$PGID" ]; then
RUN_GID="$PGID"
echo "Using PGID=$RUN_GID"
elif [ -n "$GID" ]; then
RUN_GID="$GID"
echo "Using GID=$RUN_GID (legacy - consider migrating to PGID)"
else
RUN_GID=1000
echo "Using default GID=$RUN_GID"
fi
if ! getent group "$RUN_GID" >/dev/null; then
echo "Adding group $RUN_GID with name appuser"
groupadd -g "$RUN_GID" appuser
fi
# Create user if it doesn't exist for this UID yet.
if ! getent passwd "$RUN_UID" >/dev/null; then
echo "Adding user $RUN_UID with name appuser"
useradd -u "$RUN_UID" -g "$RUN_GID" -d "$DEFAULT_RUNTIME_HOME" -s /sbin/nologin appuser
fi
# Get username for the UID (whether we just created it or it existed)
USERNAME=$(getent passwd "$RUN_UID" | cut -d: -f1)
if [ -z "$USERNAME" ]; then
USERNAME="$RUN_UID"
fi
TARGET_USER_SPEC="${RUN_UID}:${RUN_GID}"
fi
# Determine group ID with proper precedence:
# 1. PGID (LinuxServer.io standard - recommended)
# 2. GID (legacy, for backward compatibility with existing installs)
# 3. Default to 1000
if [ -n "$PGID" ]; then
RUN_GID="$PGID"
echo "Using PGID=$RUN_GID"
elif [ -n "$GID" ]; then
RUN_GID="$GID"
echo "Using GID=$RUN_GID (legacy - consider migrating to PGID)"
else
RUN_GID=1000
echo "Using default GID=$RUN_GID"
fi
# Avoid unnecessary gosu hops when we're already running as the target user.
# Some nested LXC setups spin on root-to-root gosu invocations.
needs_user_switch() {
local current_uid
local current_gid
if ! getent group "$RUN_GID" >/dev/null; then
echo "Adding group $RUN_GID with name appuser"
groupadd -g "$RUN_GID" appuser
fi
current_uid=$(id -u)
current_gid=$(id -g)
# Create user if it doesn't exist
if ! id -u "$RUN_UID" >/dev/null 2>&1; then
echo "Adding user $RUN_UID with name appuser"
useradd -u "$RUN_UID" -g "$RUN_GID" -d /app -s /sbin/nologin appuser
fi
[ "$current_uid" != "$RUN_UID" ] || [ "$current_gid" != "$RUN_GID" ]
}
# Get username for the UID (whether we just created it or it existed)
USERNAME=$(getent passwd "$RUN_UID" | cut -d: -f1)
echo "Username for UID $RUN_UID is $USERNAME"
run_as_target_user() {
if needs_user_switch; then
gosu "$TARGET_USER_SPEC" "$@"
return $?
fi
"$@"
}
exec_as_target_user() {
if needs_user_switch; then
exec gosu "$TARGET_USER_SPEC" "$@"
fi
exec "$@"
}
test_write() {
folder=$1
test_file=$folder/shelfmark_TEST_WRITE
mkdir -p $folder
(
echo 0123456789_TEST | sudo -E -u "$USERNAME" HOME=/app tee $test_file > /dev/null
)
FILE_CONTENT=$(cat $test_file || echo "")
rm -f $test_file
local folder=$1
local test_file="$folder/shelfmark_TEST_WRITE"
local FILE_CONTENT
local result
local result_text
if ! mkdir -p "$folder"; then
echo "Failed to create directory for write test: $folder"
return 1
fi
# This is a probe: a failure here is expected (e.g. a fresh root-owned bind
# mount) and is recovered by the caller via change_ownership + re-probe. Hide
# the shell's "Permission denied"/"Read-only file system" stderr so a handled
# probe miss doesn't masquerade as a real boot failure in the logs.
if ! run_as_target_user sh -c 'echo 0123456789_TEST 2>/dev/null > "$1"' _ "$test_file"; then
echo "Failed to write test file in $folder as $USERNAME"
return 1
fi
FILE_CONTENT=$(cat "$test_file" 2>/dev/null || echo "")
# A folder can be writable but not deletable (e.g. a Synology share without
# "Delete subfolders and files"). That is not a boot failure - the app writes
# files in place on such shares - so don't let a failed cleanup print an
# alarming error or fail the probe.
run_as_target_user rm -f "$test_file" 2>/dev/null || \
echo "Note: could not remove test file in $folder (folder is writable but not deletable)"
[ "$FILE_CONTENT" = "0123456789_TEST" ]
result=$?
if [ $result -eq 0 ]; then
@@ -147,34 +279,43 @@ test_write() {
}
make_writable() {
folder=$1
did_full_chown=0
local folder="$1"
local mode="${2:-tree}"
local did_full_chown=0
local is_writable
set +e
test_write $folder
test_write "$folder"
is_writable=$?
set -e
if [ $is_writable -eq 0 ]; then
echo "Folder $folder is writable, no need to change ownership"
else
echo "Folder $folder is not writable, changing ownership"
change_ownership $folder
chmod -R g+r,g+w $folder || echo "Failed to change group permissions for ${folder}, continuing..."
if [ "$mode" = "root" ]; then
echo "Folder $folder is not writable, fixing top-level ownership and permissions"
mkdir -p "$folder"
chown "${RUN_UID}:${RUN_GID}" "$folder" || echo "Failed to change ownership for ${folder}, continuing..."
chmod u+rwx "$folder" || echo "Failed to change owner permissions for ${folder}, continuing..."
else
echo "Folder $folder is not writable, changing ownership"
change_ownership "$folder"
chmod -R g+r,g+w "$folder" || echo "Failed to change group permissions for ${folder}, continuing..."
fi
did_full_chown=1
fi
# Fix any misowned subdirectories/files (e.g., from previous runs as root)
if [ "$did_full_chown" -eq 0 ] && [ -d "$folder" ]; then
if [ "$mode" = "tree" ] && [ "$did_full_chown" -eq 0 ] && [ -d "$folder" ]; then
echo "Checking for misowned files/directories in $folder"
# Stay on the same filesystem to avoid traversing mounted subpaths
# (for example read-only bind mounts under /app in dev setups).
find "$folder" -xdev -mindepth 1 \( ! -user "$RUN_UID" -o ! -group "$RUN_GID" \) \
-exec chown "$RUN_UID:$RUN_GID" {} + 2>/dev/null || true
fi
test_write $folder || echo "Failed to test write to ${folder}, continuing..."
test_write "$folder" || echo "Failed to test write to ${folder}, continuing..."
}
fix_misowned() {
folder=$1
mkdir -p $folder
local folder="$1"
mkdir -p "$folder"
echo "Checking for misowned files/directories in $folder"
# Stay on the same filesystem to avoid traversing mounted subpaths
# (for example read-only bind mounts under /app in dev setups).
@@ -184,89 +325,178 @@ fix_misowned() {
# Ensure proper ownership of application directories
change_ownership() {
folder=$1
mkdir -p $folder
local folder="$1"
mkdir -p "$folder"
echo "Changing ownership of $folder to $USERNAME:$RUN_GID"
chown -R "${RUN_UID}:${RUN_GID}" "${folder}" || echo "Failed to change ownership for ${folder}, continuing..."
}
fix_misowned /app
fix_misowned /var/log/shelfmark
fix_misowned /tmp/shelfmark
require_writable_dir() {
local folder="$1"
local label="${2:-Directory}"
# SeleniumBase (internal bypasser) writes a patched chromedriver binary (uc_driver)
# into its own drivers directory. Some NAS/docker setups can apply restrictive ACLs
# to extracted image layers that block non-root writes; ensure the runtime UID owns it.
if [ "${USING_EXTERNAL_BYPASSER}" != "true" ]; then
set +e
SELENIUMBASE_DRIVERS_DIR=$(python3 -c "import pathlib, seleniumbase; print(pathlib.Path(seleniumbase.__file__).resolve().parent / 'drivers')" 2>/dev/null)
set -e
if ! mkdir -p "$folder"; then
echo "Failed to create ${label} directory: $folder"
exit 1
fi
if [ -n "$SELENIUMBASE_DRIVERS_DIR" ] && [ -d "$SELENIUMBASE_DRIVERS_DIR" ]; then
change_ownership "$SELENIUMBASE_DRIVERS_DIR"
if ! test_write "$folder"; then
echo "${label} directory is not writable in non-root mode: $folder"
echo "Prepare ownership outside the container (for example with a pre-owned volume or Kubernetes fsGroup)."
exit 1
fi
}
# If the driver already exists, ensure it's executable for the runtime user.
if [ -f "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" ]; then
chmod +x "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" || echo "Failed to chmod uc_driver, continuing..."
fail_unwritable_config_dir() {
local folder="$1"
local owner
owner=$(stat -c '%u:%g' "$folder" 2>/dev/null || echo "unknown")
echo ""
echo "========================================================"
echo "ERROR: Config directory is not writable!"
echo ""
echo "Config directory: $folder"
echo "Current owner: $owner"
echo "Configured runtime identity: ${RUN_UID}:${RUN_GID}"
echo ""
echo "To fix this permanently, run on your HOST machine:"
echo " chown -R $RUN_UID:$RUN_GID /path/to/config"
echo "========================================================"
echo ""
exit 1
}
resolve_runtime_home() {
local runtime_home
runtime_home=$(getent passwd "$RUN_UID" 2>/dev/null | cut -d: -f6 || true)
case "$runtime_home" in
""|/|/app|/nonexistent)
runtime_home="$DEFAULT_RUNTIME_HOME"
;;
esac
printf '%s\n' "$runtime_home"
}
ensure_tree_writable() {
local folder="$1"
make_writable "$folder"
if [ -d "$folder" ]; then
chmod -R u+rwX,g+rwX "$folder" || echo "Failed to relax permissions for ${folder}, continuing..."
fi
}
ensure_symlinked_dir() {
local link_path="$1"
local target_path="$2"
ensure_tree_writable "$target_path"
if [ -L "$link_path" ]; then
local current_target
current_target=$(readlink "$link_path" 2>/dev/null || echo "")
if [ "$current_target" = "$target_path" ]; then
echo "$link_path already points to $target_path"
return 0
fi
echo "Replacing symlink $link_path -> $current_target with $target_path"
rm -f "$link_path" || echo "Failed to replace symlink ${link_path}, continuing..."
elif [ -d "$link_path" ]; then
echo "Moving existing scratch files from $link_path to $target_path"
find "$link_path" -xdev -mindepth 1 -maxdepth 1 -exec mv -t "$target_path" {} + 2>/dev/null || true
ensure_tree_writable "$target_path"
if ! rmdir "$link_path" 2>/dev/null; then
echo "Could not replace $link_path with symlink, leaving existing directory in place"
ensure_tree_writable "$link_path"
return 0
fi
elif [ -e "$link_path" ]; then
echo "$link_path exists and is not a directory, leaving it in place"
return 0
fi
if [ ! -e "$link_path" ]; then
ln -s "$target_path" "$link_path" || echo "Failed to create symlink ${link_path}, continuing..."
fi
}
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
require_writable_dir /tmp/shelfmark "Temporary"
if [ "${USING_EXTERNAL_BYPASSER}" != "true" ]; then
require_writable_dir /tmp/shelfmark/seleniumbase/downloaded_files "SeleniumBase downloads"
require_writable_dir /tmp/shelfmark/seleniumbase/archived_files "SeleniumBase archive"
fi
require_writable_dir "${CONFIG_DIR:-/config}" "Config"
else
fix_misowned /var/log/shelfmark
fix_misowned /tmp/shelfmark
# Keep SeleniumBase on its default /app-based paths, but redirect the scratch
# directories into /tmp so bypasser startup doesn't depend on image-layer writes.
if [ "${USING_EXTERNAL_BYPASSER}" != "true" ]; then
ensure_symlinked_dir /app/downloaded_files /tmp/shelfmark/seleniumbase/downloaded_files
ensure_symlinked_dir /app/archived_files /tmp/shelfmark/seleniumbase/archived_files
# Keep SeleniumBase's bundled drivers directory writable as well for
# compatibility with legacy UC code paths that still probe bundled assets.
set +e
SELENIUMBASE_DRIVERS_DIR=$("$PYTHON_BIN" -c "import pathlib, seleniumbase; print(pathlib.Path(seleniumbase.__file__).resolve().parent / 'drivers')" 2>/dev/null)
set -e
if [ -n "$SELENIUMBASE_DRIVERS_DIR" ] && [ -d "$SELENIUMBASE_DRIVERS_DIR" ]; then
change_ownership "$SELENIUMBASE_DRIVERS_DIR"
# If the legacy driver already exists, ensure it's executable for the runtime user.
if [ -f "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" ]; then
chmod +x "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" || echo "Failed to chmod uc_driver, continuing..."
fi
fi
fi
fi
# Test write to all folders
make_writable ${CONFIG_DIR:-/config}
make_writable ${INGEST_DIR:-/books}
# Config is Shelfmark-owned state, so it keeps the thorough repair path.
make_writable "${CONFIG_DIR:-/config}" tree
# Fix permissions on directories configured in settings
echo "Checking for additional configured directories..."
if [ -f /app/scripts/fix_permissions.py ]; then
configured_dirs=$(python3 /app/scripts/fix_permissions.py 2>/dev/null || echo "")
if [ -n "$configured_dirs" ]; then
echo "$configured_dirs" | while read -r dir; do
if [ -n "$dir" ] && [ -d "$dir" ]; then
echo "Checking configured directory: $dir"
make_writable "$dir"
fi
done
# Refuse to continue if the config directory is still not writable after repair.
CONFIG_PATH=${CONFIG_DIR:-/config}
set +e
test_write "$CONFIG_PATH" >/dev/null 2>&1
config_ok=$?
set -e
if [ $config_ok -ne 0 ]; then
fail_unwritable_config_dir "$CONFIG_PATH"
fi
fi
# Fallback to root if config dir is still not writable (common on NAS/Unraid after upgrade from v0.4.0)
CONFIG_PATH=${CONFIG_DIR:-/config}
set +e
test_write "$CONFIG_PATH" >/dev/null 2>&1
config_ok=$?
set -e
if [ $config_ok -ne 0 ] && [ "$RUN_UID" != "0" ]; then
config_owner=$(stat -c '%u' "$CONFIG_PATH" 2>/dev/null || echo "unknown")
if [ "$config_owner" = "0" ]; then
echo ""
echo "========================================================"
echo "WARNING: Permission issue detected!"
echo ""
echo "Config directory is owned by root but PUID=$RUN_UID."
echo "This typically happens after upgrading from v0.4.0 where"
echo "PUID/PGID settings were not respected."
echo ""
echo "Falling back to running as root to prevent data loss."
echo ""
echo "To fix this permanently, run on your HOST machine:"
echo " chown -R $RUN_UID:$RUN_GID /path/to/config"
echo ""
echo "Then restart the container."
echo "========================================================"
echo ""
RUN_UID=0
RUN_GID=0
USERNAME=root
fi
# The ingest/destination library (default /books) is user data and may be a
# bind mount owned by another uid; downloads fail with "Destination not
# writable" if the runtime user can't write there. Fix the top-level dir only
# (root mode) so we don't recursively chown a potentially huge library.
make_writable "${INGEST_DIR:-/books}" root
fi
# Always run Gunicorn (even when DEBUG=true) to ensure Socket.IO WebSocket
# upgrades work reliably on customer machines.
# Map app LOG_LEVEL (often DEBUG/INFO/...) to gunicorn's --log-level (lowercase).
gunicorn_loglevel=$([ "$DEBUG" = "true" ] && echo debug || echo "${LOG_LEVEL:-info}" | tr '[:upper:]' '[:lower:]')
command="gunicorn --log-level ${gunicorn_loglevel} --access-logfile - --error-logfile - --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker --workers 1 -t 300 -b ${FLASK_HOST:-0.0.0.0}:${FLASK_PORT:-8084} shelfmark.main:app"
# Gunicorn rejects anything outside its own list, so normalize and fall back to
# info rather than letting a typo stop the container from booting.
if [ "$DEBUG" = "true" ]; then
gunicorn_loglevel=debug
else
gunicorn_loglevel=$(echo "${LOG_LEVEL:-info}" | tr '[:upper:]' '[:lower:]')
[ "$gunicorn_loglevel" = "warn" ] && gunicorn_loglevel=warning
case "$gunicorn_loglevel" in
debug|info|warning|error|critical) ;;
*) gunicorn_loglevel=info ;;
esac
fi
command="${GUNICORN_BIN} --log-level ${gunicorn_loglevel} --access-logfile - --error-logfile - --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker --workers 1 -t 300 -b ${FLASK_HOST:-0.0.0.0}:${FLASK_PORT:-8084} shelfmark.main:app"
# If DEBUG and not using an external bypass
if [ "$DEBUG" = "true" ] && [ "$USING_EXTERNAL_BYPASSER" != "true" ]; then
@@ -274,7 +504,7 @@ if [ "$DEBUG" = "true" ] && [ "$USING_EXTERNAL_BYPASSER" != "true" ]; then
set -x
echo "vvvvvvvvvvvv DEBUG MODE vvvvvvvvvvvv"
echo "Starting Xvfb for debugging"
python3 -c "from pyvirtualdisplay import Display; Display(visible=False, size=(1440,1880)).start()"
"$PYTHON_BIN" -c "from pyvirtualdisplay import Display; Display(visible=False, size=(1440,1880)).start()"
id
free -h
uname -a
@@ -294,7 +524,7 @@ if [ "$DEBUG" = "true" ] && [ "$USING_EXTERNAL_BYPASSER" != "true" ]; then
--enable-logging --v=1 --log-level=0 \
--log-file=/tmp/chrome_entrypoint_test.log \
--crash-dumps-dir=/tmp/chrome_crash_dumps \
< /dev/null
< /dev/null
EXIT_CODE=$?
echo "Chrome exit code: $EXIT_CODE"
ls -lh /tmp/chrome_entrypoint_test.log
@@ -334,7 +564,24 @@ else
exit 1
fi
echo "Running command: '$command' as '$USERNAME' (debug=$is_debug)"
RUNTIME_HOME=$(resolve_runtime_home)
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
require_writable_dir "$RUNTIME_HOME" "Home"
else
mkdir -p "$RUNTIME_HOME"
make_writable "$RUNTIME_HOME" tree
fi
if [ "$RUN_AS_NON_ROOT" = "true" ]; then
echo "Startup mode: non-root"
elif [ "$RUN_UID" = "0" ] && [ "$RUN_GID" = "0" ]; then
echo "Startup mode: root"
else
echo "Startup mode: root bootstrap with privilege drop"
fi
echo "Runtime identity: $USERNAME (${RUN_UID}:${RUN_GID})"
echo "Running command: '$command' as '$USERNAME' (debug=${DEBUG:-false})"
# Set umask for file permissions (default: 0022 = files 644, dirs 755)
UMASK_VALUE=${UMASK:-0022}
@@ -342,4 +589,4 @@ echo "Setting umask to $UMASK_VALUE"
umask $UMASK_VALUE
stop_file_logging
exec sudo -E -u "$USERNAME" HOME=/app $command
exec_as_target_user env HOME="$RUNTIME_HOME" $command
-1
View File
@@ -199,4 +199,3 @@ else
echo "Failed to create debug archive"
exit 1
fi
-1
View File
@@ -1 +0,0 @@
../baseline-browser-mapping/dist/cli.js
-17
View File
@@ -1,17 +0,0 @@
{
"name": "shelfmark",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/baseline-browser-mapping": {
"version": "2.9.19",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
}
}
}
-201
View File
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-463
View File
@@ -1,463 +0,0 @@
# [`baseline-browser-mapping`](https://github.com/web-platform-dx/web-features/packages/baseline-browser-mapping)
By the [W3C WebDX Community Group](https://www.w3.org/community/webdx/) and contributors.
`baseline-browser-mapping` provides:
- An `Array` of browsers compatible with Baseline Widely available and Baseline year feature sets via the [`getCompatibleVersions()` function](#get-baseline-widely-available-browser-versions-or-baseline-year-browser-versions).
- An `Array`, `Object` or `CSV` as a string describing the Baseline feature set support of all browser versions included in the module's data set via the [`getAllVersions()` function](#get-data-for-all-browser-versions).
You can use `baseline-browser-mapping` to help you determine minimum browser version support for your chosen Baseline feature set; or to analyse the level of support for different Baseline feature sets in your site's traffic by joining the data with your analytics data.
## Install for local development
To install the package, run:
`npm install --save-dev baseline-browser-mapping`
`baseline-browser-mapping` depends on `web-features` and `@mdn/browser-compat-data` for core browser version selection, but the data is pre-packaged and minified. This package checks for updates to those modules and the supported [downstream browsers](#downstream-browsers) on a daily basis and is updated frequently. Consider adding a script to your `package.json` to update `baseline-browser-mapping` and using it as part of your build process to ensure your data is as up to date as possible:
```javascript
"scripts": [
"refresh-baseline-browser-mapping": "npm i --save-dev baseline-browser-mapping@latest"
]
```
The minimum supported NodeJS version for `baseline-browser-mapping` is v8 in alignment with `browserslist`. For NodeJS versions earlier than v13.2, the [`require('baseline-browser-mapping')`](https://nodejs.org/api/modules.html#requireid) syntax should be used to import the module.
## Keeping `baseline-browser-mapping` up to date
If you are only using this module to generate minimum browser versions for Baseline Widely available or Baseline year feature sets, you don't need to update this module frequently, as the backward looking data is reasonably stable.
However, if you are targeting Newly available, using the [`getAllVersions()`](#get-data-for-all-browser-versions) function or heavily relying on the data for downstream browsers, you should update this module more frequently. If you target a feature cut off date within the last two months and your installed version of `baseline-browser-mapping` has data that is more than 2 months old, you will receive a console warning advising you to update to the latest version when you call `getCompatibleVersions()` or `getAllVersions()`.
If you want to suppress these warnings you can use the `suppressWarnings: true` option in the configuration object passed to `getCompatibleVersions()` or `getAllVersions()`. Alternatively, you can use the `BASELINE_BROWSER_MAPPING_IGNORE_OLD_DATA=true` environment variable when running your build process. This module also respects the `BROWSERSLIST_IGNORE_OLD_DATA=true` environment variable. Environment variables can also be provided in a `.env` file from Node 20 onwards; however, this module does not load .env files automatically to avoid conflicts with other libraries with different requirements. You will need to use `process.loadEnvFile()` or a library like `dotenv` to load .env files before `baseline-browser-mapping` is called.
If you want to ensure [reproducible builds](https://www.wikiwand.com/en/articles/Reproducible_builds), we strongly recommend using the `widelyAvailableOnDate` option to fix the Widely available date on a per build basis to ensure dependent tools provide the same output and you do not produce data staleness warnings. If you are using [`browserslist`](https://github.com/browserslist/browserslist) to target Baseline Widely available, consider automatically updating your `browserslist` configuration in `package.json` or `.browserslistrc` to `baseline widely available on {YYYY-MM-DD}` as part of your build process to ensure the same or sufficiently similar list of minimum browsers is reproduced for historical builds.
## Importing `baseline-browser-mapping`
This module exposes two functions: `getCompatibleVersions()` and `getAllVersions()`, both which can be imported directly from `baseline-browser-mapping`:
```javascript
import {
getCompatibleVersions,
getAllVersions,
} from "baseline-browser-mapping";
```
If you want to load the script and data directly in a web page without hosting it yourself, consider using a CDN:
```html
<script type="module">
import {
getCompatibleVersions,
getAllVersions,
} from "https://cdn.jsdelivr.net/npm/baseline-browser-mapping";
</script>
```
## Get Baseline Widely available browser versions or Baseline year browser versions
To get the current list of minimum browser versions compatible with Baseline Widely available features from the core browser set, call the `getCompatibleVersions()` function:
```javascript
getCompatibleVersions();
```
Executed on 7th March 2025, the above code returns the following browser versions:
```javascript
[
{ browser: "chrome", version: "105", release_date: "2022-09-02" },
{
browser: "chrome_android",
version: "105",
release_date: "2022-09-02",
},
{ browser: "edge", version: "105", release_date: "2022-09-02" },
{ browser: "firefox", version: "104", release_date: "2022-08-23" },
{
browser: "firefox_android",
version: "104",
release_date: "2022-08-23",
},
{ browser: "safari", version: "15.6", release_date: "2022-09-02" },
{
browser: "safari_ios",
version: "15.6",
release_date: "2022-09-02",
},
];
```
> [!NOTE]
> The minimum versions of each browser are not necessarily the final release before the Widely available cutoff date of `TODAY - 30 MONTHS`. Some earlier versions will have supported the full Widely available feature set.
### `getCompatibleVersions()` configuration options
`getCompatibleVersions()` accepts an `Object` as an argument with configuration options. The defaults are as follows:
```javascript
{
targetYear: undefined,
widelyAvailableOnDate: undefined,
includeDownstreamBrowsers: false,
listAllCompatibleVersions: false,
suppressWarnings: false
}
```
#### `targetYear`
The `targetYear` option returns the minimum browser versions compatible with all **Baseline Newly available** features at the end of the specified calendar year. For example, calling:
```javascript
getCompatibleVersions({
targetYear: 2020,
});
```
Returns the following versions:
```javascript
[
{ browser: "chrome", version: "87", release_date: "2020-11-19" },
{
browser: "chrome_android",
version: "87",
release_date: "2020-11-19",
},
{ browser: "edge", version: "87", release_date: "2020-11-19" },
{ browser: "firefox", version: "83", release_date: "2020-11-17" },
{
browser: "firefox_android",
version: "83",
release_date: "2020-11-17",
},
{ browser: "safari", version: "14", release_date: "2020-09-16" },
{ browser: "safari_ios", version: "14", release_date: "2020-09-16" },
];
```
> [!NOTE]
> The minimum version of each browser is not necessarily the final version released in that calendar year. In the above example, Firefox 84 was the final version released in 2020; however Firefox 83 supported all of the features that were interoperable at the end of 2020.
> [!WARNING]
> You cannot use `targetYear` and `widelyAavailableDate` together. Please only use one of these options at a time.
#### `widelyAvailableOnDate`
The `widelyAvailableOnDate` option returns the minimum versions compatible with Baseline Widely available on a specified date in the format `YYYY-MM-DD`:
```javascript
getCompatibleVersions({
widelyAvailableOnDate: `2023-04-05`,
});
```
> [!TIP]
> This option is useful if you provide a versioned library that targets Baseline Widely available on each version's release date and you need to provide a statement on minimum supported browser versions in your documentation.
#### `includeDownstreamBrowsers`
Setting `includeDownstreamBrowsers` to `true` will include browsers outside of the Baseline core browser set where it is possible to map those browsers to an upstream Chromium or Gecko version:
```javascript
getCompatibleVersions({
includeDownstreamBrowsers: true,
});
```
For more information on downstream browsers, see [the section on downstream browsers](#downstream-browsers) below.
#### `includeKaiOS`
KaiOS is an operating system and app framework based on the Gecko engine from Firefox. KaiOS is based on the Gecko engine and feature support can be derived from the upstream Gecko version that each KaiOS version implements. However KaiOS requires other considerations beyond feature compatibility to ensure a good user experience as it runs on device types that do not have either mouse and keyboard or touch screen input in the way that all the other browsers supported by this module do.
```javascript
getCompatibleVersions({
includeDownstreamBrowsers: true,
includeKaiOS: true,
});
```
> [!NOTE]
> Including KaiOS requires you to include all downstream browsers using the `includeDownstreamBrowsers` option.
#### `listAllCompatibleVersions`
Setting `listAllCompatibleVersions` to true will include the minimum versions of each compatible browser, and all the subsequent versions:
```javascript
getCompatibleVersions({
listAllCompatibleVersions: true,
});
```
#### `suppressWarnings`
Setting `suppressWarnings` to `true` will suppress the console warning about old data:
```javascript
getCompatibleVersions({
suppressWarnings: true,
});
```
## Get data for all browser versions
You may want to obtain data on all the browser versions available in this module for use in an analytics solution or dashboard. To get details of each browser version's level of Baseline support, call the `getAllVersions()` function:
```javascript
import { getAllVersions } from "baseline-browser-mapping";
getAllVersions();
```
By default, this function returns an `Array` of `Objects` and excludes downstream browsers:
```javascript
[
...
{
browser: "firefox_android", // Browser name
version: "125", // Browser version
release_date: "2024-04-16", // Release date
year: 2023, // Baseline year feature set the version supports
wa_compatible: true // Whether the browser version supports Widely available
},
...
]
```
For browser versions in `@mdn/browser-compat-data` that were released before Baseline can be defined, i.e. Baseline 2015, the `year` property is always the string: `"pre_baseline"`.
### Understanding which browsers support Newly available features
You may want to understand which recent browser versions support all Newly available features. You can replace the `wa_compatible` property with a `supports` property using the `useSupport` option:
```javascript
getAllVersions({
useSupports: true,
});
```
The `supports` property is optional and has two possible values:
- `widely` for browser versions that support all Widely available features.
- `newly` for browser versions that support all Newly available features.
Browser versions that do not support Widely or Newly available will not include the `support` property in the `array` or `object` outputs, and in the CSV output, the `support` column will contain an empty string. Browser versions that support all Newly available features also support all Widely available features.
### `getAllVersions()` Configuration options
`getAllVersions()` accepts an `Object` as an argument with configuration options. The defaults are as follows:
```javascript
{
includeDownstreamBrowsers: false,
outputFormat: "array",
suppressWarnings: false
}
```
#### `includeDownstreamBrowsers` (in `getAllVersions()` output)
As with `getCompatibleVersions()`, you can set `includeDownstreamBrowsers` to `true` to include the Chromium and Gecko downstream browsers [listed below](#list-of-downstream-browsers).
```javascript
getAllVersions({
includeDownstreamBrowsers: true,
});
```
Downstream browsers include the same properties as core browsers, as well as the `engine`they use and `engine_version`, for example:
```javascript
[
...
{
browser: "samsunginternet_android",
version: "27.0",
release_date: "2024-11-06",
engine: "Blink",
engine_version: "125",
year: 2023,
supports: "widely"
},
...
]
```
#### `includeKaiOS` (in `getAllVersions()` output)
As with `getCompatibleVersions()` you can include KaiOS in your output. The same requirement to have `includeDownstreamBrowsers: true` applies.
```javascript
getAllVersions({
includeDownstreamBrowsers: true,
includeKaiOS: true,
});
```
#### `suppressWarnings` (in `getAllVersions()` output)
As with `getCompatibleVersions()`, you can set `suppressWarnings` to `true` to suppress the console warning about old data:
```javascript
getAllVersions({
suppressWarnings: true,
});
```
#### `outputFormat`
By default, this function returns an `Array` of `Objects` which can be manipulated in Javascript or output to JSON.
To return an `Object` that nests keys , set `outputFormat` to `object`:
```javascript
getAllVersions({
outputFormat: "object",
});
```
In thise case, `getAllVersions()` returns a nested object with the browser [IDs listed below](#list-of-downstream-browsers) as keys, and versions as keys within them:
```javascript
{
"chrome": {
"53": {
"year": 2016,
"release_date": "2016-09-07"
},
...
}
```
Downstream browsers will include extra fields for `engine` and `engine_versions`
```javascript
{
...
"webview_android": {
"53": {
"year": 2016,
"release_date": "2016-09-07",
"engine": "Blink",
"engine_version": "53"
},
...
}
```
To return a `String` in CSV format, set `outputFormat` to `csv`:
```javascript
getAllVersions({
outputFormat: "csv",
});
```
`getAllVersions` returns a `String` with a header row and comma-separated values for each browser version that you can write to a file or pass to another service. Core browsers will have "NULL" as the value for their `engine` and `engine_version`:
```csv
"browser","version","year","supports","release_date","engine","engine_version"
...
"chrome","24","pre_baseline","","2013-01-10","NULL","NULL"
...
"chrome","53","2016","","2016-09-07","NULL","NULL"
...
"firefox","135","2024","widely","2025-02-04","NULL","NULL"
"firefox","136","2024","newly","2025-03-04","NULL","NULL"
...
"ya_android","20.12","2020","year_only","2020-12-20","Blink","87"
...
```
> [!NOTE]
> The above example uses `"includeDownstreamBrowsers": true`
### Static resources
The outputs of `getAllVersions()` are available as JSON or CSV files generated on a daily basis and hosted on GitHub pages:
- Core browsers only
- [Array](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions_array.json)
- [Object](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions_object.json)
- [CSV](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions.csv)
- Core browsers only, with `supports` property
- [Array](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions_array_with_supports.json)
- [Object](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions_object_with_supports.json)
- [CSV](https://web-platform-dx.github.io/baseline-browser-mapping/all_versions_with_supports.csv)
- Including downstream browsers
- [Array](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions_array.json)
- [Object](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions_object.json)
- [CSV](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions.csv)
- Including downstream browsers with `supports` property
- [Array](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions_array_with_supports.json)
- [Object](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions_object_with_supports.json)
- [CSV](https://web-platform-dx.github.io/baseline-browser-mapping/with_downstream/all_versions_with_supports.csv)
These files are updated on a daily basis.
## CLI
`baseline-browser-mapping` includes a command line interface that exposes the same data and options as the `getCompatibleVersions()` function. To learn more about using the CLI, run:
```sh
npx baseline-browser-mapping --help
```
## Downstream browsers
### Limitations
The browser versions in this module come from two different sources:
- MDN's `browser-compat-data` module.
- Parsed user agent strings provided by [useragents.io](https://useragents.io/)
MDN `browser-compat-data` is an authoritative source of information for the browsers it contains. The release dates for the Baseline core browser set and the mapping of downstream browsers to Chromium versions should be considered accurate.
Browser mappings from useragents.io are provided on a best effort basis. They assume that browser vendors are accurately stating the Chromium version they have implemented. The initial set of version mappings was derived from a bulk export in November 2024. This version was iterated over with a Regex match looking for a major Chrome version and a corresponding version of the browser in question, e.g.:
`Mozilla/5.0 (Linux; U; Android 10; en-US; STK-L21 Build/HUAWEISTK-L21) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UCBrowser/13.8.2.1324 Mobile Safari/537.36`
Shows UC Browser Mobile 13.8 implementing Chromium 100, and:
`Mozilla/5.0 (Linux; arm_64; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.123 YaBrowser/24.10.2.123.00 SA/3 Mobile Safari/537.36`
Shows Yandex Browser Mobile 24.10 implementing Chromium 128. The Chromium version from this string is mapped to the corresponding Chrome version from MDN `browser-compat-data`.
> [!NOTE]
> Where possible, approximate release dates have been included based on useragents.io "first seen" data. useragents.io does not have "first seen" dates prior to June 2020. However, these browsers' Baseline compatibility is determined by their Chromium or Gecko version, so their release dates are more informative than critical.
This data is updated on a daily basis using a [script](https://github.com/web-platform-dx/web-features/tree/main/scripts/refresh-downstream.ts) triggered by a GitHub [action](https://github.com/web-platform-dx/web-features/tree/main/.github/workflows/refresh_downstream.yml). Useragents.io provides a private API for this module which exposes the last 7 days of newly seen user agents for the currently tracked browsers. If a new major version of one of the tracked browsers is encountered with a Chromium version that meets or exceeds the previous latest version of that browser, it is added to the [src/data/downstream-browsers.json](src/data/downstream-browsers.json) file with the date it was first seen by useragents.io as its release date.
KaiOS is an exception - its upstream version mappings are handled separately from the other browsers because they happen very infrequently.
### List of downstream browsers
| Browser | ID | Core | Source |
| --------------------- | ------------------------- | ------- | ------------------------- |
| Chrome | `chrome` | `true` | MDN `browser-compat-data` |
| Chrome for Android | `chrome_android` | `true` | MDN `browser-compat-data` |
| Edge | `edge` | `true` | MDN `browser-compat-data` |
| Firefox | `firefox` | `true` | MDN `browser-compat-data` |
| Firefox for Android | `firefox_android` | `true` | MDN `browser-compat-data` |
| Safari | `safari` | `true` | MDN `browser-compat-data` |
| Safari on iOS | `safari_ios` | `true` | MDN `browser-compat-data` |
| Opera | `opera` | `false` | MDN `browser-compat-data` |
| Opera Android | `opera_android` | `false` | MDN `browser-compat-data` |
| Samsung Internet | `samsunginternet_android` | `false` | MDN `browser-compat-data` |
| WebView Android | `webview_android` | `false` | MDN `browser-compat-data` |
| QQ Browser Mobile | `qq_android` | `false` | useragents.io |
| UC Browser Mobile | `uc_android` | `false` | useragents.io |
| Yandex Browser Mobile | `ya_android` | `false` | useragents.io |
| KaiOS | `kai_os` | `false` | Manual |
| Facebook for Android | `facebook_android` | `false` | useragents.io |
| Instagram for Android | `instagram_android` | `false` | useragents.io |
> [!NOTE]
> All the non-core browsers currently included implement Chromium or Gecko. Their inclusion in any of the above methods is based on the Baseline feature set supported by the Chromium or Gecko version they implement, not their release date.
-64
View File
@@ -1,64 +0,0 @@
{
"name": "baseline-browser-mapping",
"main": "./dist/index.cjs",
"version": "2.9.19",
"description": "A library for obtaining browser versions with their maximum supported Baseline feature set and Widely Available status.",
"exports": {
".": {
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./legacy": {
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"jsdelivr": "./dist/index.js",
"files": [
"dist/*",
"!dist/scripts/*",
"LICENSE.txt",
"README.md"
],
"types": "./dist/index.d.ts",
"type": "module",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
},
"scripts": {
"fix-cli-permissions": "output=$(npx baseline-browser-mapping 2>&1); path=$(printf '%s\n' \"$output\" | sed -n 's/^.*: \\(.*\\): Permission denied$/\\1/p; t; s/^\\(.*\\): Permission denied$/\\1/p'); if [ -n \"$path\" ]; then echo \"Permission denied for: $path\"; echo \"Removing $path ...\"; rm -rf \"$path\"; else echo \"$output\"; fi",
"test:format": "npx prettier --check .",
"test:lint": "npx eslint .",
"test:jasmine": "npx jasmine",
"test:jasmine-browser": "npx jasmine-browser-runner runSpecs --config ./spec/support/jasmine-browser.js",
"test": "npm run build && npm run fix-cli-permissions && npm run test:format && npm run test:lint && npm run test:jasmine && npm run test:jasmine-browser",
"build": "rm -rf dist; npx prettier . --write; rollup -c; rm -rf ./dist/scripts/expose-data.d.ts ./dist/cli.d.ts",
"refresh-downstream": "npx tsx scripts/refresh-downstream.ts",
"refresh-static": "npx tsx scripts/refresh-static.ts",
"update-data-file": "npx tsx scripts/update-data-file.ts; npx prettier ./src/data/data.js --write",
"update-data-dependencies": "npm i @mdn/browser-compat-data@latest web-features@latest -D",
"check-data-changes": "git diff --name-only | grep -q '^src/data/data.js$' && echo 'changes-available=TRUE' || echo 'changes-available=FALSE'"
},
"license": "Apache-2.0",
"devDependencies": {
"@mdn/browser-compat-data": "^7.2.5",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.3",
"@types/node": "^22.15.17",
"eslint-plugin-new-with-error": "^5.0.0",
"jasmine": "^5.8.0",
"jasmine-browser-runner": "^3.0.0",
"jasmine-spec-reporter": "^7.0.0",
"prettier": "^3.5.3",
"rollup": "^4.44.0",
"tslib": "^2.8.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.35.0",
"web-features": "^3.14.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/web-platform-dx/baseline-browser-mapping.git"
}
}
+155 -6
View File
@@ -2,7 +2,50 @@
name = "shelfmark"
version = "0.1.0"
description = "Shelfmark - Book Downloader"
requires-python = ">=3.10"
requires-python = ">=3.14"
dependencies = [
"flask",
"flask-cors",
"flask-socketio",
"python-socketio",
"requests[socks]",
"defusedxml",
"beautifulsoup4",
"tqdm",
"dnspython",
"gunicorn",
"gevent",
"gevent-websocket",
"psutil",
"emoji",
"rarfile",
"qbittorrent-api>=2026.8.1",
"transmission-rpc",
"authlib>=1.8.0,<1.9",
"apprise>=1.13.1",
# HTTP/2 client for RFC 8484 DoH: quad9 rejects HTTP/1.1 outright (505), which
# requests cannot speak. See shelfmark/download/doh_wireformat.py.
"httpx[http2]>=0.28.1",
]
[project.optional-dependencies]
browser = [
"pyvirtualdisplay",
"pyautogui",
"seleniumbase==4.54.9",
"python-xlib",
]
[dependency-groups]
dev = [
"basedpyright>=1.40.1",
"prek",
"pytest",
"pytest-cov",
"pytest-xdist>=3.8.0",
"ruff==0.16.8",
"vulture>=2.14",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
@@ -12,6 +55,8 @@ python_functions = ["test_*"]
addopts = [
"-v",
"--tb=short",
"-n",
"auto",
]
markers = [
"integration: marks tests that require running services (deselect with '-m \"not integration\"')",
@@ -19,8 +64,112 @@ markers = [
"e2e: marks end-to-end tests that require the full application stack",
]
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_ignores = true
ignore_missing_imports = true
[tool.ruff]
line-length = 100
extend-exclude = [".local"]
[tool.ruff.lint]
select = [
"F", "I", "UP", "B", "C4", "SIM", "PTH", "RET", "PIE", "FURB", "PERF", "TRY",
"A", "DTZ", "N",
"BLE001",
"ANN001", "ANN002", "ANN003", "ANN201", "ANN202", "ANN204",
"E402",
"ERA001",
"E731",
"S101",
"S110",
"S105", "S108",
"S311", "S324",
"S607", "S608",
"G003", "G004",
"PGH003",
"PLC0414",
"PLR1714",
"PLW1510",
"PLW2901",
"PLW0108",
"PT028",
"PYI034",
"Q000",
"RUF005", "RUF012", "RUF013", "RUF059", "RUF100",
"TC001", "TC002", "TC003",
]
ignore = ["D", "EM", "FBT", "PLR2004", "UP035", "TRY003", "E501", "TD002", "S104", "S603"]
[tool.ruff.lint.per-file-ignores]
"scripts/**/*.py" = [
"BLE001",
"S",
"TRY",
]
"tests/**/*.py" = [
"ANN",
"BLE001",
"B010",
"B017",
"B028",
"DTZ",
"E402",
"E731",
"ERA001",
"FURB",
"G003",
"G004",
"PERF",
"PIE",
"PLC0414",
"PLW0108",
"PLW1510",
"PLW2901",
"PTH",
"PT028",
"PYI034",
"Q000",
"RET",
"RUF012",
"S",
"SIM",
"TC001",
"TC002",
"TC003",
"TRY",
"UP028",
]
[tool.basedpyright]
include = ["shelfmark"]
exclude = [".local", "tests", "**/__pycache__", "**/node_modules"]
pythonVersion = "3.14"
typeCheckingMode = "standard"
[tool.vulture]
paths = ["shelfmark"]
exclude = [".local", "tests"]
ignore_decorators = [
"@app.route",
"@app.before_request",
"@app.after_request",
"@app.errorhandler",
"@socketio.on",
"@register_provider",
"@register_provider_kwargs",
"@register_settings",
"@register_source",
"@register_handler",
"@register_client",
"@register_output",
]
min_confidence = 90
sort_by_size = true
[tool.coverage.run]
source = ["shelfmark"]
branch = true
[tool.coverage.report]
show_missing = true
skip_empty = true
[tool.uv]
package = false
+150 -85
View File
@@ -1,30 +1,29 @@
# 📚 Shelfmark: Book Downloader
Formerly *Calibre Web Automated Book Downloader (CWABD)*
# 📚 Shelfmark: Book Search & Request Tool
<img src="src/frontend/public/logo.png" alt="Shelfmark" width="200">
Shelfmark is a self-hosted web interface for searching and downloading books and audiobooks from multiple sources. Works out of the box with popular web sources, no configuration required. Add metadata providers, additional release sources, and download clients to build a single hub for your digital library. Supports multiple users with a built-in request system, so you can share your instance with others and let them browse and request books on their own.
> [!NOTE]
> Shelfmark is feature stable and maintained on a best-effort basis. Bug fixes, security updates, and small quality-of-life improvements are still shipped, and pull requests are reviewed — including new features. There is no roadmap for new features for now.
**Fully standalone** - no external dependencies required. Works great alongside the following library tools, with support for automatic imports:
Shelfmark is a self-hosted web interface for searching and requesting books and audiobooks across multiple sources. Bring your own sources, metadata providers, and download clients to build a single hub for your digital library. Supports multiple users with a built-in request system, so you can share your instance with others and let them browse and request books on their own.
Works great alongside the following library tools, with support for automatic imports:
- [Calibre](https://calibre-ebook.com/)
- [Calibre-Web](https://github.com/janeczku/calibre-web)
- [Calibre-Web-Automated](https://github.com/crocodilestick/Calibre-Web-Automated)
- [Booklore](https://github.com/booklore-app/booklore)
- [Grimmory](https://github.com/grimmory-tools/grimmory)
- [Audiobookshelf](https://github.com/advplyr/audiobookshelf)
## ✨ Features
- **One-Stop Interface** - A clean, modern UI to search, browse, and download from multiple sources in one place
- **Multiple Sources** - Popular archive websites, Torrent, Usenet, and IRC download support
- **One-Stop Interface** - A clean, modern UI to search, browse, and download from multiple configured sources in one place
- **Multiple Sources** - Configurable web, torrent, usenet, and IRC source support
- **Audiobook Support** - Full audiobook search and download with dedicated processing
- **Two Search Modes**:
- **Direct** - Search popular web sources
- **Universal** - Search metadata providers (Hardcover, Open Library) for richer book and audiobook discovery, with multi-source downloads
- **Flexible Search** - Search metadata providers (Hardcover, Open Library, Google Books) for rich book and audiobook discovery, or query configured sources directly
- **Multi-User & Requests** - Share your instance with others, let users browse and request books, and manage approvals with configurable notifications
- **Authentication** - Built-in login, OIDC single sign-on, proxy auth, and Calibre-Web database support
- **Real-Time Progress** - Unified download queue with live status updates across all sources
- **Cloudflare Bypass** - Built-in bypasser for reliable access to protected sources
- **Network Flexibility** - Configurable proxy support, DNS settings, and optional Cloudflare handling for protected sources
## 🖼️ Screenshots
@@ -45,6 +44,7 @@ Shelfmark is a self-hosted web interface for searching and downloading books and
### Prerequisites
- Docker & Docker Compose
- At least 2 GB of RAM available to the container when using the standard image — see [Memory Requirements](#memory-requirements)
### Installation
@@ -60,7 +60,7 @@ Shelfmark is a self-hosted web interface for searching and downloading books and
3. Open `http://localhost:8084`
That's it! Configure settings through the web interface as needed.
Open the web interface, then configure the sources and settings you want to use.
### Volume Setup
@@ -68,27 +68,56 @@ That's it! Configure settings through the web interface as needed.
volumes:
- /your/config/path:/config # Config, database, and artwork cache directory
- /your/download/path:/books # Downloaded books
- /client/path:/client/path # Optional: For Torrent/Usenet downloads, match your client directory exactly.
- /client/path:/client/path # Optional: For Torrent/Usenet downloads, match your client directory exactly.
```
> **Tip**: Point the download volume to your CWA or Booklore ingest folder for automatic import.
> **Tip**: Point the download volume to your CWA or Grimmory ingest folder for automatic import.
> **Note**: CIFS shares require `nobrl` mount option to avoid database lock errors.
### Non-root container mode
- Start the container as `1000:1000` with Docker `user: "1000:1000"` or `docker run --user 1000:1000`.
- For Kubernetes, set `runAsUser: 1000`, `runAsGroup: 1000`, and `runAsNonRoot: true` together.
- `PUID`/`PGID` keep the default root startup flow.
- Mounted paths must already be writable by `1000:1000`.
- `USING_TOR=true` requires root startup.
## ⚙️ Configuration
### Search Modes
**Direct** (default)
- Works out of the box, no setup required
- Searches a huge library of books directly
- Returns downloadable releases immediately
**Direct**
- Queries configured sources directly
**Universal**
- Cleaner search results via metadata providers (Hardcover is recommended)
**Universal** (recommended)
- Search via metadata providers (Hardcover, Open Library, Google Books) for richer results
- Aggregates releases from multiple configured sources
- Full Audiobook support
- Requires manual setup (API keys, additional sources)
- Full audiobook support
### Hardcover API Key
Hardcover powers metadata search in Universal mode. Create a token at
[hardcover.app/account/api](https://hardcover.app/account/api) — current keys start with `hc_pat_`
and are far shorter than the JWTs Hardcover issued before August 2026.
Tick these seven scopes on the token screen:
| Scope | Used for |
|-------|----------|
| `read:catalog` | Metadata search, plus book, edition, author and series lookups |
| `read:library` | Your reading status and shelf counts |
| `read:lists` | Your lists and the books on them |
| `read:me:content` | Test Connection and the "Connected as" label |
| `read:users` | Usernames shown alongside lists |
| `write:library` | Setting a book's reading status from Shelfmark |
| `write:lists` | Adding and removing books from lists, including auto-remove on download |
The two `write:` scopes matter only if you set reading status from Shelfmark or leave
**Auto-Remove from List on Download** enabled (it is on by default) — without them those actions
fail silently. Everything else Hardcover offers (journal, goals, reviews, prompts, notifications,
account) can stay unticked. The `all` scope works too, but it grants full account access including
deletion, so prefer the list above.
### Environment Variables
@@ -99,20 +128,30 @@ Environment variables work for initial setup and Docker deployments. They serve
| `FLASK_PORT` | Web interface port | `8084` |
| `INGEST_DIR` | Book download directory | `/books` |
| `TZ` | Container timezone | `UTC` |
| `PUID` / `PGID` | Runtime user/group ID (also supports legacy `UID`/`GID`) | `1000` / `1000` |
| `SEARCH_MODE` | `direct` or `universal` | `direct` |
| `USING_TOR` | Enable Tor routing (requires `NET_ADMIN` capability) | `false` |
| `PUID` / `PGID` | Runtime user/group for the default root-startup flow (also supports legacy `UID`/`GID`) | `1000` / `1000` |
| `SEARCH_MODE` | `direct` or `universal` | `universal` |
| `USING_TOR` | Enable Tor routing (requires root startup) | `false` |
| `USING_WIREGUARD` | Enable WireGuard VPN egress with kill-switch (requires root startup) | `false` |
| `WIREGUARD_CONFIG` | Path to the mounted wg-quick config | `/config/wg0.conf` |
| `WIREGUARD_INTERFACE` | WireGuard interface name | `wg0` |
| `LAN_NETWORK` | Comma-separated CIDRs kept off the tunnel so the WebUI / internal clients stay reachable | `127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16` |
| `WIREGUARD_ENFORCE_DNS` | Pin the resolver (via `WIREGUARD_DNS`, else the config's `DNS =`) so DNS can't silently fall back to an off-tunnel path. Designed for a trusted LAN resolver kept reachable via `LAN_NETWORK` (query leaves over the LAN; download still egresses via the tunnel) — it does **not** force queries through the tunnel. Docker's embedded resolver (`127.0.0.11`) is preserved when present so container-name resolution keeps working; pin its upstream via the container's `dns:` list. Fails closed if no resolver is available or `/etc/resolv.conf` is not writable. | `true` |
| `WIREGUARD_DNS` | Explicit resolver(s) to pin (comma/space separated). Use when the VPN's pushed DNS filters domains you need; point at a resolver reachable via the tunnel or an allowed LAN resolver. | _(unset; uses config `DNS =`)_ |
| `WIREGUARD_DISABLE_IPV6` | Strip IPv6 from the tunnel config (many container kernels lack the ip6tables `raw` table wg-quick needs) and remove IPv6 as a leak surface. | `true` |
| `WIREGUARD_ALLOW_IPV6_LEAK` | Escape hatch: continue even when an IPv6 kill-switch can't be installed AND IPv6 can't be disabled. Only set if the container has no IPv6 connectivity. | `false` |
| `WIREGUARD_ALLOW_WEBUI_OFFTUNNEL` | Opt-in off-tunnel WebUI reachability. Default (`false`) keeps the kill-switch strictly fail-closed: the only off-tunnel egress is loopback, the tunnel device and the LAN allowlist. Set `true` only if a **non-LAN** client (e.g. a public reverse proxy on another segment) must reach the WebUI; it permits app-server **replies** (`--sport FLASK_PORT`, conntrack REPLY) off-tunnel — server replies only, never client-initiated egress. LAN clients never need it (covered by `LAN_NETWORK`). | `false` |
| `WIREGUARD_STALE_AFTER` | Seconds since the last handshake before the healthcheck bounces the tunnel. | `180` |
See the full [Environment Variables Reference](docs/environment-variables.md) for all available options.
Some of the additional options available in Settings:
- **Fast Download Key** - Use your paid account to skip Cloudflare challenges entirely and use faster, direct downloads
- **Prowlarr** - Configure indexers and download clients to download books and audiobooks
- **AudiobookBay** - Web scraping source for audiobook torrents (audiobooks only)
- **IRC** - Add details for IRC book sources and download directly from the UI
- **Library Link** - Add a link to your Calibre-Web or Booklore instance in the UI header
- **Additional audiobook sources** - Configure additional sources for audiobook discovery
- **Direct Download mirrors** - Supply your own Anna's Archive mirror URLs; Auto mode tries them in the order listed. The `annas-archive.is` domain does not currently work as a source — use `annas-archive.gl` instead (checked August 2026; mirror availability changes)
- **IRC** - Add details for IRC book sources and download directly from the UI. Most networks serve audiobooks from the same channel as ebooks (on `irc.irchighway.net` that's `#ebooks`, while `#bookz` is effectively inactive), so leave the separate audiobook channel blank unless your network actually indexes one. IRC audiobooks usually arrive as ZIP/RAR archives — keep those enabled under Supported Audiobook Formats or the releases are filtered out of results
- **Library Link** - Add a link to your Calibre-Web or Grimmory instance in the UI header
- **File processing** - Customiseable download paths, file renaming and directory creation with template-based renaming
- **Network Resilience** - Auto DNS rotation and mirror fallback when sources are unreachable. Custom proxy support (SOCK5 + HTTP/S), Tor routing.
- **Network Settings** - Custom proxy support (SOCKS5 + HTTP/S) and configurable DNS
- **Format & Language** - Filter downloads by preferred formats, languages and sorting order
- **Metadata Providers** - Configure API keys for Hardcover, Open Library, etc.
@@ -123,34 +162,64 @@ Some of the additional options available in Settings:
docker compose up -d
```
The full-featured image with built-in Cloudflare bypass.
The full-featured image with all network capabilities included.
#### Enable Tor Routing
Routes all traffic through Tor for enhanced privacy:
#### Memory Requirements
The standard image ships a real Chromium browser, which it launches to solve Cloudflare challenges for Direct Download. Chromium needs room to run:
- **2 GB of RAM available to the container** is a safe minimum; 1 GB or less is where problems usually start
- Only relevant if you use Direct Download. Prowlarr, IRC and audiobook sources don't start the browser
When the container is starved of memory, Chromium fails to start and every Direct Download fails with unrelated-looking errors — repeated `403 detected; switching to bypasser` followed by `No download URL found`, and downloads that never complete. If you're seeing that, check the container's memory limit and the host's free memory before suspecting your ISP or DNS.
If you can't spare the memory, use the [Lite](#lite) image with an external resolver (e.g. FlareSolverr) running elsewhere.
#### Tor Routing
Optional Tor support for network privacy:
```bash
curl -O https://raw.githubusercontent.com/calibrain/shelfmark/main/compose/docker-compose.tor.yml
docker compose -f docker-compose.tor.yml up -d
```
**Notes:**
- Requires root startup
- Requires `NET_ADMIN` and `NET_RAW` capabilities
- Timezone is auto-detected from Tor exit node
- Custom DNS/proxy settings are ignored when Tor is active
### Lite
A smaller image without the built-in Cloudflare bypasser. Ideal for:
#### WireGuard VPN Routing
Optional WireGuard support to route all external egress through a VPN tunnel with a fail-closed kill-switch:
```bash
curl -O https://raw.githubusercontent.com/calibrain/shelfmark/main/compose/docker-compose.wireguard.yml
# place your wg-quick config where the compose mounts /config, as wg0.conf
docker compose -f docker-compose.wireguard.yml up -d
```
- **External bypassers** - Already running FlareSolverr or ByParr for other services
- **Fast downloads** - Using fast download sources
- **Alternative sources only** - Exclusively using Prowlarr, AudiobookBay, IRC, or other sources
- **Audiobooks** - Using Shelfmark exclusively for audiobooks
**Notes:**
- Requires root startup
- Requires `NET_ADMIN` and `NET_RAW` capabilities
- Mount a standard wg-quick config at `WIREGUARD_CONFIG` (default `/config/wg0.conf`)
- All non-LAN egress is forced through the tunnel; if the tunnel drops, external traffic **fails closed** while LAN ranges (WebUI, Prowlarr, qBittorrent) stay reachable
- IPv4 and IPv6 both fail closed. On kernels without a usable `ip6tables`, disable IPv6 for the container (`sysctls: net.ipv6.conf.all.disable_ipv6=1`, as in the compose example) or the container refuses to start rather than risk an IPv6 leak
- A supervised healthcheck bounces the tunnel if the handshake goes stale, and refreshes the endpoint allow rules so a roaming/rotated peer endpoint can reconnect
- Mutually exclusive with `USING_TOR`
- **DNS trust:** `WIREGUARD_DNS` must be a resolver you trust on a trusted network segment. When it is a LAN resolver (kept reachable off-tunnel by `LAN_NETWORK`), the query to that resolver leaves as plaintext UDP/53 on the LAN — the resolver is responsible for encrypting upstream. Two resolver paths exist: (1) when Docker's embedded resolver (`127.0.0.11`) is present it is **preserved** so container names (Prowlarr, qBittorrent) resolve — you MUST pin its upstream to a trusted resolver via the container's compose `dns:` list, since `WIREGUARD_DNS` cannot repoint the embedded resolver from inside the container; (2) otherwise `WIREGUARD_DNS`/the config `DNS =` line is written to `/etc/resolv.conf`. Setting `WIREGUARD_ENFORCE_DNS=false` is a **foot-gun**: with no embedded resolver present the container then uses its inherited resolver, which forwards to the Docker daemon's upstream **off-tunnel**, leaking your DNS. Leave enforcement on unless you have pinned the resolver another way.
### Lite
A lighter image without the built-in browser automation. Ideal for:
- **External services** - Already running FlareSolverr or similar for other applications
- **Alternative sources** - Using Prowlarr, IRC, or other configured sources
- **Audiobooks** - Using Shelfmark primarily for audiobooks
- **Constrained hosts** - No bundled browser, so it runs comfortably below the standard image's [memory requirements](#memory-requirements)
```bash
curl -O https://raw.githubusercontent.com/calibrain/shelfmark/main/compose/docker-compose.lite.yml
docker compose -f docker-compose.lite.yml up -d
```
If you need Cloudflare bypass with the Lite image, configure an external resolver (FlareSolverr/ByParr) in Settings under the Cloudflare tab.
If you need browser-based access with the Lite image, configure an external resolver in Settings.
## 🔐 Authentication
@@ -179,6 +248,29 @@ volumes:
With any authentication method enabled, Shelfmark supports multi-user management with admin/user roles. Users can have per-user settings for download destinations, email recipients, and notification preferences. Non-admin users only see their own downloads and can submit book requests for admin review. Admins can configure request policies per source to control whether users can download directly, must submit a request, or are blocked entirely.
See [API Access](docs/api-access.md) to call the API with a static key from scripts and integrations.
## Project Scope
Shelfmark is a manual search and download tool, the entry point to your book library, not a library manager. It finds books, downloads them, and sends them to a configured destination. That's the full scope.
Shelfmark intentionally does not:
- **Track or manage your library** - it doesn't know or care what you already own
- **Integrate with library software** - what happens after delivery is up to your library tool
- **Monitor authors, series, or new releases** - there is no background automation
- **Queue future downloads** - if a book isn't available now, Shelfmark won't watch for it
These are non-goals, not missing features.
## Contributing
Shelfmark's core feature set is complete.
Pull requests are welcome and all of them get reviewed, new features included. If you want a feature, the fastest path is to send a PR for it rather than to file a request.
Feature requests that fall outside the project scope (library integration, automation, collection management) will be closed, and PRs implementing them won't be merged. If you're unsure whether something fits, open a discussion first.
## Health Monitoring
The application exposes a health endpoint at `/api/health` (no authentication required). Add a health check to your compose:
@@ -197,16 +289,24 @@ Logs are available via:
- `docker logs <container-name>`
- `/var/log/shelfmark/` inside the container (when `ENABLE_LOGGING=true`)
Log level is configurable via Settings or `LOG_LEVEL` environment variable.
Log level is configurable under Settings → Advanced or via the `LOG_LEVEL` environment
variable (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`; case-insensitive, defaults to
`INFO`). The environment variable wins over the setting, and `DEBUG=true` forces `DEBUG`
regardless of either. Changes take effect on restart.
## Development
```bash
# Quality checks
make checks # Run ALL static analysis (frontend + Python)
make python-checks # Run Ruff, BasedPyright, and Vulture
make install-python-dev # Sync Python runtime + dev tools with uv
# Frontend development
make install # Install dependencies
make dev # Start Vite dev server (localhost:5173)
make build # Production build
make typecheck # TypeScript checks
make frontend-typecheck # TypeScript checks
# Backend (Docker)
make up # Start backend via docker-compose.dev.yml
@@ -217,55 +317,20 @@ make restart # Restart container
The frontend dev server proxies to the backend on port 8084.
### Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Web Interface │
│ (React + TypeScript + Vite) │
├─────────────────────────────────────────────────────────────┤
│ Flask Backend │
│ (REST API + WebSocket) │
├───────────────────┬─────────────────────┬───────────────────┤
│ Metadata Providers│ Download Queue │ Cloudflare │
│ │ & Orchestrator │ Bypass │
├───────────────────┼─────────────────────┼───────────────────┤
│ • Hardcover │ • Task scheduling │ • Internal │
│ • Open Library │ • Progress tracking │ • External │
│ │ • Retry logic │ (FlareSolverr) │
├───────────────────┴─────────────────────┴───────────────────┤
│ Release Sources │
├─────────────────────────────────────────────────────────────┤
│ • Direct Download (Web Sources → Mirrors → Fallbacks) │
├─────────────────────────────────────────────────────────────┤
│ Network Layer │
├─────────────────────────────────────────────────────────────┤
│ • Auto DNS rotation • Mirror failover • Resume support │
└─────────────────────────────────────────────────────────────┘
```
The backend uses a plugin architecture. Metadata providers and release sources register via decorators and are automatically discovered.
## Contributing
Shelfmark's core feature set is now largely complete. Development going forward will focus on stability, bug fixes, and maintenance rather than major new features. Contributions in these areas are welcome - please file issues or submit pull requests on GitHub.
## License
MIT License - see [LICENSE](LICENSE) for details.
## ⚠️ Disclaimers
## ⚠️ Disclaimer
### Copyright Notice
Shelfmark is a search interface that displays results from external metadata providers and sources. It does not host, store, or distribute any content. The developers are not responsible for how the tool is used or what is accessed through it.
This tool can access various sources including those that might contain copyrighted material. Users are responsible for:
- Ensuring they have the right to download requested materials
- Respecting copyright laws and intellectual property rights
- Using the tool in compliance with their local regulations
Users are solely responsible for:
- Ensuring they have the legal right to download any material they access
- Complying with copyright laws and intellectual property rights in their jurisdiction
- Understanding and accepting the terms of any sources they configure
### Library Integration
Downloads are written atomically (via intermediate `.crdownload` files) to prevent partial files from being ingested. However, if your library tool (CWA, Booklore, Calibre) is actively scanning or importing, there's a small chance of race conditions. If you experience database errors or import failures, try pausing your library's auto-import during bulk downloads.
Use of this tool is entirely at your own risk.
## Support
-18
View File
@@ -1,18 +0,0 @@
flask>=3.1.0,<3.1.3 # Temporary: Flask 3.1.3 breaks flask-socketio (github.com/miguelgrinberg/Flask-SocketIO/pull/2153)
flask-cors
flask-socketio
python-socketio
requests[socks]
beautifulsoup4
tqdm
dnspython
gunicorn
gevent
gevent-websocket
psutil
emoji
rarfile
qbittorrent-api
transmission-rpc
authlib>=1.6.6,<1.7
apprise>=1.9.0
-4
View File
@@ -1,4 +0,0 @@
pyvirtualdisplay
pyautogui
seleniumbase==4.45.10
python-xlib
+246
View File
@@ -0,0 +1,246 @@
#!/usr/bin/env bash
set -euo pipefail
LATEST_IMAGE="${LATEST_IMAGE:-ghcr.io/calibrain/shelfmark:latest}"
LEGACY_IMAGE="${LEGACY_IMAGE:-ghcr.io/calibrain/shelfmark:v1.0.2}"
WAIT_SECONDS="${WAIT_SECONDS:-5}"
STARTUP_TIMEOUT_SECONDS="${STARTUP_TIMEOUT_SECONDS:-120}"
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing required command: $1" >&2
exit 1
}
}
cleanup() {
local name="$1"
docker rm -f "$name" >/dev/null 2>&1 || true
}
wait_for_startup() {
local name="$1"
local elapsed=0
while [ "$elapsed" -lt "$STARTUP_TIMEOUT_SECONDS" ]; do
if ! docker inspect "$name" >/dev/null 2>&1; then
echo "Container $name no longer exists" >&2
return 1
fi
if [ "$(docker inspect -f '{{.State.Status}}' "$name" 2>/dev/null)" != "running" ]; then
echo "Container $name exited before startup completed" >&2
docker logs --tail 120 "$name" 2>&1 || true
return 1
fi
if docker exec "$name" sh -lc "getent passwd 1000 >/dev/null 2>&1 && ps -eo comm,args | awk '\$1 == \"gunicorn\" && index(\$0, \"shelfmark.main:app\") { found=1 } END { exit(found ? 0 : 1) }'" >/dev/null 2>&1; then
return 0
fi
sleep 1
elapsed=$((elapsed + 1))
done
echo "Timed out waiting for $name to finish startup" >&2
docker logs --tail 120 "$name" 2>&1 || true
return 1
}
start_container() {
local name="$1"
local image="$2"
local pre_entrypoint_script="${3:-}"
cleanup "$name"
if [ -n "$pre_entrypoint_script" ]; then
docker run -d \
--name "$name" \
--entrypoint sh \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=UTC \
"$image" \
-lc "$pre_entrypoint_script
exec /app/entrypoint.sh" >/dev/null
else
docker run -d \
--name "$name" \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=UTC \
"$image" >/dev/null
sleep "$WAIT_SECONDS"
fi
wait_for_startup "$name"
}
run_probe() {
local name="$1"
local mode="${2:-default}"
docker exec -u 1000:1000 -e PROBE_MODE="$mode" "$name" sh -lc 'python3 - <<'"'"'PY'"'"'
import asyncio
import os
import shelfmark.bypass.internal_bypasser as ib
async def run_probe():
driver = None
probe_mode = os.environ.get("PROBE_MODE", "default")
if probe_mode == "proxy_auth" and hasattr(ib, "_get_proxy_string"):
ib._get_proxy_string = lambda _url: "user:pass@127.0.0.1:8888"
if hasattr(ib, "_create_cdp_browser"):
try:
driver = await ib._create_cdp_browser("https://example.com")
profile = getattr(getattr(driver, "config", None), "user_data_dir", "")
print(f"PROBE=OK mode={probe_mode} fn=_create_cdp_browser profile={profile}")
except Exception as e:
print(f"PROBE=ERR mode={probe_mode} fn=_create_cdp_browser type={type(e).__name__} msg={e}")
finally:
if driver and hasattr(ib, "_close_cdp_driver"):
await ib._close_cdp_driver(driver)
return
if hasattr(ib, "_create_driver"):
try:
driver = await ib._create_driver()
print(f"PROBE=OK mode={probe_mode} fn=_create_driver driver_type={type(driver).__name__}")
except Exception as e:
print(f"PROBE=ERR mode={probe_mode} fn=_create_driver type={type(e).__name__} msg={e}")
finally:
if driver and hasattr(ib, "_quit_driver"):
await ib._quit_driver(driver)
return
print(f"PROBE=ERR mode={probe_mode} fn=unknown type=RuntimeError msg=no supported startup function found")
asyncio.run(run_probe())
PY'
}
show_logs() {
local name="$1"
docker logs --tail 80 "$name" 2>&1 | tail -n 20
}
scenario_latest_baseline() {
local name="sb-lab-latest-baseline"
echo
echo "== latest baseline =="
start_container "$name" "$LATEST_IMAGE"
run_probe "$name"
cleanup "$name"
}
scenario_latest_drivers_readonly() {
local name="sb-lab-latest-drivers"
echo
echo "== latest drivers readonly =="
start_container "$name" "$LATEST_IMAGE" '
chown -R root:root /usr/local/lib/python3.10/site-packages/seleniumbase/drivers &&
chmod -R a-w /usr/local/lib/python3.10/site-packages/seleniumbase/drivers &&
ls -ld /usr/local/lib/python3.10/site-packages/seleniumbase/drivers
'
run_probe "$name"
cleanup "$name"
}
scenario_latest_proxy_auth_baseline() {
local name="sb-lab-latest-proxy-baseline"
echo
echo "== latest proxy auth baseline =="
start_container "$name" "$LATEST_IMAGE"
run_probe "$name" "proxy_auth"
cleanup "$name"
}
scenario_latest_downloads_readonly() {
local name="sb-lab-latest-downloads"
echo
echo "== latest downloaded_files readonly =="
start_container "$name" "$LATEST_IMAGE" '
mkdir -p /app/downloaded_files &&
touch /app/downloaded_files/pipfinding.lock /app/downloaded_files/proxy_dir.lock &&
chown -R root:root /app/downloaded_files &&
chmod -R a-w /app/downloaded_files &&
find /app/downloaded_files -maxdepth 2 -printf "%M %u:%g %p\n"
'
run_probe "$name"
show_logs "$name"
cleanup "$name"
}
scenario_latest_proxy_auth_downloads_readonly() {
local name="sb-lab-latest-proxy-downloads"
echo
echo "== latest proxy auth with readonly downloaded_files =="
start_container "$name" "$LATEST_IMAGE" '
mkdir -p /app/downloaded_files &&
touch /app/downloaded_files/pipfinding.lock /app/downloaded_files/proxy_dir.lock &&
chown 1000:1000 /app/downloaded_files/pipfinding.lock /app/downloaded_files/proxy_dir.lock &&
chmod 0666 /app/downloaded_files/pipfinding.lock /app/downloaded_files/proxy_dir.lock &&
chown root:root /app/downloaded_files &&
chmod 0555 /app/downloaded_files &&
ls -ld /app/downloaded_files &&
ls -la /app/downloaded_files
'
run_probe "$name" "proxy_auth"
show_logs "$name"
cleanup "$name"
}
scenario_latest_bind_mount_readonly() {
local name="sb-lab-latest-bind-ro"
local bind_dir
bind_dir="$(mktemp -d /tmp/sb-lab-bind.XXXXXX)"
echo
echo "== latest readonly bind mount for downloaded_files =="
chmod 0555 "$bind_dir"
cleanup "$name"
docker run -d \
--name "$name" \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=UTC \
--mount "type=bind,src=${bind_dir},target=/app/downloaded_files,readonly" \
"$LATEST_IMAGE" >/dev/null
wait_for_startup "$name"
run_probe "$name"
show_logs "$name"
cleanup "$name"
rm -rf "$bind_dir"
}
scenario_legacy_drivers_readonly() {
local name="sb-lab-legacy-drivers"
echo
echo "== legacy drivers readonly =="
start_container "$name" "$LEGACY_IMAGE" '
chown -R root:root /usr/local/lib/python3.10/site-packages/seleniumbase/drivers &&
chmod -R a-w /usr/local/lib/python3.10/site-packages/seleniumbase/drivers &&
ls -ld /usr/local/lib/python3.10/site-packages/seleniumbase/drivers
'
run_probe "$name"
show_logs "$name"
cleanup "$name"
}
main() {
require_cmd docker
scenario_latest_baseline
scenario_latest_drivers_readonly
scenario_latest_proxy_auth_baseline
scenario_latest_downloads_readonly
scenario_latest_proxy_auth_downloads_readonly
scenario_latest_bind_mount_readonly
scenario_legacy_drivers_readonly
}
main "$@"
-92
View File
@@ -1,92 +0,0 @@
#!/usr/bin/env python3
"""Fix permissions on all configured directories.
This script is called by the entrypoint to ensure all user-configured
directories have correct ownership. It reads directory paths from:
- CONFIG_DIR environment variable
- Config files in CONFIG_DIR/plugins/
Outputs directory paths that need permission fixing (one per line).
The entrypoint handles the actual chown operations.
"""
import json
import os
import sys
from pathlib import Path
def get_directories_from_config() -> set[str]:
"""Extract all directory paths from config files."""
directories = set()
config_dir = Path(os.getenv("CONFIG_DIR", "/config"))
plugins_dir = config_dir / "plugins"
if not plugins_dir.exists():
return directories
# Keys that contain directory paths
directory_keys = {
# Main destinations
"DESTINATION",
"DESTINATION_AUDIOBOOK",
# Content type routing directories
"AA_CONTENT_TYPE_DIR_FICTION",
"AA_CONTENT_TYPE_DIR_NON_FICTION",
"AA_CONTENT_TYPE_DIR_UNKNOWN",
"AA_CONTENT_TYPE_DIR_MAGAZINE",
"AA_CONTENT_TYPE_DIR_COMIC",
"AA_CONTENT_TYPE_DIR_STANDARDS",
"AA_CONTENT_TYPE_DIR_MUSICAL_SCORE",
"AA_CONTENT_TYPE_DIR_OTHER",
# Legacy keys (in case of old configs)
"INGEST_DIR",
"INGEST_DIR_AUDIOBOOK",
"INGEST_DIR_BOOK_FICTION",
"INGEST_DIR_BOOK_NON_FICTION",
"INGEST_DIR_BOOK_UNKNOWN",
"INGEST_DIR_MAGAZINE",
"INGEST_DIR_COMIC_BOOK",
"INGEST_DIR_STANDARDS_DOCUMENT",
"INGEST_DIR_MUSICAL_SCORE",
"INGEST_DIR_OTHER",
"LIBRARY_PATH",
"LIBRARY_PATH_AUDIOBOOK",
}
# Read all JSON config files
for config_file in plugins_dir.glob("*.json"):
try:
with open(config_file, "r") as f:
config = json.load(f)
for key in directory_keys:
if key in config:
value = config[key]
if value and isinstance(value, str) and value.startswith("/"):
directories.add(value)
except (json.JSONDecodeError, OSError):
continue
return directories
def main():
"""Output all configured directories that exist."""
directories = get_directories_from_config()
# Filter to directories that actually exist
existing = []
for dir_path in directories:
path = Path(dir_path)
if path.exists() and path.is_dir():
existing.append(dir_path)
# Output one directory per line
for dir_path in sorted(existing):
print(dir_path)
if __name__ == "__main__":
main()
+175 -48
View File
@@ -17,16 +17,15 @@ The generated documentation includes:
import argparse
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Any
# Add project root to path
project_root = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(project_root))
def get_field_type_name(field) -> str:
def get_field_type_name(field: Any) -> str:
"""Get a human-readable type name for a field."""
from shelfmark.core.settings_registry import (
CheckboxField,
@@ -35,54 +34,55 @@ def get_field_type_name(field) -> str:
OrderableListField,
PasswordField,
SelectField,
TagListField,
TextField,
)
if isinstance(field, CheckboxField):
return "boolean"
elif isinstance(field, NumberField):
if isinstance(field, NumberField):
return "number"
elif isinstance(field, SelectField):
if isinstance(field, SelectField):
return "string (choice)"
elif isinstance(field, MultiSelectField):
if isinstance(field, MultiSelectField):
return "string (comma-separated)"
elif isinstance(field, OrderableListField):
if isinstance(field, TagListField):
return "string (comma-separated)"
if isinstance(field, OrderableListField):
return "JSON array"
elif isinstance(field, PasswordField):
if isinstance(field, PasswordField):
return "string (secret)"
elif isinstance(field, TextField):
return "string"
else:
if isinstance(field, TextField):
return "string"
return "string"
def format_default_value(field) -> str:
def format_default_value(field: Any) -> str:
"""Format the default value for display."""
default = field.default
if default is None:
return "_none_"
elif isinstance(default, bool):
if isinstance(default, bool):
return f"`{str(default).lower()}`"
elif isinstance(default, (int, float)):
if isinstance(default, (int, float)):
return f"`{default}`"
elif isinstance(default, str):
if isinstance(default, str):
if default == "":
return "_empty string_"
return f"`{default}`"
elif isinstance(default, list):
if isinstance(default, list):
if not default:
return "_empty list_"
# For simple lists, show comma-separated values
if all(isinstance(item, str) for item in default):
return f"`{','.join(default)}`"
# For complex lists (e.g., OrderableListField defaults), summarize
return f"_see UI for defaults_"
else:
return f"`{default}`"
return "_see UI for defaults_"
return f"`{default}`"
def get_select_options(field) -> Optional[List[str]]:
def get_select_options(field: Any) -> list[str] | None:
"""Get the available options for a SelectField.
Returns options formatted as 'value (label)' or just 'value' if they match,
@@ -119,7 +119,7 @@ def get_select_options(field) -> Optional[List[str]]:
return result
def _generate_bootstrap_env_docs() -> List[str]:
def _generate_bootstrap_env_docs() -> list[str]:
"""Generate documentation for bootstrap environment variables from env.py."""
# These are environment variables defined in env.py that are used before
# the settings registry is available
@@ -172,6 +172,30 @@ def _generate_bootstrap_env_docs() -> List[str]:
"type": "string (path)",
"default": "/auth/app.db",
},
{
"name": "HIDE_LOCAL_AUTH",
"description": "Hide the username/password login form when OIDC is active.",
"type": "boolean",
"default": "false",
},
{
"name": "DISABLE_LOCAL_AUTH",
"description": "Disable username/password login and remove the local-admin prerequisite for OIDC. Implies HIDE_LOCAL_AUTH; with AUTH_METHOD=builtin, everyone is locked out until auth env vars are changed.",
"type": "boolean",
"default": "false",
},
{
"name": "SHELFMARK_API_KEY",
"description": "Optional static API key. When set, requests carrying it as 'Authorization: Bearer <key>' (or X-Api-Key) are authenticated as an admin; browser sessions keep working. Unset = off.",
"type": "string",
"default": "unset",
},
{
"name": "OIDC_AUTO_REDIRECT",
"description": "Automatically redirect to the OIDC provider instead of showing the login page.",
"type": "boolean",
"default": "false",
},
{
"name": "DOCKERMODE",
"description": "Indicates the application is running inside a Docker container.",
@@ -189,14 +213,16 @@ def _generate_bootstrap_env_docs() -> List[str]:
lines = [
"## Bootstrap Configuration",
"",
"These environment variables are used at startup before the settings system loads. They typically configure paths and server settings.",
"These environment variables are used at startup before the settings system loads. They typically configure paths, server settings, and authentication startup behavior.",
"",
"| Variable | Description | Type | Default |",
"|----------|-------------|------|---------|",
]
for var in bootstrap_vars:
lines.append(f"| `{var['name']}` | {var['description']} | {var['type']} | `{var['default']}` |")
lines.extend(
f"| `{var['name']}` | {var['description']} | {var['type']} | `{var['default']}` |"
for var in bootstrap_vars
)
lines.append("")
lines.append("<details>")
@@ -218,19 +244,124 @@ def _generate_bootstrap_env_docs() -> List[str]:
return lines
def _generate_egress_env_docs() -> list[str]:
"""Generate documentation for VPN/Tor egress environment variables.
These are startup-only variables consumed by entrypoint.sh / wireguard.sh
(before and outside the settings registry) to select and configure the
transparent-egress kill-switch. `USING_TOR` has a registry-backed entry
under Network and is cross-referenced rather than repeated here so the two
mutually exclusive egress modes are discoverable side by side without
emitting a duplicate `#### USING_TOR` anchor.
"""
egress_vars = [
{
"name": "USING_WIREGUARD",
"description": "Route all traffic through a WireGuard VPN tunnel with a fail-closed iptables kill-switch (non-tunnel egress is dropped). Requires root startup and NET_ADMIN (plus NET_RAW). Mutually exclusive with USING_TOR.",
"type": "boolean",
"default": "false",
},
{
"name": "WIREGUARD_CONFIG",
"description": "Path to the mounted wg-quick configuration file.",
"type": "string (path)",
"default": "/config/wg0.conf",
},
{
"name": "WIREGUARD_INTERFACE",
"description": "WireGuard interface name brought up by wg-quick.",
"type": "string",
"default": "wg0",
},
{
"name": "LAN_NETWORK",
"description": "Comma-separated CIDRs kept off the tunnel so the WebUI and internal download clients (Prowlarr, qBittorrent) stay reachable.",
"type": "string (comma-separated)",
"default": "127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16",
},
{
"name": "WIREGUARD_ENFORCE_DNS",
"description": "Pin the container's resolver so DNS cannot silently fall back to an off-tunnel path. The resolver used is WIREGUARD_DNS if set, else the tunnel config's DNS = line. This does NOT force queries through the tunnel: it is designed for a trusted LAN resolver kept reachable off-tunnel via LAN_NETWORK (the query leaves over the LAN; the resolver encrypts upstream while the download still egresses via the tunnel). Special case: when Docker's embedded resolver (nameserver 127.0.0.11) is present, it is PRESERVED so container-name resolution (e.g. prowlarr, qbittorrent) keeps working, and the embedded resolver's upstream must be pinned via the container's compose dns: list. Fails closed (refuses to start) only when no embedded resolver is present AND no resolver is defined, or /etc/resolv.conf is not writable.",
"type": "boolean",
"default": "true",
},
{
"name": "WIREGUARD_DNS",
"description": "Explicit resolver(s) (comma/space separated) to pin when WIREGUARD_ENFORCE_DNS is true and Docker's embedded resolver is NOT in use. Use when the VPN's pushed DNS filters domains you need; point it at a resolver reachable via the tunnel or an allowed LAN resolver. NOTE: when the embedded resolver (127.0.0.11) is present it is preserved and this value cannot repoint its upstream from inside the container — set the container's compose dns: list to the trusted resolver instead.",
"type": "string (comma-separated)",
"default": "unset (uses config DNS = line)",
},
{
"name": "WIREGUARD_DISABLE_IPV6",
"description": "Strip IPv6 Address/AllowedIPs/DNS from the tunnel config before wg-quick (many container kernels lack the ip6tables raw table wg-quick needs) and remove IPv6 as a leak surface.",
"type": "boolean",
"default": "true",
},
{
"name": "WIREGUARD_ALLOW_IPV6_LEAK",
"description": "Escape hatch: continue startup even when an IPv6 kill-switch cannot be installed AND IPv6 cannot be disabled. Only set when the container has no IPv6 connectivity, as IPv6 egress may otherwise bypass the tunnel.",
"type": "boolean",
"default": "false",
},
{
"name": "WIREGUARD_ALLOW_WEBUI_OFFTUNNEL",
"description": "When false (default) the kill-switch is strictly fail-closed: the only off-tunnel egress permitted is loopback, the tunnel device and the LAN allowlist. Set true only if a NON-LAN client (e.g. a public reverse proxy on a different segment) must reach the WebUI; it permits app-server REPLY packets (--sport FLASK_PORT, conntrack REPLY) to leave off-tunnel. Server replies only, never client-initiated egress, so it cannot leak outbound browsing/downloads or the real IP for outbound requests, but it is still an off-tunnel path while the tunnel is down, hence opt-in. LAN WebUI clients never need it (covered by LAN_NETWORK).",
"type": "boolean",
"default": "false",
},
{
"name": "WIREGUARD_STALE_AFTER",
"description": "Seconds since the last WireGuard handshake before the healthcheck bounces the tunnel.",
"type": "number",
"default": "180",
},
]
lines = [
"## Egress / VPN Routing",
"",
"These startup-only variables are consumed by `entrypoint.sh` / `wireguard.sh` to select and configure the WireGuard transparent-egress kill-switch. `USING_WIREGUARD` and [`USING_TOR`](#using_tor) (documented under Network) are mutually exclusive; both require root startup.",
"",
"| Variable | Description | Type | Default |",
"|----------|-------------|------|---------|",
]
lines.extend(
f"| `{var['name']}` | {var['description']} | {var['type']} | `{var['default']}` |"
for var in egress_vars
)
lines.append("")
lines.append("<details>")
lines.append("<summary>Detailed descriptions</summary>")
lines.append("")
for var in egress_vars:
lines.append(f"#### `{var['name']}`")
lines.append("")
lines.append(var["description"])
lines.append("")
lines.append(f"- **Type:** {var['type']}")
lines.append(f"- **Default:** `{var['default']}`")
lines.append("")
lines.append("</details>")
lines.append("")
return lines
def generate_env_docs() -> str:
"""Generate markdown documentation for all environment variables."""
# Import settings modules to ensure all settings are registered
import shelfmark.config.settings # noqa: F401
import shelfmark.release_sources.irc.settings # noqa: F401
import shelfmark.config.security
import shelfmark.config.settings
import shelfmark.metadata_providers.googlebooks
import shelfmark.metadata_providers.hardcover
import shelfmark.metadata_providers.openlibrary
import shelfmark.release_sources.irc.settings
import shelfmark.release_sources.prowlarr.settings # noqa: F401
import shelfmark.metadata_providers.hardcover # noqa: F401
import shelfmark.metadata_providers.openlibrary # noqa: F401
import shelfmark.metadata_providers.googlebooks # noqa: F401
from shelfmark.core.settings_registry import (
ActionButton,
HeadingField,
get_all_groups,
get_all_settings_tabs,
)
@@ -239,7 +370,7 @@ def generate_env_docs() -> str:
groups = {g.name: g for g in get_all_groups()}
# Organize tabs by group
grouped_tabs: Dict[Optional[str], List] = {None: []}
grouped_tabs: dict[str | None, list] = {None: []}
for group_name in groups:
grouped_tabs[group_name] = []
@@ -264,6 +395,7 @@ def generate_env_docs() -> str:
# Generate TOC
toc_entries = [
"- [Bootstrap Configuration](#bootstrap-configuration)",
"- [Egress / VPN Routing](#egress--vpn-routing)",
]
# Ungrouped tabs first
@@ -289,6 +421,9 @@ def generate_env_docs() -> str:
# Add bootstrap environment variables documentation
lines.extend(_generate_bootstrap_env_docs())
# Add egress / VPN routing (startup-only, shell-driven) documentation
lines.extend(_generate_egress_env_docs())
# Generate documentation for ungrouped tabs
for tab in grouped_tabs.get(None, []):
lines.extend(_generate_tab_docs(tab))
@@ -308,33 +443,24 @@ def generate_env_docs() -> str:
return "\n".join(lines)
def _generate_tab_docs(tab, group_prefix: Optional[str] = None) -> List[str]:
def _generate_tab_docs(tab: Any, group_prefix: str | None = None) -> list[str]:
"""Generate documentation for a single settings tab."""
from shelfmark.core.settings_registry import ActionButton, HeadingField
from shelfmark.core.settings_registry import iter_value_fields
lines = []
# Section header
if group_prefix:
lines.append(f"### {group_prefix}: {tab.display_name}")
anchor_id = f"{group_prefix}-{tab.display_name}".lower().replace(" ", "-")
else:
lines.append(f"## {tab.display_name}")
lines.append("")
# Collect env-supported fields
env_fields = []
for field in tab.fields:
# Skip non-value fields
if isinstance(field, (ActionButton, HeadingField)):
continue
# Skip fields that don't support ENV vars
if not getattr(field, "env_supported", True):
continue
env_fields.append(field)
env_fields = [
field for field in iter_value_fields(tab) if getattr(field, "env_supported", True)
]
if not env_fields:
lines.append("_No environment variables for this section._")
@@ -390,6 +516,7 @@ def _generate_tab_docs(tab, group_prefix: Optional[str] = None) -> List[str]:
# Show constraints for NumberField
from shelfmark.core.settings_registry import NumberField
if isinstance(field, NumberField):
constraints = []
if field.min_value is not None:
@@ -407,7 +534,7 @@ def _generate_tab_docs(tab, group_prefix: Optional[str] = None) -> List[str]:
return lines
def main():
def main() -> None:
parser = argparse.ArgumentParser(
description="Generate markdown documentation for environment variables"
)
+38 -27
View File
@@ -9,7 +9,7 @@ Usage:
2. Wait for containers to initialize (first run takes ~30s)
3. Run this script to verify clients are accessible:
python scripts/test_clients.py
uv run python scripts/test_clients.py
4. Access cwabd at http://localhost:8084
- Go to Settings > Prowlarr > Download Clients
@@ -26,7 +26,7 @@ Web UIs:
- rTorrent: http://localhost:8000 (web ui http://localhost:8089 via ruTorrent)
Prerequisites (for running this script locally):
pip install requests transmission-rpc qbittorrent-api
uv sync --locked
First-Time Setup:
qBittorrent:
@@ -51,7 +51,8 @@ First-Time Setup:
import sys
import time
from xmlrpc import client
from pathlib import Path
from typing import Any
# Test configuration - matches docker-compose.test-clients.yml
CONFIG = {
@@ -89,7 +90,7 @@ CONFIG = {
TEST_MAGNET = "magnet:?xt=urn:btih:3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0&dn=ubuntu-22.04.3-live-server-amd64.iso"
def test_nzbget():
def test_nzbget() -> bool:
"""Test NZBGet connection."""
import requests
@@ -138,7 +139,7 @@ def test_nzbget():
return False
def test_sabnzbd():
def test_sabnzbd() -> bool:
"""Test SABnzbd connection."""
import requests
@@ -152,10 +153,9 @@ def test_sabnzbd():
# Try to get API key from config if not set
if not api_key:
try:
import os
ini_path = ".local/test-clients/sabnzbd/config/sabnzbd.ini"
if os.path.exists(ini_path):
with open(ini_path) as f:
ini_path = Path(".local/test-clients/sabnzbd/config/sabnzbd.ini")
if ini_path.exists():
with ini_path.open() as f:
for line in f:
if line.startswith("api_key"):
api_key = line.split("=")[1].strip()
@@ -204,7 +204,7 @@ def test_sabnzbd():
return False
def test_qbittorrent():
def test_qbittorrent() -> bool:
"""Test qBittorrent connection."""
print("\n" + "=" * 50)
print("Testing qBittorrent")
@@ -219,6 +219,7 @@ def test_qbittorrent():
# Parse URL for host/port
from urllib.parse import urlparse
parsed = urlparse(url)
client = qbittorrentapi.Client(
@@ -260,7 +261,7 @@ def test_qbittorrent():
except ImportError:
print(" ERROR: qbittorrent-api not installed")
print(" Run: pip install qbittorrent-api")
print(" Run: uv sync --locked")
return False
except Exception as e:
print(f" ERROR: {e}")
@@ -271,16 +272,17 @@ def test_qbittorrent():
return False
def test_transmission():
def test_transmission() -> bool:
"""Test Transmission connection."""
print("\n" + "=" * 50)
print("Testing Transmission")
print("=" * 50)
try:
from transmission_rpc import Client
from urllib.parse import urlparse
from transmission_rpc import Client
url = CONFIG["transmission"]["url"]
parsed = urlparse(url)
@@ -317,14 +319,14 @@ def test_transmission():
except ImportError:
print(" ERROR: transmission-rpc not installed")
print(" Run: pip install transmission-rpc")
print(" Run: uv sync --locked")
return False
except Exception as e:
print(f" ERROR: {e}")
return False
def test_deluge():
def test_deluge() -> bool:
"""Test Deluge Web UI (JSON-RPC) connection."""
import requests
@@ -336,7 +338,7 @@ def test_deluge():
password = CONFIG["deluge"]["password"]
rpc_url = f"{base_url}/json"
def rpc_call(session: requests.Session, rpc_id: int, method: str, *params):
def rpc_call(session: requests.Session, rpc_id: int, method: str, *params: Any) -> Any:
payload = {"id": rpc_id, "method": method, "params": list(params)}
resp = session.post(rpc_url, json=payload, timeout=10)
resp.raise_for_status()
@@ -366,7 +368,11 @@ def test_deluge():
host_id = hosts[0][0]
for entry in hosts:
if isinstance(entry, list) and len(entry) >= 2 and entry[1] in {"127.0.0.1", "localhost"}:
if (
isinstance(entry, list)
and len(entry) >= 2
and entry[1] in {"127.0.0.1", "localhost"}
):
host_id = entry[0]
break
@@ -386,13 +392,18 @@ def test_deluge():
# Test adding a torrent (then remove it)
print(" Testing add/remove torrent...")
torrent_id = rpc_call(session, 8, "core.add_torrent_magnet", TEST_MAGNET, {"add_paused": True})
torrent_id = rpc_call(
session, 8, "core.add_torrent_magnet", TEST_MAGNET, {"add_paused": True}
)
if torrent_id:
torrent_id = str(torrent_id)
print(f" Added test torrent: {torrent_id[:20]}...")
status = rpc_call(session, 9, "core.get_torrent_status", torrent_id, ["state", "progress"]) or {}
status = (
rpc_call(session, 9, "core.get_torrent_status", torrent_id, ["state", "progress"])
or {}
)
state = status.get("state", "unknown") if isinstance(status, dict) else "unknown"
progress = status.get("progress", 0) if isinstance(status, dict) else 0
print(f" Status: {state} ({progress:.1f}%)")
@@ -418,7 +429,8 @@ def test_deluge():
print(" Check Deluge Web UI password (default: deluge)")
return False
def test_rtorrent():
def test_rtorrent() -> bool:
"""Test rTorrent connection."""
print("\n" + "=" * 50)
print("Testing rTorrent")
@@ -457,19 +469,18 @@ def test_rtorrent():
# rtorrent is weird in that it doesn't return the torrent ID/hash on add
client.load.start("", TEST_MAGNET, ";".join(commands))
# but we know that it is 3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0 from the magnet link
torrent_id = "3B245504CF5F11BBDBE1201CEA6A6BF45AEE1BC0" # rtorrent uses uppercase hashes
torrent_id = "3B245504CF5F11BBDBE1201CEA6A6BF45AEE1BC0" # rtorrent uses uppercase hashes
print(f" Added test torrent: {torrent_id}")
torrents = client.download_list()
print(f" Active torrents: {len(torrents)}")
print(f" Active torrents: {len(torrents)}")
torrent_list = client.d.multicall.filtered(
"",
"default",
f"equal={{d.hash=,cat={torrent_id}}}"
"d.hash=",
f"equal={{d.hash=,cat={torrent_id}}}d.hash=",
"d.state=",
"d.completed_bytes=",
"d.size_bytes=",
@@ -483,7 +494,7 @@ def test_rtorrent():
if not torrent:
print(" ERROR: Could not find added torrent in list")
return False
# let's test the base path call
details = client.d.multicall.filtered(
"",
@@ -511,7 +522,7 @@ def test_rtorrent():
return False
def main():
def main() -> int:
print("Download Client Test Suite")
print("=" * 50)
print("Make sure containers are running:")
+17 -2
View File
@@ -1,8 +1,23 @@
"""Package entry point for `python -m shelfmark`."""
from shelfmark.main import app, socketio
from shelfmark.config.env import FLASK_HOST, FLASK_PORT
from shelfmark.core.config import config
from shelfmark.main import app, socketio
def _resolve_debug_flag(value: object) -> bool:
"""Normalize DEBUG config values for Flask-SocketIO startup."""
if isinstance(value, bool):
return value
if isinstance(value, str):
return value.strip().lower() in {"1", "true", "yes", "on"}
return bool(value)
if __name__ == "__main__":
socketio.run(app, host=FLASK_HOST, port=FLASK_PORT, debug=config.get("DEBUG", False))
socketio.run(
app,
host=FLASK_HOST,
port=FLASK_PORT,
debug=_resolve_debug_flag(config.get("DEBUG", False)),
)
+95 -128
View File
@@ -1,124 +1,81 @@
"""WebSocket manager for real-time status updates."""
from __future__ import annotations
import logging
import threading
from typing import Optional, Dict, Any, Callable, List
from typing import TYPE_CHECKING, Any
from flask_socketio import SocketIO, join_room, leave_room
if TYPE_CHECKING:
from collections.abc import Callable
from flask import Flask
logger = logging.getLogger(__name__)
class WebSocketManager:
"""Manages WebSocket connections and broadcasts."""
def __init__(self):
self.socketio: Optional[SocketIO] = None
def __init__(self) -> None:
"""Initialize in-memory connection and room tracking."""
self.socketio: SocketIO | None = None
self._enabled = False
self._connection_count = 0
self._connection_lock = threading.Lock()
self._on_first_connect_callbacks: List[Callable[[], None]] = []
self._on_all_disconnect_callbacks: List[Callable[[], None]] = []
self._needs_rewarm = False # Flag to trigger warmup callbacks on next connect
self._user_rooms: Dict[str, int] = {} # room_name -> ref count
self._sid_rooms: Dict[str, str] = {} # sid -> room_name
self._user_rooms: dict[str, int] = {} # room_name -> ref count
self._sid_rooms: dict[str, str] = {} # sid -> room_name
self._rooms_lock = threading.Lock()
self._queue_status_fn: Optional[Callable] = None # Reference to queue_status()
self._queue_status_fn: Callable | None = None # Reference to queue_status()
def init_app(self, app, socketio: SocketIO):
def init_app(self, app: Flask, socketio: SocketIO) -> None:
"""Initialize the WebSocket manager with Flask-SocketIO instance."""
self.socketio = socketio
self._enabled = True
logger.info("WebSocket manager initialized")
def register_on_first_connect(self, callback: Callable[[], None]):
"""Register a callback for when the first client connects."""
self._on_first_connect_callbacks.append(callback)
logger.debug(f"Registered on_first_connect callback: {callback.__name__}")
def register_on_all_disconnect(self, callback: Callable[[], None]):
"""Register a callback for when all clients disconnect."""
self._on_all_disconnect_callbacks.append(callback)
logger.debug(f"Registered on_all_disconnect callback: {callback.__name__}")
def request_warmup_on_next_connect(self):
"""Request warmup callbacks on the next client connect (e.g., after idle shutdown)."""
with self._connection_lock:
self._needs_rewarm = True
logger.debug("Warmup requested for next client connect")
def client_connected(self):
def client_connected(self) -> None:
"""Track a new client connection. Call this from the connect event handler."""
with self._connection_lock:
was_zero = self._connection_count == 0
needs_rewarm = self._needs_rewarm
self._connection_count += 1
current_count = self._connection_count
# Clear rewarm flag if we're going to trigger warmup
if was_zero or needs_rewarm:
self._needs_rewarm = False
logger.debug(f"Client connected. Active connections: {current_count}")
logger.debug("Client connected. Active connections: %s", current_count)
# Trigger warmup callbacks if this is the first connection OR if rewarm was requested
# (rewarm is requested when bypasser shuts down due to idle while clients are connected)
if was_zero or needs_rewarm:
reason = "First client connected" if was_zero else "Rewarm requested after idle shutdown"
logger.info(f"{reason}, triggering warmup callbacks...")
for callback in self._on_first_connect_callbacks:
try:
# Run callbacks in a separate thread to not block the connection
thread = threading.Thread(target=callback, daemon=True)
thread.start()
except Exception as e:
logger.error(f"Error in on_first_connect callback {callback.__name__}: {e}")
def client_disconnected(self):
def client_disconnected(self) -> None:
"""Track a client disconnection. Call this from the disconnect event handler."""
with self._connection_lock:
self._connection_count = max(0, self._connection_count - 1)
current_count = self._connection_count
is_now_zero = current_count == 0
logger.debug(f"Client disconnected. Active connections: {current_count}")
# If all clients have disconnected, trigger cleanup callbacks
if is_now_zero:
logger.info("All clients disconnected, triggering disconnect callbacks...")
for callback in self._on_all_disconnect_callbacks:
try:
callback()
except Exception as e:
logger.error(f"Error in on_all_disconnect callback {callback.__name__}: {e}")
def get_connection_count(self) -> int:
"""Get the current number of active WebSocket connections."""
with self._connection_lock:
return self._connection_count
def has_active_connections(self) -> bool:
"""Check if there are any active WebSocket connections."""
return self.get_connection_count() > 0
logger.debug("Client disconnected. Active connections: %s", current_count)
def is_enabled(self) -> bool:
"""Check if WebSocket is enabled and ready."""
return self._enabled and self.socketio is not None
def set_queue_status_fn(self, fn: Callable):
def _get_socketio(self) -> SocketIO | None:
if not self._enabled:
return None
return self.socketio
def set_queue_status_fn(self, fn: Callable) -> None:
"""Set the queue_status function reference for per-room filtering."""
self._queue_status_fn = fn
def _increment_user_room_locked(self, room: str):
def _increment_user_room_locked(self, room: str) -> None:
self._user_rooms[room] = self._user_rooms.get(room, 0) + 1
def _decrement_user_room_locked(self, room: str):
def _decrement_user_room_locked(self, room: str) -> None:
count = self._user_rooms.get(room, 1) - 1
if count <= 0:
self._user_rooms.pop(room, None)
else:
self._user_rooms[room] = count
def _set_sid_room_locked(self, sid: str, room: Optional[str]):
def _set_sid_room_locked(self, sid: str, room: str | None) -> None:
current_room = self._sid_rooms.get(sid)
if current_room == room:
return
@@ -135,9 +92,14 @@ class WebSocketManager:
if room.startswith("user_"):
self._increment_user_room_locked(room)
def sync_user_room(self, sid: str, is_admin: bool, db_user_id: Optional[int] = None):
def sync_user_room(
self,
sid: str,
is_admin: bool,
db_user_id: int | None = None,
) -> None:
"""Ensure a SID is in exactly one room matching the current session scope."""
room: Optional[str] = None
room: str | None = None
if is_admin:
room = "admins"
elif db_user_id is not None:
@@ -146,24 +108,36 @@ class WebSocketManager:
with self._rooms_lock:
self._set_sid_room_locked(sid, room)
def join_user_room(self, sid: str, is_admin: bool, db_user_id: Optional[int] = None):
def join_user_room(
self,
sid: str,
is_admin: bool,
db_user_id: int | None = None,
) -> None:
"""Join the appropriate room based on user role."""
self.sync_user_room(sid, is_admin, db_user_id)
self.sync_user_room(sid, is_admin=is_admin, db_user_id=db_user_id)
def leave_user_room(self, sid: str, is_admin: bool = False, db_user_id: Optional[int] = None):
def leave_user_room(
self,
sid: str,
*,
is_admin: bool = False,
db_user_id: int | None = None,
) -> None:
"""Leave whichever room the SID currently belongs to."""
del is_admin, db_user_id # Backward-compatible signature; routing is SID-based.
with self._rooms_lock:
self._set_sid_room_locked(sid, None)
def broadcast_status_update(self, status_data: Dict[str, Any]):
def broadcast_status_update(self, status_data: dict[str, Any]) -> None:
"""Broadcast status update to all connected clients, filtered by user room."""
if not self.is_enabled():
socketio = self._get_socketio()
if socketio is None:
return
try:
# Admins (and no-auth users) get full status
self.socketio.emit('status_update', status_data, to="admins")
socketio.emit("status_update", status_data, to="admins")
# Each user room gets filtered status
with self._rooms_lock:
@@ -171,56 +145,48 @@ class WebSocketManager:
if active_rooms and self._queue_status_fn:
for room in active_rooms:
try:
# Extract user_id from room name "user_123"
uid = int(room.split("_", 1)[1])
filtered = self._queue_status_fn(user_id=uid)
self.socketio.emit('status_update', filtered, to=room)
except Exception as e:
logger.error(f"Failed to send status update for room {room}: {e}")
self._broadcast_status_update_to_room(room)
logger.debug("Broadcasted status update to all rooms")
except Exception as e:
logger.error(f"Error broadcasting status update: {e}")
except Exception:
logger.exception("Error broadcasting status update")
def broadcast_download_progress(self, book_id: str, progress: float, status: str, user_id: Optional[int] = None):
"""Broadcast download progress update for a specific book."""
if not self.is_enabled():
def _broadcast_status_update_to_room(self, room: str) -> None:
"""Broadcast status update to one user room."""
socketio = self._get_socketio()
if socketio is None:
return
try:
data = {
'book_id': book_id,
'progress': progress,
'status': status
}
# Extract user_id from room name "user_123"
uid = int(room.split("_", 1)[1])
filtered = self._queue_status_fn(user_id=uid) if self._queue_status_fn else None
if filtered is not None:
socketio.emit("status_update", filtered, to=room)
except Exception:
logger.exception("Failed to send status update for room %s", room)
def broadcast_download_progress(
self, book_id: str, progress: float, status: str, user_id: int | None = None
) -> None:
"""Broadcast download progress update for a specific book."""
socketio = self._get_socketio()
if socketio is None:
return
try:
data = {"book_id": book_id, "progress": progress, "status": status}
# Admins always see all progress
self.socketio.emit('download_progress', data, to="admins")
socketio.emit("download_progress", data, to="admins")
# If task belongs to a specific user, send to their room too
if user_id is not None:
room = f"user_{user_id}"
with self._rooms_lock:
if room in self._user_rooms:
self.socketio.emit('download_progress', data, to=room)
logger.debug(f"Broadcasted progress for book {book_id}: {progress}%")
except Exception as e:
logger.error(f"Error broadcasting download progress: {e}")
def broadcast_notification(self, message: str, notification_type: str = 'info'):
"""Broadcast a notification message to all clients."""
if not self.is_enabled():
return
try:
data = {
'message': message,
'type': notification_type
}
# When calling socketio.emit() outside event handlers, it broadcasts by default
self.socketio.emit('notification', data)
logger.debug(f"Broadcasted notification: {message}")
except Exception as e:
logger.error(f"Error broadcasting notification: {e}")
socketio.emit("download_progress", data, to=room)
logger.debug("Broadcasted progress for book %s: %s%%", book_id, progress)
except Exception:
logger.exception("Error broadcasting download progress")
def broadcast_search_status(
self,
@@ -228,23 +194,24 @@ class WebSocketManager:
provider: str,
book_id: str,
message: str,
phase: str = 'searching'
):
phase: str = "searching",
) -> None:
"""Broadcast search status update for a release source search."""
if not self.is_enabled():
socketio = self._get_socketio()
if socketio is None:
return
try:
data = {
'source': source,
'provider': provider,
'book_id': book_id,
'message': message,
'phase': phase,
"source": source,
"provider": provider,
"book_id": book_id,
"message": message,
"phase": phase,
}
self.socketio.emit('search_status', data)
except Exception as e:
logger.error(f"Error broadcasting search status: {e}")
socketio.emit("search_status", data)
except Exception:
logger.exception("Error broadcasting search status")
# Global WebSocket manager instance
+12 -1
View File
@@ -1,5 +1,16 @@
"""Cloudflare bypass utilities."""
class BypassCancelledException(Exception):
class BypassCancelledError(Exception):
"""Raised when a bypass operation is cancelled."""
class ChallengeNotSolvedError(Exception):
"""Raised when a bypasser ran but the site still answered with a challenge.
Distinct from a bypasser that is broken or unreachable, which is what every
"the bypass failed" message used to say. A solver can do its job perfectly and
still be handed something it cannot clear - DDoS-Guard's manual CAPTCHA page is
the case from #1292 - and telling the user to go check that FlareSolverr is
reachable sends them to fix a service that is working.
"""
+52
View File
@@ -0,0 +1,52 @@
"""Challenge-page detection shared by the bypassers and the HTTP retry path.
Kept out of `internal_bypasser` so the HTTP layer can recognise an interstitial
without importing SeleniumBase: that module is imported lazily precisely because its
browser dependencies are optional, and external-bypasser setups run without them.
"""
# Matched against lowercased text, so every entry must be lowercase.
CLOUDFLARE_INDICATORS = [
"just a moment",
"verify you are human",
"verifying you are human",
"cloudflare.com/products/turnstile",
]
DDOS_GUARD_INDICATORS = [
"ddos-guard",
"ddos guard",
"checking your browser before accessing",
"complete the manual check to continue",
"could not verify your browser automatically",
]
# Markers that exist only in raw markup: the bypassers scan rendered innerText, where
# a script src or a <title> never appears. The title match is scoped to the tag on
# purpose - hosts word the rest of that sentence differently, and matching "checking
# your browser" as free text would trip on any page that merely discusses a challenge.
_RAW_HTML_MARKERS = (
"<title>checking your browser",
"/cdn-cgi/challenge-platform",
"/.well-known/ddos-guard/",
)
# An interstitial is a few KB of markup. Past that it is a real page that happens to
# mention a marker - a protected site links its own DDoS-Guard endpoints on every page.
MAX_CHALLENGE_HTML_CHARS = 64 * 1024
def challenge_marker(html: str) -> str | None:
"""Return the marker proving `html` is an unsolved challenge page, or None.
Only meaningful for a response that already carries a challenge status: the
markers appear on protected sites' real pages too, so the status is what
separates "blocked" from "served".
"""
if not html or len(html) > MAX_CHALLENGE_HTML_CHARS:
return None
lowered = html.lower()
for marker in (*_RAW_HTML_MARKERS, *DDOS_GUARD_INDICATORS, *CLOUDFLARE_INDICATORS):
if marker in lowered:
return marker
return None
+286
View File
@@ -0,0 +1,286 @@
"""Clearance cookies won by a bypass, shared by every bypasser implementation.
Kept in its own module rather than inside a bypasser because both of them feed it and
both read from it. The internal bypasser cannot host it: it imports seleniumbase at
module scope, which is exactly the dependency an external-bypasser deployment is
entitled not to have installed.
"""
import threading
import time
from collections.abc import Mapping
from typing import Any
from urllib.parse import urlparse
from shelfmark.core.logger import setup_logger
logger = setup_logger(__name__)
# Cookie storage - shared with requests library for Cloudflare bypass
# Nested mapping of domain to cookie name to cookie metadata.
_cf_cookies: dict[str, dict] = {}
_cf_cookies_lock = threading.Lock()
# User-Agent storage - Cloudflare ties cf_clearance to the UA that solved the challenge
_cf_user_agents: dict[str, str] = {}
# Protection cookie names we care about (Cloudflare and DDoS-Guard)
CF_COOKIE_NAMES = {"cf_clearance", "__cf_bm", "cf_chl_2", "cf_chl_prog"}
DDG_COOKIE_NAMES = {
"__ddg1_",
"__ddg2_",
"__ddg5_",
"__ddg8_",
"__ddg9_",
"__ddg10_",
"__ddgid_",
"__ddgmark_",
"ddg_last_challenge",
}
# Anna's Archive's own pass for its ?check=1 hop. Without it the hop 302s back
# forever, however good the __ddg* clearance is.
AA_COOKIE_NAMES = {"aa_ddg_check"}
# DDoS-Guard cookies that describe *one* check rather than granting clearance, and so
# must never be replayed on a later request. Observed live on Anna's Archive:
#
# __ddg9_ the client IP address
# __ddg10_ the unix timestamp the check was issued
# __ddg8_ an opaque token issued with them, same ~40 minute expiry
#
# Clearance itself lives in __ddg1_/__ddg2_/__ddgid_ (roughly a year) and __ddg5_.
# Replaying the trio is actively harmful: once the timestamp ages out - or the egress
# IP changes, which happens routinely behind a VPN - the values no longer describe the
# caller, DDoS-Guard re-arms its check and answers every request with a ?check=1
# redirect. That is the redirect loop, and it is self-inflicted. Dropping them simply
# lets DDoS-Guard issue a fresh set, exactly as it does for a browser.
DDG_EPHEMERAL_COOKIE_NAMES = {
"__ddg8_",
"__ddg9_",
"__ddg10_",
"ddg_last_challenge",
}
def _get_base_domain(domain: str) -> str:
"""Extract base domain from hostname (e.g., 'www.example.com' -> 'example.com')."""
return ".".join(domain.split(".")[-2:]) if "." in domain else domain
def _get_full_cookie_domains() -> set[str]:
"""Return mirror domains that need full-session cookie extraction."""
from shelfmark.core.mirrors import get_zlib_cookie_domains
return {_get_base_domain(domain) for domain in get_zlib_cookie_domains()}
def _replay_per_check_cookies() -> bool:
"""Whether the per-check trio is kept rather than dropped (see env.py)."""
from shelfmark.config import env
return env.DDG_REPLAY_PER_CHECK_COOKIES
def _should_extract_cookie(name: str, *, extract_all: bool) -> bool:
"""Determine if a cookie should be extracted based on its name."""
# Checked before extract_all: a per-check token is wrong to replay for every
# domain, including the full-session ones.
if name in DDG_EPHEMERAL_COOKIE_NAMES and not _replay_per_check_cookies():
return False
if extract_all:
return True
is_cf = name in CF_COOKIE_NAMES or name.startswith("cf_")
is_ddg = name in DDG_COOKIE_NAMES or name.startswith("__ddg")
is_aa = name in AA_COOKIE_NAMES
return is_cf or is_ddg or is_aa
def _cookie_field(cookie: Any, name: str) -> Any:
"""Read one field from a cookie in either shape we are handed.
The internal bypasser extracts CDP cookie objects; an external bypasser returns
the same fields as JSON objects, so the difference is attribute versus key access.
"""
if isinstance(cookie, Mapping):
return cookie.get(name)
return getattr(cookie, name, None)
def _cookie_expiry(cookie: Any) -> float | None:
"""A cookie's absolute expiry, or None when it is a session cookie.
The two spellings are not interchangeable and both reach this store. CDP and
Playwright cookies carry `expires`; the WebDriver cookie object - what a
Selenium-based solver such as FlareSolverr returns - carries `expiry`. Reading
only one silently turns every cookie from the other into a never-expiring one,
which is exactly how dead clearance ends up replayed forever (see
get_cf_cookies_for_domain).
The value is coerced rather than trusted: it arrives as JSON from a service we
do not control, and a string here used to raise straight out of the store.
"""
for field in ("expires", "expiry"):
raw = _cookie_field(cookie, field)
if raw is None:
continue
try:
expiry = float(raw)
except TypeError, ValueError:
logger.debug("Unreadable cookie expiry %r; treating as a session cookie", raw)
return None
# <= 0 is how both shapes spell "session cookie", not "expired in 1970".
return expiry if expiry > 0 else None
return None
def store_extracted_cookies(
*,
url: str,
cookies: list[Any],
user_agent: str | None = None,
) -> None:
"""Store filtered bypass cookies (and optional UA) for a URL domain."""
parsed = urlparse(url)
domain = parsed.hostname or ""
if not domain:
return
base_domain = _get_base_domain(domain)
extract_all = base_domain in _get_full_cookie_domains()
cookies_found: dict[str, dict[str, Any]] = {}
dropped: list[str] = []
for cookie in cookies:
name = _cookie_field(cookie, "name") or ""
if not _should_extract_cookie(name, extract_all=extract_all):
dropped.append(name)
continue
secure = _cookie_field(cookie, "secure")
cookies_found[name] = {
"value": _cookie_field(cookie, "value") or "",
"domain": _cookie_field(cookie, "domain") or domain,
"path": _cookie_field(cookie, "path") or "/",
"expiry": _cookie_expiry(cookie),
"secure": True if secure is None else bool(secure),
"httpOnly": True,
}
# Names only, never values. Which cookies a solve won, and which of them were held
# back, is the evidence needed to settle what DDoS-Guard actually treats as clearance
# (issue #1276) - and without it a debug log shows a solve succeeding and the next
# request being challenged with nothing in between to explain why.
logger.debug(
"Solve on %s won %s; keeping %s; dropping %s",
base_domain,
sorted({_cookie_field(c, "name") or "" for c in cookies}),
sorted(cookies_found),
sorted(set(dropped)) or "nothing",
)
if not cookies_found:
return
with _cf_cookies_lock:
_cf_cookies[base_domain] = cookies_found
if user_agent:
_cf_user_agents[base_domain] = user_agent
logger.debug("Stored UA for %s: %s...", base_domain, str(user_agent)[:60])
else:
logger.debug("No UA captured for %s", base_domain)
cookie_type = "all" if extract_all else "protection"
logger.debug("Extracted %s %s cookies for %s", len(cookies_found), cookie_type, base_domain)
def _is_cookie_expired(cookie: dict[str, Any]) -> bool:
"""Whether a stored cookie's expiry has passed. Session cookies never expire here."""
expiry = cookie.get("expiry")
if expiry is None:
expiry = cookie.get("expires")
if not expiry or expiry <= 0:
return False
return time.time() > expiry
def get_cf_cookies_for_domain(domain: str) -> dict[str, str]:
"""Get stored cookies for a domain. Returns empty dict if none available."""
if not domain:
return {}
base_domain = _get_base_domain(domain)
with _cf_cookies_lock:
cookies = _cf_cookies.get(base_domain, {})
if not cookies:
return {}
cf_clearance = cookies.get("cf_clearance", {})
if cf_clearance and _is_cookie_expired(cf_clearance):
logger.debug("CF cookies expired for %s", base_domain)
_cf_cookies.pop(base_domain, None)
return {}
# Expiry applies to every cookie, not just Cloudflare's. DDoS-Guard domains
# have no cf_clearance, so the check above never fired for them and dead
# cookies were replayed indefinitely - the server answers those with a
# challenge, which is indistinguishable from having sent nothing at all.
live = {name: c for name, c in cookies.items() if not _is_cookie_expired(c)}
if len(live) != len(cookies):
expired = sorted(set(cookies) - set(live))
logger.debug("Dropping expired cookies for %s: %s", base_domain, expired)
if live:
_cf_cookies[base_domain] = live
else:
_cf_cookies.pop(base_domain, None)
return {name: c["value"] for name, c in live.items()}
def has_valid_cf_cookies(domain: str) -> bool:
"""Check if we have valid Cloudflare cookies for a domain."""
return bool(get_cf_cookies_for_domain(domain))
def get_cf_user_agent_for_domain(domain: str) -> str | None:
"""Get the User-Agent that was used during bypass for a domain."""
if not domain:
return None
with _cf_cookies_lock:
return _cf_user_agents.get(_get_base_domain(domain))
def export_store() -> tuple[dict[str, dict], dict[str, str]]:
"""Snapshot the whole store, for handing to another process.
The internal bypasser's Docker helper solves in a subprocess, so the clearance it
wins has to be serialized back to the parent or the solve is lost with the child.
"""
with _cf_cookies_lock:
return (
{domain: dict(cookies) for domain, cookies in _cf_cookies.items()},
dict(_cf_user_agents),
)
def import_store(cookies: object, user_agents: object) -> None:
"""Merge a snapshot produced by :func:`export_store` into this process's store."""
with _cf_cookies_lock:
if isinstance(cookies, dict):
_cf_cookies.update(cookies)
if isinstance(user_agents, dict):
_cf_user_agents.update(
{str(domain): str(agent) for domain, agent in user_agents.items()}
)
def clear_cf_cookies(domain: str | None = None) -> None:
"""Clear stored Cloudflare cookies and User-Agent. If domain is None, clear all."""
with _cf_cookies_lock:
if domain:
base_domain = _get_base_domain(domain)
_cf_cookies.pop(base_domain, None)
_cf_user_agents.pop(base_domain, None)
else:
_cf_cookies.clear()
_cf_user_agents.clear()
+189 -35
View File
@@ -2,20 +2,26 @@
import random
import time
from threading import Event
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Any
import requests
from shelfmark.bypass import BypassCancelledException
from shelfmark.bypass import BypassCancelledError, ChallengeNotSolvedError
from shelfmark.bypass.challenge import challenge_marker
from shelfmark.bypass.cookie_store import store_extracted_cookies
from shelfmark.core.config import config
from shelfmark.core.logger import setup_logger
from shelfmark.core.utils import normalize_http_url
from shelfmark.download.network import get_ssl_verify
if TYPE_CHECKING:
from collections.abc import Mapping
from threading import Event
from shelfmark.download import network
logger = setup_logger(__name__)
_RNG = random.SystemRandom()
# Timeout constants (seconds)
CONNECT_TIMEOUT = 10
@@ -28,15 +34,83 @@ BACKOFF_BASE = 1.0
BACKOFF_CAP = 10.0
def _fetch_via_bypasser(target_url: str) -> Optional[str]:
"""Make a single request to the external bypasser service. Returns HTML or None."""
raw_bypasser_url = config.get("EXT_BYPASSER_URL", "http://flaresolverr:8191")
bypasser_path = config.get("EXT_BYPASSER_PATH", "/v1")
bypasser_timeout = config.get("EXT_BYPASSER_TIMEOUT", 60000)
def _coerce_config_str(value: object, default: str) -> str:
"""Return a string config value or a safe default."""
if isinstance(value, str):
return value
return default
def _coerce_timeout_ms(value: object, default: int) -> int:
"""Return a positive timeout in milliseconds or the default."""
if isinstance(value, bool):
return default
if isinstance(value, int) and value > 0:
return value
return default
def max_duration_seconds() -> float:
"""Upper bound on how long get_bypassed_page() can take for one URL.
MAX_RETRY attempts at the configured read timeout, plus the exponential backoff waited
between them (jitter is < 1s per gap, counted as a full second to stay conservative).
Callers use this to declare a stall-detection grace; see shelfmark.download.activity.
"""
bypasser_timeout = _coerce_timeout_ms(config.get("EXT_BYPASSER_TIMEOUT", 60000), 60000)
read_timeout = min((bypasser_timeout / 1000) + READ_TIMEOUT_BUFFER, MAX_READ_TIMEOUT)
backoff_total = sum(
min(BACKOFF_CAP, BACKOFF_BASE * (2 ** (attempt - 1))) + 1.0
for attempt in range(1, MAX_RETRY)
)
return MAX_RETRY * read_timeout + backoff_total
def _store_solution_clearance(target_url: str, solution: Mapping[str, Any]) -> None:
"""Keep the clearance the solver won, so later requests do not re-solve.
A solve is the expensive part of an external bypass - tens of seconds of real
browser - and FlareSolverr-compatible services hand back the cookies and the
User-Agent that earned it. Dropping them meant every single request paid a 403
plus a full solve, and a file download (which the solver cannot proxy, being
binary) never presented clearance at all.
The UA matters as much as the cookies: Cloudflare ties cf_clearance to the UA
that solved the challenge, so replaying the cookie under our own UA is rejected.
"""
cookies = solution.get("cookies") or []
if not isinstance(cookies, list):
logger.debug("External bypasser returned no usable cookie list for '%s'", target_url)
return
user_agent = solution.get("userAgent")
store_extracted_cookies(
url=target_url,
cookies=cookies,
user_agent=user_agent if isinstance(user_agent, str) else None,
)
def _fetch_via_bypasser(target_url: str) -> str | None:
"""Make a single request to the external bypasser service. Returns HTML or None.
Raises:
ChallengeNotSolvedError: the service answered with a page that is still a
challenge, whatever verdict it reported on itself.
"""
raw_bypasser_url = _coerce_config_str(
config.get("EXT_BYPASSER_URL", "http://flaresolverr:8191"),
"http://flaresolverr:8191",
)
bypasser_path = _coerce_config_str(config.get("EXT_BYPASSER_PATH", "/v1"), "/v1")
bypasser_timeout = _coerce_timeout_ms(config.get("EXT_BYPASSER_TIMEOUT", 60000), 60000)
bypasser_url = normalize_http_url(raw_bypasser_url)
if not bypasser_url or not bypasser_path:
logger.error("External bypasser not configured. Check EXT_BYPASSER_URL and EXT_BYPASSER_PATH.")
logger.error(
"External bypasser not configured. Check EXT_BYPASSER_URL and EXT_BYPASSER_PATH."
)
return None
read_timeout = min((bypasser_timeout / 1000) + READ_TIMEOUT_BUFFER, MAX_READ_TIMEOUT)
@@ -45,47 +119,98 @@ def _fetch_via_bypasser(target_url: str) -> Optional[str]:
response = requests.post(
f"{bypasser_url}{bypasser_path}",
headers={"Content-Type": "application/json"},
json={"cmd": "request.get", "url": target_url, "maxTimeout": bypasser_timeout},
timeout=(CONNECT_TIMEOUT, read_timeout)
json={
"cmd": "request.get",
"url": target_url,
"maxTimeout": bypasser_timeout,
},
timeout=(CONNECT_TIMEOUT, read_timeout),
verify=get_ssl_verify(bypasser_url),
)
response.raise_for_status()
result = response.json()
status = result.get('status', 'unknown')
message = result.get('message', '')
logger.debug(f"External bypasser response for '{target_url}': {status} - {message}")
status = result.get("status", "unknown")
message = result.get("message", "")
logger.debug("External bypasser response for '%s': %s - %s", target_url, status, message)
if status != 'ok':
logger.warning(f"External bypasser failed for '{target_url}': {status} - {message}")
if status != "ok":
logger.warning(
"External bypasser failed for '%s': %s - %s",
target_url,
status,
message,
)
return None
solution = result.get('solution')
html = solution.get('response', '') if solution else ''
solution = result.get("solution")
html = solution.get("response", "") if solution else ""
if not html:
logger.warning(f"External bypasser returned empty response for '{target_url}'")
logger.warning("External bypasser returned empty response for '%s'", target_url)
return None
return html
# "Challenge solved!" is the solver's verdict on its own work, and #1289 showed
# it can be reported alongside a page the caller then rejects. Say what actually
# came back, so a later report does not have to infer it from downstream errors.
marker = challenge_marker(html)
logger.debug(
"External bypasser page for '%s': %d bytes, challenge_marker=%r",
target_url,
len(html),
marker,
)
if marker:
# The solver's verdict is not evidence; the page is. Returning this one as a
# success is what made #1292 unrecoverable: the retry-and-rotate loop that
# could still have saved the search - the next mirror is a different
# DDoS-Guard host, in its own state - was never entered, and the challenge
# page's own __ddg cookies were filed as this host's clearance and replayed
# on every later request.
logger.warning(
"External bypasser reported success but returned a challenge page for "
"'%s' (%d bytes, marker=%r) - the solve did not clear the protection",
target_url,
len(html),
marker,
)
raise ChallengeNotSolvedError(marker)
try:
_store_solution_clearance(target_url, solution)
except AttributeError, KeyError, TypeError, ValueError:
# Storing clearance is an optimisation; the page is the product. The
# solution JSON comes from a service we do not control, so a surprise in
# its cookie shape must not discard HTML that already cost a ~30s solve
# and send the caller round for up to MAX_RETRY more of them.
logger.debug("Could not store bypass clearance for '%s'", target_url, exc_info=True)
except requests.exceptions.Timeout:
logger.warning(f"External bypasser timed out for '{target_url}' (connect: {CONNECT_TIMEOUT}s, read: {read_timeout:.0f}s)")
logger.warning(
"External bypasser timed out for '%s' (connect: %ss, read: %.0fs)",
target_url,
CONNECT_TIMEOUT,
read_timeout,
)
except requests.exceptions.RequestException as e:
logger.warning(f"External bypasser request failed for '{target_url}': {e}")
logger.warning("External bypasser request failed for '%s': %s", target_url, e)
except (KeyError, TypeError, ValueError) as e:
logger.warning(f"External bypasser returned malformed response for '{target_url}': {e}")
logger.warning("External bypasser returned malformed response for '%s': %s", target_url, e)
else:
return html
return None
def _check_cancelled(cancel_flag: Optional[Event], context: str) -> None:
def _check_cancelled(cancel_flag: Event | None, context: str) -> None:
"""Check if operation was cancelled and raise exception if so."""
if cancel_flag and cancel_flag.is_set():
logger.info(f"External bypasser cancelled {context}")
raise BypassCancelledException("Bypass cancelled")
logger.info("External bypasser cancelled %s", context)
msg = "Bypass cancelled"
raise BypassCancelledError(msg)
def _sleep_with_cancellation(seconds: float, cancel_flag: Optional[Event]) -> None:
def _sleep_with_cancellation(seconds: float, cancel_flag: Event | None) -> None:
"""Sleep for the specified duration, checking for cancellation each second."""
for _ in range(int(seconds)):
_check_cancelled(cancel_flag, "during backoff")
@@ -97,32 +222,61 @@ def _sleep_with_cancellation(seconds: float, cancel_flag: Optional[Event]) -> No
def get_bypassed_page(
url: str,
selector: Optional["network.AAMirrorSelector"] = None,
cancel_flag: Optional[Event] = None
) -> Optional[str]:
"""Fetch HTML via external bypasser with retries and mirror rotation."""
selector: network.AAMirrorSelector | None = None,
cancel_flag: Event | None = None,
) -> str | None:
"""Fetch HTML via external bypasser with retries and mirror rotation.
Raises:
ChallengeNotSolvedError: every attempt came back still carrying a challenge.
Reported apart from returning None because the two ask the user for
opposite things: None means go and check the bypasser, this means the
bypasser is fine and the host is the one refusing.
BypassCancelledError: the caller's cancel flag was set.
"""
from shelfmark.download import network as network_module
sel = selector or network_module.AAMirrorSelector()
unsolved_marker: str | None = None
for attempt in range(1, MAX_RETRY + 1):
_check_cancelled(cancel_flag, "by user")
attempt_url = sel.rewrite(url)
result = _fetch_via_bypasser(attempt_url)
try:
result = _fetch_via_bypasser(attempt_url)
except ChallengeNotSolvedError as e:
# Worth the remaining attempts rather than an immediate give-up: the retry
# rotates onto the next mirror, and that is a different DDoS-Guard host with
# its own idea of whether this caller needs a CAPTCHA.
unsolved_marker = str(e) or unsolved_marker
result = None
if result:
return result
if attempt == MAX_RETRY:
break
delay = min(BACKOFF_CAP, BACKOFF_BASE * (2 ** (attempt - 1))) + random.random()
logger.info(f"External bypasser attempt {attempt}/{MAX_RETRY} failed, retrying in {delay:.1f}s")
delay = min(BACKOFF_CAP, BACKOFF_BASE * (2 ** (attempt - 1))) + _RNG.random()
logger.info(
"External bypasser attempt %s/%s failed, retrying in %.1fs",
attempt,
MAX_RETRY,
delay,
)
_sleep_with_cancellation(delay, cancel_flag)
new_base, action = sel.next_mirror_or_rotate_dns()
if action in ("mirror", "dns") and new_base:
logger.info(f"Rotated {action} for retry")
logger.info("Rotated %s for retry", action)
if unsolved_marker:
msg = (
"The bypasser ran, but the site kept answering with a protection challenge "
f"(marker={unsolved_marker!r}). That is usually a manual CAPTCHA, which no "
"bypasser can answer - the bypasser itself is working. Try again shortly."
)
raise ChallengeNotSolvedError(msg)
return None
+29 -16
View File
@@ -1,52 +1,65 @@
"""Browser fingerprint profile management for bypass stealth."""
import random
from typing import Optional
from shelfmark.core.logger import setup_logger
logger = setup_logger(__name__)
COMMON_RESOLUTIONS = [
(1920, 1080, 0.35),
(1366, 768, 0.18),
(1536, 864, 0.10),
(1440, 900, 0.08),
(1280, 720, 0.07),
(1600, 900, 0.06),
(1280, 800, 0.05),
(2560, 1440, 0.04),
(1680, 1050, 0.04),
(1920, 1200, 0.03),
(1920, 1080, 0.35),
(1366, 768, 0.18),
(1536, 864, 0.10),
(1440, 900, 0.08),
(1280, 720, 0.07),
(1600, 900, 0.06),
(1280, 800, 0.05),
(2560, 1440, 0.04),
(1680, 1050, 0.04),
(1920, 1200, 0.03),
]
# Current screen size (module-level singleton)
_current_screen_size: Optional[tuple[int, int]] = None
_current_screen_size: tuple[int, int] | None = None
_RNG = random.SystemRandom()
def get_screen_size() -> tuple[int, int]:
"""Return the current synthetic screen size, generating one if needed."""
global _current_screen_size
if _current_screen_size is None:
_current_screen_size = _generate_screen_size()
logger.debug(f"Generated initial screen size: {_current_screen_size[0]}x{_current_screen_size[1]}")
logger.debug(
"Generated initial screen size: %sx%s",
_current_screen_size[0],
_current_screen_size[1],
)
return _current_screen_size
def rotate_screen_size() -> tuple[int, int]:
"""Rotate to a new synthetic screen size and return it."""
global _current_screen_size
old_size = _current_screen_size
_current_screen_size = _generate_screen_size()
width, height = _current_screen_size
if old_size:
logger.info(f"Rotated screen size: {old_size[0]}x{old_size[1]} -> {width}x{height}")
logger.info(
"Rotated screen size: %sx%s -> %sx%s",
old_size[0],
old_size[1],
width,
height,
)
else:
logger.info(f"Generated screen size: {width}x{height}")
logger.info("Generated screen size: %sx%s", width, height)
return _current_screen_size
def clear_screen_size() -> None:
"""Clear the cached synthetic screen size."""
global _current_screen_size
_current_screen_size = None
@@ -54,4 +67,4 @@ def clear_screen_size() -> None:
def _generate_screen_size() -> tuple[int, int]:
resolutions = [(w, h) for w, h, _ in COMMON_RESOLUTIONS]
weights = [weight for _, _, weight in COMMON_RESOLUTIONS]
return random.choices(resolutions, weights=weights)[0]
return _RNG.choices(resolutions, weights=weights)[0]
File diff suppressed because it is too large Load Diff
+16
View File
@@ -0,0 +1,16 @@
"""Recognize Anna's Archive pages that require a live JavaScript timer."""
from urllib.parse import urlparse
from bs4 import BeautifulSoup
class WaitingRoomTimeoutError(TimeoutError):
"""The source waiting room did not finish within the browser session budget."""
def is_aa_waiting_room(url: str, html: str) -> bool:
"""Match the download route and actual timer element, not a script reference."""
return urlparse(url).path.startswith("/slow_download/") and bool(
BeautifulSoup(html, "html.parser").select_one(".js-partner-countdown")
)
+28 -21
View File
@@ -1,5 +1,8 @@
"""Helpers for Booklore settings validation, option loading, and connection tests."""
from __future__ import annotations
import hashlib
from typing import Any
from shelfmark.core.config import config
@@ -21,7 +24,7 @@ _BOOKLORE_OPTIONS_CACHE: dict[str, Any] = {
def _get_booklore_cache_key(base_url: str, username: str, password: str) -> str:
return f"{base_url}|{username}|{hash(password)}"
return f"{base_url}|{username}|{hashlib.sha256(password.encode()).hexdigest()}"
def _get_booklore_select_options(
@@ -121,7 +124,7 @@ def get_booklore_library_options() -> list[dict[str, Any]]:
base_url = str(config.get("BOOKLORE_HOST", "") or "").strip().rstrip("/")
username = str(config.get("BOOKLORE_USERNAME", "") or "").strip()
password = config.get("BOOKLORE_PASSWORD", "") or ""
password = str(config.get("BOOKLORE_PASSWORD", "") or "")
if not base_url or not username or not password:
return []
@@ -130,12 +133,13 @@ def get_booklore_library_options() -> list[dict[str, Any]]:
try:
library_options, _ = _get_booklore_cached_options(base_url, username, password)
return library_options
except Exception as exc:
logger.error(f"Failed to fetch Booklore libraries: {exc}")
except Exception:
logger.exception("Failed to fetch Booklore libraries")
if _BOOKLORE_OPTIONS_CACHE.get("key") == cache_key:
return _BOOKLORE_OPTIONS_CACHE.get("library_options", [])
return []
else:
return library_options
def get_booklore_path_options() -> list[dict[str, Any]]:
@@ -145,7 +149,7 @@ def get_booklore_path_options() -> list[dict[str, Any]]:
base_url = str(config.get("BOOKLORE_HOST", "") or "").strip().rstrip("/")
username = str(config.get("BOOKLORE_USERNAME", "") or "").strip()
password = config.get("BOOKLORE_PASSWORD", "") or ""
password = str(config.get("BOOKLORE_PASSWORD", "") or "")
if not base_url or not username or not password:
return []
@@ -154,19 +158,22 @@ def get_booklore_path_options() -> list[dict[str, Any]]:
try:
_, path_options = _get_booklore_cached_options(base_url, username, password)
return path_options
except Exception as exc:
logger.error(f"Failed to fetch Booklore paths: {exc}")
except Exception:
logger.exception("Failed to fetch Booklore paths")
if _BOOKLORE_OPTIONS_CACHE.get("key") == cache_key:
return _BOOKLORE_OPTIONS_CACHE.get("path_options", [])
return []
else:
return path_options
def test_booklore_connection(current_values: dict[str, Any] | None = None) -> dict[str, Any]:
def check_booklore_connection(
current_values: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Test the Booklore connection using current form values."""
current_values = current_values or {}
def _get_value(key: str, default: Any = None) -> Any:
def _get_value(key: str, default: object = None) -> object:
value = current_values.get(key)
if value not in (None, ""):
return value
@@ -176,22 +183,22 @@ def test_booklore_connection(current_values: dict[str, Any] | None = None) -> di
base_url = str(_get_value("BOOKLORE_HOST", "") or "").strip().rstrip("/")
username = str(_get_value("BOOKLORE_USERNAME", "") or "").strip()
password = _get_value("BOOKLORE_PASSWORD", "") or ""
password = str(_get_value("BOOKLORE_PASSWORD", "") or "")
if not base_url:
return {"success": False, "message": "Booklore URL is required"}
return {"success": False, "message": "Grimmory URL is required"}
if not username:
return {"success": False, "message": "Booklore username is required"}
return {"success": False, "message": "Grimmory username is required"}
if not password:
return {"success": False, "message": "Booklore password is required"}
return {"success": False, "message": "Grimmory password is required"}
try:
library_options, _ = _get_booklore_select_options(base_url, username, password)
message = "Connected to Booklore"
if library_options:
message = f"Connected to Booklore ({len(library_options)} libraries)"
return {"success": True, "message": message}
except BookloreError as exc:
return {"success": False, "message": str(exc)}
else:
message = "Connected to Grimmory"
if library_options:
message = f"Connected to Grimmory ({len(library_options)} libraries)"
return {"success": True, "message": message}
@@ -0,0 +1,110 @@
from __future__ import annotations
import re
from pathlib import Path
from typing import Any
_USER_PLACEHOLDER_PATTERN = re.compile(r"\{user\}", re.IGNORECASE)
def _get_download_setting_value(
current_values: dict[str, Any] | None,
key: str,
*,
default: object = None,
) -> object:
"""Read a downloads setting from unsaved form values first, then persisted config."""
from shelfmark.core.config import config
current_values = current_values or {}
if key in current_values:
return current_values[key]
if default is None:
return config.get(key)
return config.get(key, default)
def _resolve_destination_test_path(
configured_path: str,
) -> tuple[Path, str | None]:
"""Resolve a safe path to validate for destination test actions."""
stripped_path = configured_path.strip()
if not _USER_PLACEHOLDER_PATTERN.search(stripped_path):
return Path(stripped_path), None
base_prefix = _USER_PLACEHOLDER_PATTERN.split(stripped_path, maxsplit=1)[0].rstrip("/")
if not base_prefix and not stripped_path.startswith("/"):
return Path(stripped_path), None
base_path = base_prefix or "/"
return Path(base_path), (
f" (tested base path {base_path} from configured template {stripped_path})"
)
def _test_folder_destination(
*,
current_values: dict[str, Any] | None = None,
is_audiobook: bool,
) -> dict[str, Any]:
"""Validate a folder destination using current form values."""
from shelfmark.download.postprocess.destination import validate_destination
destination_value = _get_download_setting_value(
current_values,
"DESTINATION",
default="/books",
)
destination = str(destination_value or "").strip()
label = "Books destination"
message_suffix = ""
if is_audiobook:
audiobook_value = _get_download_setting_value(
current_values,
"DESTINATION_AUDIOBOOK",
default="",
)
audiobook_destination = str(audiobook_value or "").strip()
if audiobook_destination:
destination = audiobook_destination
label = "Audiobook destination"
else:
label = "Audiobook destination"
message_suffix = " (using the Books destination)"
if not destination:
return {"success": False, "message": f"{label} is required"}
test_path, path_message = _resolve_destination_test_path(destination)
if path_message:
message_suffix += path_message
errors: list[str] = []
def _status_callback(status: str, message: str | None) -> None:
if status == "error" and message:
errors.append(message)
if not validate_destination(test_path, _status_callback):
message = errors[-1] if errors else f"Cannot access destination: {test_path}"
if message_suffix:
message = f"{message}{message_suffix}"
return {"success": False, "message": message}
return {
"success": True,
"message": f"{label} is writable: {test_path}{message_suffix}",
}
def check_books_destination(current_values: dict[str, Any] | None = None) -> dict[str, Any]:
"""Validate the configured books destination."""
return _test_folder_destination(current_values=current_values, is_audiobook=False)
def check_audiobook_destination(current_values: dict[str, Any] | None = None) -> dict[str, Any]:
"""Validate the configured audiobook destination."""
return _test_folder_destination(current_values=current_values, is_audiobook=True)
+16 -8
View File
@@ -1,17 +1,25 @@
"""Helpers for email settings validation and SMTP connection tests."""
from __future__ import annotations
import smtplib
from typing import Any
from shelfmark.core.config import config
from shelfmark.download.outputs.email import EmailOutputError, build_email_smtp_config, test_smtp_connection
from shelfmark.download.outputs.email import (
EmailOutputError,
build_email_smtp_config,
test_smtp_connection,
)
def test_email_connection(current_values: dict[str, Any] | None = None) -> dict[str, Any]:
def check_email_connection(
current_values: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Test SMTP connectivity using current form values (including unsaved changes)."""
current_values = current_values or {}
def _get_value(key: str, default: Any = None) -> Any:
def _get_value(key: str, default: object = None) -> object:
value = current_values.get(key)
if value not in (None, ""):
return value
@@ -28,15 +36,15 @@ def test_email_connection(current_values: dict[str, Any] | None = None) -> dict[
"EMAIL_FROM": _get_value("EMAIL_FROM", ""),
"EMAIL_SUBJECT_TEMPLATE": _get_value("EMAIL_SUBJECT_TEMPLATE", "{Title}"),
"EMAIL_SMTP_TIMEOUT_SECONDS": _get_value("EMAIL_SMTP_TIMEOUT_SECONDS", 60),
"EMAIL_ALLOW_UNVERIFIED_TLS": _get_value("EMAIL_ALLOW_UNVERIFIED_TLS", False),
"EMAIL_ALLOW_UNVERIFIED_TLS": _get_value("EMAIL_ALLOW_UNVERIFIED_TLS", default=False),
}
try:
smtp_config = build_email_smtp_config(settings)
test_smtp_connection(smtp_config)
return {"success": True, "message": "Connected to SMTP server"}
except EmailOutputError as exc:
return {"success": False, "message": str(exc)}
except Exception as exc:
except (OSError, smtplib.SMTPException) as exc:
return {"success": False, "message": f"SMTP test failed: {exc}"}
else:
return {"success": True, "message": "Connected to SMTP server"}
+90 -20
View File
@@ -3,43 +3,88 @@
import json
import os
import shutil
import tempfile
from pathlib import Path
LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
def string_to_bool(s: str) -> bool:
"""Convert string to boolean."""
return s.lower() in ["true", "yes", "1", "y"]
def _read_advanced_config(key: str) -> object | None:
"""Read a key from the advanced settings file (import-time safe)."""
config_dir = Path(os.getenv("CONFIG_DIR", "/config"))
config_file = config_dir / "plugins" / "advanced.json"
if config_file.exists():
try:
with config_file.open() as f:
config = json.load(f)
if key in config:
return config[key]
except json.JSONDecodeError, OSError:
pass
return None
def _read_debug_from_config() -> bool:
"""Read DEBUG from env var or config file (import-time safe)."""
env_debug = os.environ.get("DEBUG")
if env_debug is not None:
return string_to_bool(env_debug)
# Try to read from config file
config_dir = Path(os.getenv("CONFIG_DIR", "/config"))
config_file = config_dir / "plugins" / "advanced.json"
if config_file.exists():
try:
with open(config_file, "r") as f:
config = json.load(f)
if "DEBUG" in config:
return bool(config["DEBUG"])
except (json.JSONDecodeError, OSError):
pass
value = _read_advanced_config("DEBUG")
if value is not None:
return bool(value)
return False
def normalize_log_level(raw: str | None) -> str:
"""Normalize a log level name, falling back to INFO when unrecognized."""
if raw is None:
return "INFO"
normalized = raw.strip().upper()
# "WARN" is a logging alias, but gunicorn only accepts "warning".
if normalized == "WARN":
normalized = "WARNING"
if normalized not in LOG_LEVELS:
return "INFO"
return normalized
def _read_log_level_from_config(debug: bool) -> str:
"""Resolve the app log level from DEBUG, env var, or config file.
DEBUG wins when enabled, mirroring how entrypoint.sh picks gunicorn's level.
Otherwise LOG_LEVEL is read from the env var, then the settings file, and
falls back to INFO when unset or unrecognized.
"""
if debug:
return "DEBUG"
raw = os.environ.get("LOG_LEVEL")
if raw is None:
value = _read_advanced_config("LOG_LEVEL")
raw = value if isinstance(value, str) else None
return normalize_log_level(raw)
def _is_sqlite_file(path: Path) -> bool:
"""Check if a file is a valid SQLite database by reading magic bytes."""
try:
with open(path, "rb") as f:
with path.open("rb") as f:
header = f.read(16)
return header[:16] == b"SQLite format 3\x00"
except (OSError, PermissionError):
except OSError, PermissionError:
return False
@@ -67,16 +112,20 @@ def _is_config_dir_writable() -> bool:
test_file = CONFIG_DIR / ".write_test"
test_file.touch()
test_file.unlink()
return True
except (OSError, PermissionError):
except OSError, PermissionError:
return False
else:
return True
def is_covers_cache_enabled() -> bool:
"""Check if cover caching is enabled (requires setting + writable config dir)."""
from shelfmark.core.config import config
setting_enabled = config.get("COVERS_CACHE_ENABLED", True)
return setting_enabled and _is_config_dir_writable()
if isinstance(setting_enabled, str):
return string_to_bool(setting_enabled) and _is_config_dir_writable()
return bool(setting_enabled) and _is_config_dir_writable()
# =============================================================================
@@ -87,7 +136,7 @@ CONFIG_DIR = Path(os.getenv("CONFIG_DIR", "/config"))
LOG_ROOT = Path(os.getenv("LOG_ROOT", "/var/log/"))
LOG_DIR = LOG_ROOT / "shelfmark"
LOG_FILE = LOG_DIR / "shelfmark.log"
TMP_DIR = Path(os.getenv("TMP_DIR", "/tmp/shelfmark"))
TMP_DIR = Path(os.getenv("TMP_DIR", (Path(tempfile.gettempdir()) / "shelfmark").as_posix()))
INGEST_DIR = Path(os.getenv("INGEST_DIR", "/books"))
@@ -96,7 +145,7 @@ INGEST_DIR = Path(os.getenv("INGEST_DIR", "/books"))
# =============================================================================
DEBUG = _read_debug_from_config()
LOG_LEVEL = "DEBUG" if DEBUG else "INFO"
LOG_LEVEL = _read_log_level_from_config(DEBUG)
ENABLE_LOGGING = string_to_bool(os.getenv("ENABLE_LOGGING", "true"))
@@ -115,6 +164,12 @@ FLASK_PORT = int(os.getenv("FLASK_PORT", "8084"))
SESSION_COOKIE_SECURE_ENV = os.getenv("SESSION_COOKIE_SECURE", "false")
SESSION_COOKIE_NAME = "shelfmark_session"
CWA_DB_PATH = _resolve_cwa_db_path()
HIDE_LOCAL_AUTH = string_to_bool(os.getenv("HIDE_LOCAL_AUTH", "false"))
DISABLE_LOCAL_AUTH = string_to_bool(os.getenv("DISABLE_LOCAL_AUTH", "false"))
# Optional static API key. When set, requests carrying it as a Bearer token
# (or X-Api-Key) are authenticated as an admin for that request only.
SHELFMARK_API_KEY = os.getenv("SHELFMARK_API_KEY", "").strip()
OIDC_AUTO_REDIRECT = string_to_bool(os.getenv("OIDC_AUTO_REDIRECT", "false"))
# =============================================================================
@@ -149,7 +204,22 @@ ONBOARDING = string_to_bool(os.getenv("ONBOARDING", "true"))
# Debug: skip specific download sources for testing fallback chains
# Comma-separated values: aa-fast, aa-slow-nowait, aa-slow-wait, libgen, zlib, welib
_DEBUG_SKIP_SOURCES_RAW = os.getenv("DEBUG_SKIP_SOURCES", "").strip().lower()
DEBUG_SKIP_SOURCES = set(s.strip() for s in _DEBUG_SKIP_SOURCES_RAW.split(",") if s.strip())
DEBUG_SKIP_SOURCES = {s.strip() for s in _DEBUG_SKIP_SOURCES_RAW.split(",") if s.strip()}
# Debug: keep DDoS-Guard's __ddg8_/__ddg9_/__ddg10_ in the clearance store instead of
# dropping them after a solve.
#
# Which of DDoS-Guard's cookies actually *are* clearance is not settled. The store treats
# the trio as describing one check (client IP, timestamp, token) and drops them, on the
# reasoning that replaying a stale IP/timestamp is what re-arms the ?check=1 loop - see
# shelfmark.bypass.cookie_store. Field reports on issue #1276 point the other way: every
# request after a successful solve was challenged again, which is only consistent with
# what the store keeps not being sufficient clearance on its own.
#
# Deliberately env-only and off by default: this is a knob for reproducing the question
# against a live host, not a setting to offer users. Set it to true, solve once, and watch
# whether the next search still logs "Redirect loop detected".
DDG_REPLAY_PER_CHECK_COOKIES = string_to_bool(os.getenv("DDG_REPLAY_PER_CHECK_COOKIES", "false"))
# =============================================================================
+107 -26
View File
@@ -1,8 +1,14 @@
"""Configuration migration helpers."""
import json
from typing import Any, Callable
from __future__ import annotations
import json
from pathlib import Path
from typing import TYPE_CHECKING, Any, Protocol
if TYPE_CHECKING:
from collections.abc import Callable, Sequence
from os import PathLike
_DEPRECATED_SETTINGS_RESTRICTION_KEYS = (
"PROXY_AUTH_RESTRICT_SETTINGS_TO_ADMIN",
@@ -10,8 +16,25 @@ _DEPRECATED_SETTINGS_RESTRICTION_KEYS = (
"RESTRICT_SETTINGS_TO_ADMIN",
)
# The audiobook format list shipped as the default until the format sets were unified.
# It only covered m4b/mp3, so FLAC/OPUS/OGG/M4A releases were dropped from search results
# and rejected after download - and the wider default alone would never reach existing
# installs, because initialize_default_configs() only writes defaults when the config
# file does not exist yet.
_LEGACY_AUDIOBOOK_FORMATS_DEFAULT = ("m4b", "mp3")
def _as_bool(value: Any) -> bool:
class MigrationLogger(Protocol):
"""Logger surface used by config migration helpers."""
def info(self, msg: str, *args: object) -> object: ...
def debug(self, msg: str, *args: object) -> object: ...
def exception(self, msg: str, *args: object) -> object: ...
def _as_bool(value: object) -> bool:
if isinstance(value, bool):
return value
if isinstance(value, str):
@@ -23,10 +46,7 @@ def _pick_legacy_settings_restriction(config: dict[str, Any]) -> bool | None:
"""Pick the best legacy admin-restriction value to migrate."""
auth_method = str(config.get("AUTH_METHOD", "")).strip().lower()
if (
auth_method == "proxy"
and "PROXY_AUTH_RESTRICT_SETTINGS_TO_ADMIN" in config
):
if auth_method == "proxy" and "PROXY_AUTH_RESTRICT_SETTINGS_TO_ADMIN" in config:
return _as_bool(config.get("PROXY_AUTH_RESTRICT_SETTINGS_TO_ADMIN"))
if auth_method == "cwa" and "CWA_RESTRICT_SETTINGS_TO_ADMIN" in config:
@@ -44,15 +64,63 @@ def _pick_legacy_settings_restriction(config: dict[str, Any]) -> bool | None:
return None
def migrate_audiobook_formats(
*,
load_general_config: Callable[[], dict[str, Any]],
# `object` rather than `None`: the result is discarded, and savers that report
# success (settings_registry.save_config_file returns bool) are not assignable to a
# `-> None` callable.
save_general_config: Callable[[dict[str, Any]], object],
widened_formats: Sequence[str],
logger: MigrationLogger,
) -> None:
"""Widen an untouched audiobook format list to the current, fuller default.
Only a list that still matches the old default exactly is rewritten. Any other value
means someone chose it deliberately, and a migration that "helpfully" re-enabled
formats a user had turned off would be worse than leaving them on the narrow list.
"""
try:
config = load_general_config()
if "SUPPORTED_AUDIOBOOK_FORMATS" not in config:
# Nothing persisted, so the field default already applies.
logger.debug("No persisted audiobook formats - the current default applies")
return
current = config.get("SUPPORTED_AUDIOBOOK_FORMATS")
if not isinstance(current, list):
return
normalized = {str(fmt).strip().lower() for fmt in current if str(fmt).strip()}
if normalized != set(_LEGACY_AUDIOBOOK_FORMATS_DEFAULT):
logger.debug(
"Audiobook formats were customized (%s) - left unchanged", sorted(normalized)
)
return
save_general_config({"SUPPORTED_AUDIOBOOK_FORMATS": list(widened_formats)})
logger.info(
"Widened audiobook formats from the legacy default %s to %s",
list(_LEGACY_AUDIOBOOK_FORMATS_DEFAULT),
list(widened_formats),
)
except FileNotFoundError:
logger.debug("No existing general config file found - nothing to migrate")
except Exception:
logger.exception("Failed to migrate audiobook formats")
def migrate_security_settings(
*,
load_security_config: Callable[[], dict[str, Any]],
load_users_config: Callable[[], dict[str, Any]],
save_users_config: Callable[[dict[str, Any]], None],
ensure_config_dir: Callable[[], None],
get_config_path: Callable[[], Any],
get_config_path: Callable[[], str | PathLike[str]],
sync_builtin_admin_user: Callable[[str, str], None],
logger: Any,
logger: MigrationLogger,
) -> None:
"""Migrate legacy security keys and sync builtin admin credentials."""
try:
@@ -67,49 +135,62 @@ def migrate_security_settings(
if old_value:
config["AUTH_METHOD"] = "cwa"
logger.info("Migrated USE_CWA_AUTH=True to AUTH_METHOD='cwa'")
elif config.get("BUILTIN_USERNAME") and config.get("BUILTIN_PASSWORD_HASH"):
config["AUTH_METHOD"] = "builtin"
logger.info("Migrated USE_CWA_AUTH=False to AUTH_METHOD='builtin'")
else:
if config.get("BUILTIN_USERNAME") and config.get("BUILTIN_PASSWORD_HASH"):
config["AUTH_METHOD"] = "builtin"
logger.info("Migrated USE_CWA_AUTH=False to AUTH_METHOD='builtin'")
else:
config["AUTH_METHOD"] = "none"
logger.info("Migrated USE_CWA_AUTH=False to AUTH_METHOD='none'")
config["AUTH_METHOD"] = "none"
logger.info("Migrated USE_CWA_AUTH=False to AUTH_METHOD='none'")
migrated_security = True
else:
logger.info("Removed deprecated USE_CWA_AUTH setting (AUTH_METHOD already exists)")
migrated_security = True
# Backfill AUTH_METHOD for configs that have builtin credentials but
# were never migrated from USE_CWA_AUTH (e.g. dev builds that predated
# the AUTH_METHOD field).
if (
"AUTH_METHOD" not in config
and config.get("BUILTIN_USERNAME")
and config.get("BUILTIN_PASSWORD_HASH")
):
config["AUTH_METHOD"] = "builtin"
migrated_security = True
logger.info(
"Backfilled AUTH_METHOD='builtin' from legacy "
"BUILTIN_USERNAME/BUILTIN_PASSWORD_HASH credentials"
)
if "RESTRICT_SETTINGS_TO_ADMIN" not in users_config:
legacy_restrict = _pick_legacy_settings_restriction(config)
if legacy_restrict is not None:
save_users_config({"RESTRICT_SETTINGS_TO_ADMIN": legacy_restrict})
migrated_users = True
logger.info(
"Migrated legacy settings-admin restriction to users.RESTRICT_SETTINGS_TO_ADMIN="
f"{legacy_restrict}"
"Migrated legacy settings-admin restriction to users.RESTRICT_SETTINGS_TO_ADMIN=%s",
legacy_restrict,
)
for deprecated_key in _DEPRECATED_SETTINGS_RESTRICTION_KEYS:
if deprecated_key in config:
config.pop(deprecated_key, None)
migrated_security = True
logger.info(f"Removed deprecated security setting: {deprecated_key}")
logger.info("Removed deprecated security setting: %s", deprecated_key)
try:
sync_builtin_admin_user(
config.get("BUILTIN_USERNAME", ""),
config.get("BUILTIN_PASSWORD_HASH", ""),
)
except Exception as exc:
logger.error(
"Failed to sync builtin credentials to users database during migration: "
f"{exc}"
except Exception:
logger.exception(
"Failed to sync builtin credentials to users database during migration"
)
if migrated_security:
ensure_config_dir()
config_path = get_config_path()
with open(config_path, "w") as f:
config_path = Path(get_config_path())
with config_path.open("w") as f:
json.dump(config, f, indent=2)
logger.info("Security settings migration completed successfully")
elif migrated_users:
@@ -119,5 +200,5 @@ def migrate_security_settings(
except FileNotFoundError:
logger.debug("No existing security config file found - nothing to migrate")
except Exception as exc:
logger.error(f"Failed to migrate security settings: {exc}")
except Exception:
logger.exception("Failed to migrate security settings")
+8 -4
View File
@@ -6,10 +6,12 @@ import re
from typing import Any
from urllib.parse import urlsplit
from shelfmark.core.config import config as app_config
from shelfmark.core.notifications import NotificationEvent, send_test_notification
from shelfmark.core.settings_registry import (
ActionButton,
HeadingField,
SettingsField,
TableField,
load_config_file,
register_on_save,
@@ -123,7 +125,7 @@ def _count_invalid_route_urls(routes: list[dict[str, Any]]) -> int:
def _ensure_default_route_row(routes: list[dict[str, Any]]) -> list[dict[str, Any]]:
return routes if routes else [dict(row) for row in _DEFAULT_ROUTE_ROWS]
return routes or [dict(row) for row in _DEFAULT_ROUTE_ROWS]
def _extract_unique_route_urls(routes: list[dict[str, Any]]) -> list[str]:
@@ -141,6 +143,7 @@ def _extract_unique_route_urls(routes: list[dict[str, Any]]) -> list[str]:
def build_notification_test_result(routes_input: Any, *, scope_label: str) -> dict[str, Any]:
"""Validate routes and return a test-notification result payload."""
invalid_event_count = _count_invalid_route_events(routes_input)
if invalid_event_count:
return {
@@ -245,8 +248,9 @@ def _on_save_notifications(values: dict[str, Any]) -> dict[str, Any]:
def _test_admin_notification_action(current_values: dict[str, Any]) -> dict[str, Any]:
persisted = load_config_file("notifications")
effective: dict[str, Any] = dict(persisted)
effective: dict[str, Any] = {
"ADMIN_NOTIFICATION_ROUTES": app_config.get("ADMIN_NOTIFICATION_ROUTES", []),
}
if isinstance(current_values, dict):
effective.update(current_values)
@@ -258,7 +262,7 @@ register_on_save("notifications", _on_save_notifications)
@register_settings("notifications", "Notifications", icon="bell", order=7)
def notifications_settings():
def notifications_settings() -> list[SettingsField]:
"""Global notifications settings."""
return [
HeadingField(
+111 -38
View File
@@ -1,26 +1,32 @@
"""Authentication settings registration."""
from typing import Any, Dict, Callable
from typing import TYPE_CHECKING, Any
from shelfmark.config.migrations import migrate_security_settings
from shelfmark.config.security_handlers import (
check_oidc_connection,
on_save_security,
test_oidc_connection,
)
from shelfmark.core.config import config as app_config
from shelfmark.core.logger import setup_logger
from shelfmark.core.settings_registry import (
register_settings,
register_on_save,
load_config_file,
TextField,
SelectField,
PasswordField,
CheckboxField,
ActionButton,
CheckboxField,
CustomComponentField,
PasswordField,
SelectField,
SettingsField,
TagListField,
TextField,
load_config_file,
register_on_save,
register_settings,
)
from shelfmark.core.user_db import sync_builtin_admin_user
if TYPE_CHECKING:
from collections.abc import Callable
logger = setup_logger(__name__)
@@ -28,25 +34,24 @@ def _auth_condition(auth_method: str) -> dict[str, str]:
return {"field": "AUTH_METHOD", "value": auth_method}
def _ui_field(factory: Callable[..., Any], **kwargs: Any) -> Any:
return factory(env_supported=False, **kwargs)
def _auth_ui_field(factory: Callable[..., Any], auth_method: str, **kwargs: Any) -> Any:
return _ui_field(factory, show_when=_auth_condition(auth_method), **kwargs)
def _auth_field(factory: Callable[..., Any], auth_method: str, **kwargs: Any) -> Any:
return factory(show_when=_auth_condition(auth_method), **kwargs)
def _migrate_security_settings() -> None:
from shelfmark.core.settings_registry import (
_get_config_file_path,
_ensure_config_dir,
_get_config_file_path,
save_config_file,
)
def _save_users_config(values: dict[str, Any]) -> None:
save_config_file("users", values)
migrate_security_settings(
load_security_config=lambda: load_config_file("security"),
load_users_config=lambda: load_config_file("users"),
save_users_config=lambda values: save_config_file("users", values),
save_users_config=_save_users_config,
ensure_config_dir=lambda: _ensure_config_dir("security"),
get_config_path=lambda: _get_config_file_path("security"),
sync_builtin_admin_user=sync_builtin_admin_user,
@@ -54,22 +59,24 @@ def _migrate_security_settings() -> None:
)
def _on_save_security(values: Dict[str, Any]) -> Dict[str, Any]:
def _on_save_security(values: dict[str, Any]) -> dict[str, Any]:
return on_save_security(values)
def _test_oidc_connection() -> Dict[str, Any]:
return test_oidc_connection(
load_security_config=lambda: load_config_file("security"),
def _test_oidc_connection(current_values: dict[str, Any] | None = None) -> dict[str, Any]:
return check_oidc_connection(
load_security_config=lambda: {
"OIDC_DISCOVERY_URL": app_config.get("OIDC_DISCOVERY_URL", ""),
},
current_values=current_values or {},
logger=logger,
)
@register_settings("security", "Security", icon="shield", order=5)
def security_settings():
def security_settings() -> list[SettingsField]:
"""Security and authentication settings."""
from shelfmark.config.env import CWA_DB_PATH
from shelfmark.config.env import CWA_DB_PATH, DISABLE_LOCAL_AUTH
cwa_db_available = CWA_DB_PATH is not None and CWA_DB_PATH.exists()
@@ -78,31 +85,65 @@ def security_settings():
{"label": "Local", "value": "builtin"},
{"label": "Proxy Authentication", "value": "proxy"},
{"label": "OIDC (OpenID Connect)", "value": "oidc"},
{"label": "Calibre-Web Database", "value": "cwa"},
]
if cwa_db_available:
auth_method_options.append({"label": "Calibre-Web Database", "value": "cwa"})
auth_method_description = "Select the authentication method for accessing Shelfmark."
if not cwa_db_available:
auth_method_description += " Calibre-Web database option requires mounting your Calibre-Web app.db to /auth/app.db."
fields = [
SelectField(
key="AUTH_METHOD",
label="Authentication Method",
description=auth_method_description,
description=(
"Select the authentication method for accessing Shelfmark. "
"Restart container after changing Calibre-Web passwords."
),
options=auth_method_options,
default="none",
env_supported=False,
),
CustomComponentField(
key="builtin_admin_requirement",
component="oidc_admin_hint",
label=(
"Local authentication is inactive until a local admin account with a "
"password is created."
),
show_when=_auth_condition("builtin"),
),
*(
[]
if DISABLE_LOCAL_AUTH
else [
CustomComponentField(
key="oidc_admin_requirement",
component="oidc_admin_hint",
label="A local admin account is required before OIDC can be enabled.",
show_when=_auth_condition("oidc"),
),
]
),
*(
[]
if cwa_db_available
else [
CustomComponentField(
key="cwa_db_missing",
component="oidc_admin_hint",
label=(
"Calibre-Web database not detected. Mount your app.db to "
"/auth/app.db to enable this method. Authentication will fall "
"back to none until the database is available."
),
show_when=_auth_condition("cwa"),
),
]
),
ActionButton(
key="open_users_tab",
label="Go to Users",
description="Configure local users and admin access in the Users tab.",
style="primary",
show_when=_auth_condition("builtin"),
show_when={"field": "AUTH_METHOD", "value": ["builtin", "oidc"]},
),
_auth_ui_field(
_auth_field(
TextField,
"proxy",
key="PROXY_AUTH_USER_HEADER",
@@ -111,7 +152,7 @@ def security_settings():
placeholder="e.g. X-Auth-User",
default="X-Auth-User",
),
_auth_ui_field(
_auth_field(
TextField,
"proxy",
key="PROXY_AUTH_LOGOUT_URL",
@@ -120,7 +161,7 @@ def security_settings():
placeholder="https://myauth.example.com/logout",
default="",
),
_auth_ui_field(
_auth_field(
TextField,
"proxy",
key="PROXY_AUTH_ADMIN_GROUP_HEADER",
@@ -129,7 +170,7 @@ def security_settings():
placeholder="e.g. X-Auth-Groups",
default="X-Auth-Groups",
),
_auth_ui_field(
_auth_field(
TextField,
"proxy",
key="PROXY_AUTH_ADMIN_GROUP_NAME",
@@ -138,8 +179,30 @@ def security_settings():
placeholder="e.g. admins",
default="",
),
_auth_field(
SelectField,
"proxy",
key="PROXY_AUTH_DEFAULT_ROLE",
label="Proxy Auth Default Role",
description="Role for users the proxy authenticates for the first time when no admin group is configured. The first account is always an admin so the instance is never left without one.",
options=[
{"value": "user", "label": "User"},
{"value": "admin", "label": "Admin"},
],
default="user",
),
]
fields.append(
CustomComponentField(
key="oidc_callback_url",
component="settings_label",
label="Callback URL",
description="{origin}/api/auth/oidc/callback",
show_when=_auth_condition("oidc"),
)
)
oidc_specs = [
(
TextField,
@@ -228,7 +291,7 @@ def security_settings():
},
),
]
fields.extend(_auth_ui_field(factory, "oidc", **spec) for factory, spec in oidc_specs)
fields.extend(_auth_field(factory, "oidc", **spec) for factory, spec in oidc_specs)
fields.append(
ActionButton(
key="test_oidc",
@@ -239,6 +302,16 @@ def security_settings():
show_when=_auth_condition("oidc"),
)
)
fields.append(
CustomComponentField(
key="oidc_env_info",
component="oidc_env_info",
label="Environment-Only Options",
description="These options can only be set via environment variables because changing them through the UI could lock you out of the application.",
wrap_in_field_wrapper=True,
show_when=_auth_condition("oidc"),
)
)
return fields
+89 -14
View File
@@ -1,20 +1,56 @@
"""Operational handlers for security settings (save/actions)."""
import os
from typing import Any, Callable
from pathlib import Path
from typing import TYPE_CHECKING, Any
from shelfmark.core.utils import normalize_http_url
from shelfmark.config.env import DISABLE_LOCAL_AUTH
from shelfmark.core.user_db import UserDB
from shelfmark.core.utils import normalize_http_url
from shelfmark.download.network import get_ssl_verify
if TYPE_CHECKING:
from collections.abc import Callable
_OIDC_LOCKOUT_MESSAGE = "Create a local admin account first (Users tab) before enabling OIDC. This ensures you can still log in with a password if SSO is unavailable."
_OIDC_LOCKOUT_MESSAGE = "A local admin account with a password is required before enabling OIDC. Use the 'Go to Users' button above to create one. This ensures you can still sign in if your identity provider is unavailable."
_OIDC_REQUIRED_FIELDS = (
("OIDC_DISCOVERY_URL", "Discovery URL"),
("OIDC_CLIENT_ID", "Client ID"),
("OIDC_CLIENT_SECRET", "Client Secret"),
)
def _has_local_password_admin() -> bool:
root = os.environ.get("CONFIG_DIR", "/config")
user_db = UserDB(os.path.join(root, "users.db"))
user_db = UserDB(str(Path(root) / "users.db"))
user_db.initialize()
return any(user.get("password_hash") and user.get("role") == "admin" for user in user_db.list_users())
return any(
user.get("password_hash") and user.get("role") == "admin" for user in user_db.list_users()
)
def _load_effective_security_values(values: dict[str, Any]) -> dict[str, Any]:
"""Merge the current save payload onto the persisted security config."""
from shelfmark.core.settings_registry import load_config_file
effective_values = load_config_file("security")
effective_values.update(values)
return effective_values
def _get_missing_oidc_required_fields(effective_values: dict[str, Any]) -> list[str]:
"""Return missing required OIDC field labels from the effective config."""
missing_fields: list[str] = []
for key, label in _OIDC_REQUIRED_FIELDS:
value = effective_values.get(key)
if value is None:
missing_fields.append(label)
continue
if isinstance(value, str) and not value.strip():
missing_fields.append(label)
return missing_fields
def on_save_security(
@@ -28,6 +64,7 @@ def on_save_security(
normalized_values["OIDC_DISCOVERY_URL"] = normalize_http_url(
str(discovery_url),
default_scheme="https",
strip_trailing_slash=False,
)
proxy_logout_url = normalized_values.get("PROXY_AUTH_LOGOUT_URL")
@@ -38,35 +75,73 @@ def on_save_security(
strip_trailing_slash=False,
)
if normalized_values.get("AUTH_METHOD") == "oidc" and not _has_local_password_admin():
return {"error": True, "message": _OIDC_LOCKOUT_MESSAGE, "values": normalized_values}
effective_values = _load_effective_security_values(normalized_values)
auth_method = str(effective_values.get("AUTH_METHOD", "") or "").strip().lower()
if auth_method == "oidc":
if not DISABLE_LOCAL_AUTH and not _has_local_password_admin():
return {"error": True, "message": _OIDC_LOCKOUT_MESSAGE, "values": normalized_values}
missing_fields = _get_missing_oidc_required_fields(effective_values)
if missing_fields:
missing_fields_text = ", ".join(missing_fields)
return {
"error": True,
"message": f"OIDC configuration is incomplete: missing {missing_fields_text}.",
"values": normalized_values,
}
return {"error": False, "values": normalized_values}
def test_oidc_connection(
def check_oidc_connection(
*,
load_security_config: Callable[[], dict[str, Any]],
current_values: dict[str, Any] | None = None,
logger: Any,
) -> dict[str, Any]:
"""Fetch and validate the configured OIDC discovery document."""
import requests
try:
discovery_url = load_security_config().get("OIDC_DISCOVERY_URL", "")
# Prefer the current (unsaved) form value over the saved config
discovery_url = (current_values or {}).get(
"OIDC_DISCOVERY_URL"
) or load_security_config().get("OIDC_DISCOVERY_URL", "")
if not discovery_url:
return {"success": False, "message": "Discovery URL is not configured."}
response = requests.get(discovery_url, timeout=10)
response = requests.get(discovery_url, timeout=10, verify=get_ssl_verify(discovery_url))
response.raise_for_status()
document = response.json()
required_fields = ["issuer", "authorization_endpoint", "token_endpoint"]
required_fields = ["issuer", "authorization_endpoint", "token_endpoint", "jwks_uri"]
missing_fields = [field for field in required_fields if field not in document]
if missing_fields:
return {"success": False, "message": f"Discovery document missing fields: {', '.join(missing_fields)}"}
return {
"success": False,
"message": f"Discovery document missing fields: {', '.join(missing_fields)}",
}
# Logins verify the ID token against the provider's JWKS, so an empty key
# set (e.g. an Authentik provider with no Signing Key selected) means every
# login will fail even though discovery looks healthy.
jwks_uri = str(document["jwks_uri"])
jwks_response = requests.get(jwks_uri, timeout=10, verify=get_ssl_verify(jwks_uri))
jwks_response.raise_for_status()
jwks_document = jwks_response.json()
jwks_keys = jwks_document.get("keys") if isinstance(jwks_document, dict) else None
if not jwks_keys:
return {
"success": False,
"message": (
"Discovery document is valid, but the provider returned no token "
"signing keys (empty JWKS), so logins will fail. If you use "
"Authentik, select a Signing Key in the provider settings."
),
}
return {"success": True, "message": f"Connected to {document['issuer']}"}
except Exception as exc:
logger.error(f"OIDC connection test failed: {exc}")
return {"success": False, "message": f"Connection failed: {str(exc)}"}
logger.exception("OIDC connection test failed")
return {"success": False, "message": f"Connection failed: {exc!s}"}
File diff suppressed because it is too large Load Diff
+178 -50
View File
@@ -5,6 +5,14 @@ The actual user management is handled by a custom frontend component
that talks to /api/admin/users endpoints.
"""
from typing import Any
from shelfmark.core.languages import normalize_language
from shelfmark.core.request_policy import (
get_source_content_type_capabilities,
parse_policy_mode,
validate_policy_rules,
)
from shelfmark.core.settings_registry import (
CheckboxField,
CustomComponentField,
@@ -12,16 +20,11 @@ from shelfmark.core.settings_registry import (
MultiSelectField,
NumberField,
SelectField,
SettingsField,
TableField,
register_on_save,
register_settings,
)
from shelfmark.core.request_policy import (
get_source_content_type_capabilities,
parse_policy_mode,
validate_policy_rules,
)
_REQUEST_DEFAULT_MODE_OPTIONS = [
{
@@ -56,6 +59,11 @@ _SELF_SETTINGS_SECTION_OPTIONS = [
"label": "Delivery Preferences",
"description": "Show personal delivery output and destination settings.",
},
{
"value": "search",
"label": "Search Preferences",
"description": "Show personal search mode, language, and provider settings.",
},
{
"value": "notifications",
"label": "Notifications",
@@ -64,6 +72,21 @@ _SELF_SETTINGS_SECTION_OPTIONS = [
]
_SELF_SETTINGS_SECTION_VALUES = {option["value"] for option in _SELF_SETTINGS_SECTION_OPTIONS}
_SELF_SETTINGS_SECTION_DEFAULTS = [option["value"] for option in _SELF_SETTINGS_SECTION_OPTIONS]
_SEARCH_MODE_VALUES = {"direct", "universal"}
_SEARCH_PREFERENCE_PROVIDER_KEYS = {
"METADATA_PROVIDER",
"METADATA_PROVIDER_AUDIOBOOK",
"METADATA_PROVIDER_COMBINED",
}
SEARCH_PREFERENCE_VALIDATABLE_KEYS = {
"SEARCH_MODE",
"BOOK_LANGUAGE",
"DEFAULT_RELEASE_SOURCE",
"DEFAULT_RELEASE_SOURCE_AUDIOBOOK",
"SHOW_COMBINED_SELECTOR",
"FORCE_COMBINED_SEARCH",
*_SEARCH_PREFERENCE_PROVIDER_KEYS,
}
_USERS_HEADING_DESCRIPTION_BY_AUTH_MODE = {
"builtin": (
@@ -88,35 +111,45 @@ _USERS_HEADING_DESCRIPTION_BY_AUTH_MODE = {
}
def _get_request_source_options():
def _get_request_source_options() -> list[dict[str, str]]:
"""Build request-policy source options from registered release sources."""
from shelfmark.release_sources import list_available_sources
options = []
return [
{
"value": source["name"],
"label": source["display_name"],
}
for source in list_available_sources()
]
def _get_valid_release_source_names_for_content_type(content_type: str) -> set[str]:
"""Return registered release source names that support the requested content type."""
from shelfmark.release_sources import list_available_sources
valid_sources: set[str] = set()
for source in list_available_sources():
options.append(
{
"value": source["name"],
"label": source["display_name"],
}
)
return options
supported_types = source.get("supported_content_types", ["ebook", "audiobook"])
if content_type in supported_types:
valid_sources.add(source["name"])
return valid_sources
def _get_request_policy_rule_columns():
def _get_request_policy_rule_columns() -> list[dict[str, object]]:
source_capabilities = get_source_content_type_capabilities()
content_type_options = []
for source_name, supported_types in source_capabilities.items():
normalized_types = [t for t in ("ebook", "audiobook") if t in supported_types]
for content_type in normalized_types:
content_type_options.append(
{
"value": content_type,
"label": "Ebook" if content_type == "ebook" else "Audiobook",
"childOf": source_name,
}
)
content_type_options.extend(
{
"value": content_type,
"label": "Ebook" if content_type == "ebook" else "Audiobook",
"childOf": source_name,
}
for content_type in normalized_types
)
return [
{
@@ -147,7 +180,90 @@ def _get_request_policy_rule_columns():
]
def _on_save_users(values):
def _validate_book_languages(value: Any) -> tuple[Any, str | None]:
"""Validate a per-user default language list against the known languages.
Accepts the list the settings UI sends as well as a comma-separated string, so an
API client can spell the value the way the env var does. Blank entries are skipped
rather than rejected, which makes "" and "en," mean the same as [] and ["en"]. An
empty result is a deliberate override meaning "no default language filter", so it
is kept as-is; ``None`` clears the override further up the chain.
"""
entries = value.split(",") if isinstance(value, str) else value
if not isinstance(entries, (list, tuple)):
return value, "BOOK_LANGUAGE must be a list of language codes"
normalized: list[str] = []
for entry in entries:
if entry is None or (isinstance(entry, str) and not entry.strip()):
continue
code = normalize_language(entry)
if code is None:
return value, f"BOOK_LANGUAGE contains an unsupported language: {entry}"
if code not in normalized:
normalized.append(code)
return normalized, None
def validate_search_preference_value(key: str, value: Any) -> tuple[Any, str | None]:
"""Validate and normalize a search preference value for user overrides."""
if key not in SEARCH_PREFERENCE_VALIDATABLE_KEYS:
return value, None
if value is None:
return None, None
if key == "BOOK_LANGUAGE":
return _validate_book_languages(value)
normalized_value = str(value).strip()
if key == "SEARCH_MODE":
normalized_mode = normalized_value.lower()
if normalized_mode not in _SEARCH_MODE_VALUES:
return value, "SEARCH_MODE must be 'direct' or 'universal'"
return normalized_mode, None
if key in _SEARCH_PREFERENCE_PROVIDER_KEYS:
if normalized_value == "":
return "", None
from shelfmark.metadata_providers import is_provider_registered
if not is_provider_registered(normalized_value):
return (
value,
f"{key} must be a valid metadata provider name or empty",
)
return normalized_value, None
if key in {"DEFAULT_RELEASE_SOURCE", "DEFAULT_RELEASE_SOURCE_AUDIOBOOK"}:
if normalized_value == "":
return "", None
valid_sources = _get_valid_release_source_names_for_content_type(
"audiobook" if key == "DEFAULT_RELEASE_SOURCE_AUDIOBOOK" else "ebook"
)
if normalized_value not in valid_sources:
return (
value,
f"{key} must be a valid release source name or empty",
)
return normalized_value, None
if key == "SHOW_COMBINED_SELECTOR":
if isinstance(value, bool):
return value, None
return bool(value), None
if key == "FORCE_COMBINED_SEARCH":
if isinstance(value, bool):
return value, None
return bool(value), None
return value, None
def _on_save_users(values: dict[str, object]) -> dict[str, object]:
"""Validate users/request-policy settings before persistence."""
if "VISIBLE_SELF_SETTINGS_SECTIONS" in values:
raw_sections = values["VISIBLE_SELF_SETTINGS_SECTIONS"]
@@ -156,7 +272,9 @@ def _on_save_users(values):
elif isinstance(raw_sections, str):
candidate_sections = [s.strip() for s in raw_sections.split(",") if s.strip()]
elif isinstance(raw_sections, (list, tuple, set)):
candidate_sections = [str(section).strip() for section in raw_sections if str(section).strip()]
candidate_sections = [
str(section).strip() for section in raw_sections if str(section).strip()
]
else:
return {
"error": True,
@@ -181,21 +299,25 @@ def _on_save_users(values):
values["VISIBLE_SELF_SETTINGS_SECTIONS"] = normalized_sections
if "REQUEST_POLICY_DEFAULT_EBOOK" in values:
if parse_policy_mode(values["REQUEST_POLICY_DEFAULT_EBOOK"]) is None:
return {
"error": True,
"message": "REQUEST_POLICY_DEFAULT_EBOOK must be a valid policy mode",
"values": values,
}
if (
"REQUEST_POLICY_DEFAULT_EBOOK" in values
and parse_policy_mode(values["REQUEST_POLICY_DEFAULT_EBOOK"]) is None
):
return {
"error": True,
"message": "REQUEST_POLICY_DEFAULT_EBOOK must be a valid policy mode",
"values": values,
}
if "REQUEST_POLICY_DEFAULT_AUDIOBOOK" in values:
if parse_policy_mode(values["REQUEST_POLICY_DEFAULT_AUDIOBOOK"]) is None:
return {
"error": True,
"message": "REQUEST_POLICY_DEFAULT_AUDIOBOOK must be a valid policy mode",
"values": values,
}
if (
"REQUEST_POLICY_DEFAULT_AUDIOBOOK" in values
and parse_policy_mode(values["REQUEST_POLICY_DEFAULT_AUDIOBOOK"]) is None
):
return {
"error": True,
"message": "REQUEST_POLICY_DEFAULT_AUDIOBOOK must be a valid policy mode",
"values": values,
}
if "REQUEST_POLICY_RULES" in values:
normalized_rules, errors = validate_policy_rules(values["REQUEST_POLICY_RULES"])
@@ -207,6 +329,18 @@ def _on_save_users(values):
}
values["REQUEST_POLICY_RULES"] = normalized_rules
for key in SEARCH_PREFERENCE_VALIDATABLE_KEYS:
if key not in values:
continue
normalized_value, validation_error = validate_search_preference_value(key, values[key])
if validation_error:
return {
"error": True,
"message": validation_error,
"values": values,
}
values[key] = normalized_value
return {"error": False, "values": values}
@@ -214,7 +348,7 @@ register_on_save("users", _on_save_users)
@register_settings("users", "Users & Requests", icon="users", order=6)
def users_settings():
def users_settings() -> list[SettingsField]:
"""User management tab - rendered as a custom component on the frontend."""
return [
HeadingField(
@@ -241,9 +375,7 @@ def users_settings():
HeadingField(
key="requests_heading",
title="Requests",
description=(
"Choose what users can download directly and what needs approval first."
),
description=("Choose what users can download directly and what needs approval first."),
),
CheckboxField(
key="REQUESTS_ENABLED",
@@ -267,9 +399,7 @@ def users_settings():
SelectField(
key="REQUEST_POLICY_DEFAULT_EBOOK",
label="Default Ebook Mode",
description=(
"Sets the baseline for all ebook sources."
),
description=("Sets the baseline for all ebook sources."),
options=_REQUEST_DEFAULT_MODE_OPTIONS,
default="download",
user_overridable=True,
@@ -277,9 +407,7 @@ def users_settings():
SelectField(
key="REQUEST_POLICY_DEFAULT_AUDIOBOOK",
label="Default Audiobook Mode",
description=(
"Sets the baseline for all audiobook sources."
),
description=("Sets the baseline for all audiobook sources."),
options=_REQUEST_DEFAULT_MODE_OPTIONS,
default="download",
user_overridable=True,
+11 -2
View File
@@ -1,5 +1,14 @@
"""Core module - shared models, queue, and utilities."""
from shelfmark.core.models import BookInfo, QueueItem, SearchFilters, QueueStatus
from shelfmark.core.queue import BookQueue, book_queue
from shelfmark.core.logger import setup_logger
from shelfmark.core.models import QueueItem, QueueStatus, SearchFilters
from shelfmark.core.queue import BookQueue, book_queue
__all__ = [
"BookQueue",
"QueueItem",
"QueueStatus",
"SearchFilters",
"book_queue",
"setup_logger",
]
File diff suppressed because it is too large Load Diff
-618
View File
@@ -1,618 +0,0 @@
"""Persistence helpers for Activity dismissals and terminal snapshots."""
from __future__ import annotations
from datetime import datetime, timezone
import json
import sqlite3
from typing import Any, Iterable
VALID_ITEM_TYPES = frozenset({"download", "request"})
VALID_ORIGINS = frozenset({"direct", "request", "requested"})
VALID_FINAL_STATUSES = frozenset({"complete", "error", "cancelled", "rejected"})
def _now_timestamp() -> str:
return datetime.now(timezone.utc).isoformat(timespec="seconds")
def _normalize_item_type(item_type: Any) -> str:
if not isinstance(item_type, str):
raise ValueError("item_type must be a string")
normalized = item_type.strip().lower()
if normalized not in VALID_ITEM_TYPES:
raise ValueError("item_type must be one of: download, request")
return normalized
def _normalize_item_key(item_key: Any) -> str:
if not isinstance(item_key, str):
raise ValueError("item_key must be a string")
normalized = item_key.strip()
if not normalized:
raise ValueError("item_key must not be empty")
return normalized
def _normalize_origin(origin: Any) -> str:
if not isinstance(origin, str):
raise ValueError("origin must be a string")
normalized = origin.strip().lower()
if normalized not in VALID_ORIGINS:
raise ValueError("origin must be one of: direct, request, requested")
return normalized
def _normalize_final_status(final_status: Any) -> str:
if not isinstance(final_status, str):
raise ValueError("final_status must be a string")
normalized = final_status.strip().lower()
if normalized not in VALID_FINAL_STATUSES:
raise ValueError("final_status must be one of: complete, error, cancelled, rejected")
return normalized
def build_item_key(item_type: str, raw_id: Any) -> str:
"""Build a stable item key used by dismiss/history APIs."""
normalized_type = _normalize_item_type(item_type)
if normalized_type == "request":
try:
request_id = int(raw_id)
except (TypeError, ValueError) as exc:
raise ValueError("request item IDs must be integers") from exc
if request_id < 1:
raise ValueError("request item IDs must be positive integers")
return f"request:{request_id}"
if not isinstance(raw_id, str):
raise ValueError("download item IDs must be strings")
task_id = raw_id.strip()
if not task_id:
raise ValueError("download item IDs must not be empty")
return f"download:{task_id}"
def build_request_item_key(request_id: int) -> str:
"""Build a request item key."""
return build_item_key("request", request_id)
def build_download_item_key(task_id: str) -> str:
"""Build a download item key."""
return build_item_key("download", task_id)
def _parse_request_id_from_item_key(item_key: Any) -> int | None:
if not isinstance(item_key, str) or not item_key.startswith("request:"):
return None
raw_value = item_key.split(":", 1)[1].strip()
try:
parsed = int(raw_value)
except (TypeError, ValueError):
return None
return parsed if parsed > 0 else None
def _request_final_status(request_status: Any, delivery_state: Any) -> str | None:
status = str(request_status or "").strip().lower()
if status == "pending":
return None
if status == "rejected":
return "rejected"
if status == "cancelled":
return "cancelled"
if status != "fulfilled":
return None
delivery = str(delivery_state or "").strip().lower()
if delivery in {"error", "cancelled"}:
return delivery
return "complete"
class ActivityService:
"""Service for per-user activity dismissals and terminal history snapshots."""
def __init__(self, db_path: str):
self._db_path = db_path
def _connect(self) -> sqlite3.Connection:
conn = sqlite3.connect(self._db_path)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
return conn
@staticmethod
def _coerce_positive_int(value: Any, field: str) -> int:
try:
parsed = int(value)
except (TypeError, ValueError) as exc:
raise ValueError(f"{field} must be an integer") from exc
if parsed < 1:
raise ValueError(f"{field} must be a positive integer")
return parsed
@staticmethod
def _row_to_dict(row: sqlite3.Row | None) -> dict[str, Any] | None:
return dict(row) if row is not None else None
@staticmethod
def _parse_json_column(value: Any) -> Any:
if not isinstance(value, str):
return None
try:
return json.loads(value)
except (ValueError, TypeError):
return None
def _build_legacy_request_snapshot(
self,
conn: sqlite3.Connection,
request_id: int,
) -> tuple[dict[str, Any] | None, str | None]:
request_row = conn.execute(
"""
SELECT
id,
user_id,
status,
delivery_state,
request_level,
book_data,
release_data,
note,
admin_note,
created_at,
reviewed_at
FROM download_requests
WHERE id = ?
""",
(request_id,),
).fetchone()
if request_row is None:
return None, None
row_dict = dict(request_row)
book_data = self._parse_json_column(row_dict.get("book_data"))
release_data = self._parse_json_column(row_dict.get("release_data"))
if not isinstance(book_data, dict):
book_data = {}
if not isinstance(release_data, dict):
release_data = {}
snapshot = {
"kind": "request",
"request": {
"id": int(row_dict["id"]),
"user_id": row_dict.get("user_id"),
"status": row_dict.get("status"),
"delivery_state": row_dict.get("delivery_state"),
"request_level": row_dict.get("request_level"),
"book_data": book_data,
"release_data": release_data,
"note": row_dict.get("note"),
"admin_note": row_dict.get("admin_note"),
"created_at": row_dict.get("created_at"),
"updated_at": row_dict.get("reviewed_at") or row_dict.get("created_at"),
},
}
final_status = _request_final_status(row_dict.get("status"), row_dict.get("delivery_state"))
return snapshot, final_status
def record_terminal_snapshot(
self,
*,
user_id: int | None,
item_type: str,
item_key: str,
origin: str,
final_status: str,
snapshot: dict[str, Any],
request_id: int | None = None,
source_id: str | None = None,
terminal_at: str | None = None,
) -> dict[str, Any]:
"""Record a durable terminal-state snapshot for an activity item."""
normalized_item_type = _normalize_item_type(item_type)
normalized_item_key = _normalize_item_key(item_key)
normalized_origin = _normalize_origin(origin)
normalized_final_status = _normalize_final_status(final_status)
if not isinstance(snapshot, dict):
raise ValueError("snapshot must be an object")
if user_id is not None:
user_id = self._coerce_positive_int(user_id, "user_id")
if request_id is not None:
request_id = self._coerce_positive_int(request_id, "request_id")
if source_id is not None and not isinstance(source_id, str):
raise ValueError("source_id must be a string when provided")
if source_id is not None:
source_id = source_id.strip() or None
effective_terminal_at = terminal_at if isinstance(terminal_at, str) and terminal_at.strip() else _now_timestamp()
serialized_snapshot = json.dumps(snapshot, separators=(",", ":"), ensure_ascii=False)
conn = self._connect()
try:
cursor = conn.execute(
"""
INSERT INTO activity_log (
user_id,
item_type,
item_key,
request_id,
source_id,
origin,
final_status,
snapshot_json,
terminal_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
user_id,
normalized_item_type,
normalized_item_key,
request_id,
source_id,
normalized_origin,
normalized_final_status,
serialized_snapshot,
effective_terminal_at,
),
)
snapshot_id = int(cursor.lastrowid)
conn.commit()
row = conn.execute(
"SELECT * FROM activity_log WHERE id = ?",
(snapshot_id,),
).fetchone()
payload = self._row_to_dict(row)
if payload is None:
raise ValueError("Failed to read back recorded activity snapshot")
return payload
finally:
conn.close()
def get_latest_activity_log_id(self, *, item_type: str, item_key: str) -> int | None:
"""Get the newest snapshot ID for an item key."""
normalized_item_type = _normalize_item_type(item_type)
normalized_item_key = _normalize_item_key(item_key)
conn = self._connect()
try:
row = conn.execute(
"""
SELECT id
FROM activity_log
WHERE item_type = ? AND item_key = ?
ORDER BY terminal_at DESC, id DESC
LIMIT 1
""",
(normalized_item_type, normalized_item_key),
).fetchone()
if row is None:
return None
return int(row["id"])
finally:
conn.close()
def dismiss_item(
self,
*,
user_id: int,
item_type: str,
item_key: str,
activity_log_id: int | None = None,
) -> dict[str, Any]:
"""Dismiss an item for a specific user (upsert)."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
normalized_item_type = _normalize_item_type(item_type)
normalized_item_key = _normalize_item_key(item_key)
normalized_log_id = (
self._coerce_positive_int(activity_log_id, "activity_log_id")
if activity_log_id is not None
else self.get_latest_activity_log_id(
item_type=normalized_item_type,
item_key=normalized_item_key,
)
)
conn = self._connect()
try:
conn.execute(
"""
INSERT INTO activity_dismissals (
user_id,
item_type,
item_key,
activity_log_id,
dismissed_at
)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(user_id, item_type, item_key)
DO UPDATE SET
activity_log_id = excluded.activity_log_id,
dismissed_at = excluded.dismissed_at
""",
(
normalized_user_id,
normalized_item_type,
normalized_item_key,
normalized_log_id,
_now_timestamp(),
),
)
conn.commit()
row = conn.execute(
"""
SELECT *
FROM activity_dismissals
WHERE user_id = ? AND item_type = ? AND item_key = ?
""",
(normalized_user_id, normalized_item_type, normalized_item_key),
).fetchone()
payload = self._row_to_dict(row)
if payload is None:
raise ValueError("Failed to read back dismissal row")
return payload
finally:
conn.close()
def dismiss_many(self, *, user_id: int, items: Iterable[dict[str, Any]]) -> int:
"""Dismiss many items for one user."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
normalized_items: list[tuple[str, str, int | None]] = []
for item in items:
if not isinstance(item, dict):
raise ValueError("items must contain objects")
normalized_item_type = _normalize_item_type(item.get("item_type"))
normalized_item_key = _normalize_item_key(item.get("item_key"))
raw_log_id = item.get("activity_log_id")
normalized_log_id = (
self._coerce_positive_int(raw_log_id, "activity_log_id")
if raw_log_id is not None
else self.get_latest_activity_log_id(
item_type=normalized_item_type,
item_key=normalized_item_key,
)
)
normalized_items.append((normalized_item_type, normalized_item_key, normalized_log_id))
if not normalized_items:
return 0
conn = self._connect()
try:
timestamp = _now_timestamp()
for item_type, item_key, activity_log_id in normalized_items:
conn.execute(
"""
INSERT INTO activity_dismissals (
user_id,
item_type,
item_key,
activity_log_id,
dismissed_at
)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(user_id, item_type, item_key)
DO UPDATE SET
activity_log_id = excluded.activity_log_id,
dismissed_at = excluded.dismissed_at
""",
(
normalized_user_id,
item_type,
item_key,
activity_log_id,
timestamp,
),
)
conn.commit()
return len(normalized_items)
finally:
conn.close()
def get_dismissal_set(self, user_id: int) -> list[dict[str, str]]:
"""Return dismissed item keys for one user."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
conn = self._connect()
try:
rows = conn.execute(
"""
SELECT item_type, item_key
FROM activity_dismissals
WHERE user_id = ?
ORDER BY dismissed_at DESC, id DESC
""",
(normalized_user_id,),
).fetchall()
return [
{
"item_type": str(row["item_type"]),
"item_key": str(row["item_key"]),
}
for row in rows
]
finally:
conn.close()
def clear_dismissals_for_item_keys(
self,
*,
user_id: int,
item_type: str,
item_keys: Iterable[str],
) -> int:
"""Clear dismissals for one user + item type + item keys."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
normalized_item_type = _normalize_item_type(item_type)
normalized_keys = {
_normalize_item_key(item_key)
for item_key in item_keys
if isinstance(item_key, str) and item_key.strip()
}
if not normalized_keys:
return 0
conn = self._connect()
try:
cursor = conn.executemany(
"""
DELETE FROM activity_dismissals
WHERE user_id = ? AND item_type = ? AND item_key = ?
""",
(
(normalized_user_id, normalized_item_type, item_key)
for item_key in normalized_keys
),
)
conn.commit()
return int(cursor.rowcount or 0)
finally:
conn.close()
def get_history(self, user_id: int, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
"""Return paged dismissal history for one user."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
normalized_limit = max(1, min(int(limit), 200))
normalized_offset = max(0, int(offset))
conn = self._connect()
try:
rows = conn.execute(
"""
SELECT
d.id,
d.user_id,
d.item_type,
d.item_key,
d.activity_log_id,
d.dismissed_at,
l.snapshot_json,
l.origin,
l.final_status,
l.terminal_at,
l.request_id,
l.source_id
FROM activity_dismissals d
LEFT JOIN activity_log l ON l.id = d.activity_log_id
WHERE d.user_id = ?
ORDER BY d.dismissed_at DESC, d.id DESC
LIMIT ? OFFSET ?
""",
(normalized_user_id, normalized_limit, normalized_offset),
).fetchall()
payload: list[dict[str, Any]] = []
for row in rows:
row_dict = dict(row)
raw_snapshot_json = row_dict.pop("snapshot_json", None)
snapshot_payload = None
if isinstance(raw_snapshot_json, str):
try:
snapshot_payload = json.loads(raw_snapshot_json)
except (ValueError, TypeError):
snapshot_payload = None
if snapshot_payload is None and row_dict.get("item_type") == "request":
request_id = row_dict.get("request_id")
if request_id is None:
request_id = _parse_request_id_from_item_key(row_dict.get("item_key"))
try:
normalized_request_id = int(request_id) if request_id is not None else None
except (TypeError, ValueError):
normalized_request_id = None
if normalized_request_id and normalized_request_id > 0:
fallback_snapshot, fallback_final_status = self._build_legacy_request_snapshot(
conn,
normalized_request_id,
)
if fallback_snapshot is not None:
snapshot_payload = fallback_snapshot
if not row_dict.get("origin"):
row_dict["origin"] = "request"
if not row_dict.get("final_status") and fallback_final_status is not None:
row_dict["final_status"] = fallback_final_status
row_dict["snapshot"] = snapshot_payload
payload.append(row_dict)
return payload
finally:
conn.close()
def get_undismissed_terminal_downloads(self, user_id: int, *, limit: int = 200) -> list[dict[str, Any]]:
"""Return latest undismissed terminal download snapshots for one user."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
normalized_limit = max(1, min(int(limit), 500))
conn = self._connect()
try:
rows = conn.execute(
"""
SELECT
l.id,
l.user_id,
l.item_type,
l.item_key,
l.request_id,
l.source_id,
l.origin,
l.final_status,
l.snapshot_json,
l.terminal_at
FROM activity_log l
LEFT JOIN activity_dismissals d
ON d.user_id = ?
AND d.item_type = l.item_type
AND d.item_key = l.item_key
WHERE l.user_id = ?
AND l.item_type = 'download'
AND l.final_status IN ('complete', 'error', 'cancelled')
AND d.id IS NULL
ORDER BY l.terminal_at DESC, l.id DESC
LIMIT ?
""",
(normalized_user_id, normalized_user_id, normalized_limit * 2),
).fetchall()
payload: list[dict[str, Any]] = []
seen_item_keys: set[str] = set()
for row in rows:
row_dict = dict(row)
item_key = str(row_dict.get("item_key") or "")
if not item_key or item_key in seen_item_keys:
continue
seen_item_keys.add(item_key)
raw_snapshot_json = row_dict.pop("snapshot_json", None)
snapshot_payload = None
if isinstance(raw_snapshot_json, str):
try:
snapshot_payload = json.loads(raw_snapshot_json)
except (ValueError, TypeError):
snapshot_payload = None
row_dict["snapshot"] = snapshot_payload
payload.append(row_dict)
if len(payload) >= normalized_limit:
break
return payload
finally:
conn.close()
def clear_history(self, user_id: int) -> int:
"""Delete all dismissals for a user and return deleted row count."""
normalized_user_id = self._coerce_positive_int(user_id, "user_id")
conn = self._connect()
try:
cursor = conn.execute(
"DELETE FROM activity_dismissals WHERE user_id = ?",
(normalized_user_id,),
)
conn.commit()
return int(cursor.rowcount or 0)
finally:
conn.close()
@@ -0,0 +1,327 @@
"""Persistence helpers for per-viewer activity visibility state."""
from __future__ import annotations
import sqlite3
import threading
from typing import Any
from shelfmark.core.request_helpers import now_utc_iso
VALID_ACTIVITY_ITEM_TYPES = frozenset({"download", "request"})
ADMIN_VIEWER_SCOPE = "admin:shared"
NOAUTH_VIEWER_SCOPE = "noauth:shared"
USER_VIEWER_SCOPE_PREFIX = "user:"
def user_viewer_scope(user_id: int) -> str:
"""Build the persisted viewer scope string for a specific user."""
if not isinstance(user_id, int) or user_id < 1:
msg = "user_id must be a positive integer"
raise ValueError(msg)
return f"{USER_VIEWER_SCOPE_PREFIX}{user_id}"
def normalize_viewer_scope(viewer_scope: object) -> str:
"""Validate and normalize a persisted viewer scope string."""
if not isinstance(viewer_scope, str) or not viewer_scope.strip():
msg = "viewer_scope must be a non-empty string"
raise ValueError(msg)
normalized = viewer_scope.strip()
if normalized in {ADMIN_VIEWER_SCOPE, NOAUTH_VIEWER_SCOPE}:
return normalized
if not normalized.startswith(USER_VIEWER_SCOPE_PREFIX):
msg = "viewer_scope must be one of: admin:shared, noauth:shared, or user:<id>"
raise ValueError(msg)
raw_user_id = normalized[len(USER_VIEWER_SCOPE_PREFIX) :].strip()
try:
parsed_user_id = int(raw_user_id)
except (TypeError, ValueError) as exc:
msg = "viewer_scope user id must be a positive integer"
raise ValueError(msg) from exc
return user_viewer_scope(parsed_user_id)
def _normalize_item_type(item_type: object) -> str:
if not isinstance(item_type, str) or not item_type.strip():
msg = "item_type must be a non-empty string"
raise ValueError(msg)
normalized = item_type.strip().lower()
if normalized not in VALID_ACTIVITY_ITEM_TYPES:
msg = "item_type must be one of: download, request"
raise ValueError(msg)
return normalized
def _normalize_item_key(item_key: object, *, item_type: str) -> str:
if not isinstance(item_key, str) or not item_key.strip():
msg = "item_key must be a non-empty string"
raise ValueError(msg)
normalized = item_key.strip()
expected_prefix = f"{item_type}:"
if not normalized.startswith(expected_prefix):
msg_0 = f"item_key must be in the format {expected_prefix}<id>"
raise ValueError(msg_0)
if not normalized.split(":", 1)[1].strip():
msg_0 = f"item_key must be in the format {expected_prefix}<id>"
raise ValueError(msg_0)
return normalized
class ActivityViewStateService:
"""Service for per-viewer activity dismissal and history visibility."""
def __init__(self, db_path: str) -> None:
"""Initialize the service with the SQLite state database path."""
self._db_path = db_path
self._lock = threading.Lock()
def _connect(self) -> sqlite3.Connection:
conn = sqlite3.connect(self._db_path)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
return conn
def list_hidden(
self,
*,
viewer_scope: str,
limit: int | None = None,
) -> list[dict[str, Any]]:
"""Return dismissed rows for a viewer, including cleared history entries."""
normalized_scope = normalize_viewer_scope(viewer_scope)
normalized_limit = None if limit is None else max(1, int(limit))
query = """
SELECT item_type, item_key, dismissed_at, cleared_at
FROM activity_view_state
WHERE viewer_scope = ?
AND dismissed_at IS NOT NULL
ORDER BY COALESCE(cleared_at, dismissed_at) DESC, id DESC
"""
params: list[Any] = [normalized_scope]
if normalized_limit is not None:
query += "\nLIMIT ?"
params.append(normalized_limit)
conn = self._connect()
try:
rows = conn.execute(query, params).fetchall()
return [dict(row) for row in rows]
finally:
conn.close()
def list_history(
self,
*,
viewer_scope: str,
limit: int = 50,
offset: int = 0,
) -> list[dict[str, Any]]:
"""Return active dismissal history rows for a viewer."""
normalized_scope = normalize_viewer_scope(viewer_scope)
normalized_limit = max(1, min(int(limit), 5000))
normalized_offset = max(0, int(offset))
conn = self._connect()
try:
rows = conn.execute(
"""
SELECT item_type, item_key, dismissed_at
FROM activity_view_state
WHERE viewer_scope = ?
AND dismissed_at IS NOT NULL
AND cleared_at IS NULL
ORDER BY dismissed_at DESC, id DESC
LIMIT ? OFFSET ?
""",
(normalized_scope, normalized_limit, normalized_offset),
).fetchall()
return [dict(row) for row in rows]
finally:
conn.close()
def dismiss(
self,
*,
viewer_scope: str,
item_type: str,
item_key: str,
) -> int:
"""Mark a single activity item as dismissed for a viewer."""
normalized_scope = normalize_viewer_scope(viewer_scope)
normalized_type = _normalize_item_type(item_type)
normalized_key = _normalize_item_key(item_key, item_type=normalized_type)
dismissed_at = now_utc_iso()
with self._lock:
conn = self._connect()
try:
cursor = conn.execute(
"""
INSERT INTO activity_view_state (
viewer_scope,
item_type,
item_key,
dismissed_at,
cleared_at
)
VALUES (?, ?, ?, ?, NULL)
ON CONFLICT(viewer_scope, item_type, item_key) DO UPDATE SET
dismissed_at = excluded.dismissed_at,
cleared_at = NULL
""",
(normalized_scope, normalized_type, normalized_key, dismissed_at),
)
conn.commit()
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
return max(rowcount, 0)
finally:
conn.close()
def dismiss_many(
self,
*,
viewer_scope: str,
items: list[dict[str, str]],
) -> int:
"""Mark multiple activity items as dismissed for a viewer."""
normalized_scope = normalize_viewer_scope(viewer_scope)
if not items:
return 0
seen: set[tuple[str, str]] = set()
normalized_items: list[tuple[str, str]] = []
for item in items:
normalized_type = _normalize_item_type(item.get("item_type"))
normalized_key = _normalize_item_key(item.get("item_key"), item_type=normalized_type)
marker = (normalized_type, normalized_key)
if marker in seen:
continue
seen.add(marker)
normalized_items.append(marker)
if not normalized_items:
return 0
dismissed_at = now_utc_iso()
with self._lock:
conn = self._connect()
try:
total = 0
for normalized_type, normalized_key in normalized_items:
cursor = conn.execute(
"""
INSERT INTO activity_view_state (
viewer_scope,
item_type,
item_key,
dismissed_at,
cleared_at
)
VALUES (?, ?, ?, ?, NULL)
ON CONFLICT(viewer_scope, item_type, item_key) DO UPDATE SET
dismissed_at = excluded.dismissed_at,
cleared_at = NULL
""",
(
normalized_scope,
normalized_type,
normalized_key,
dismissed_at,
),
)
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
total += max(rowcount, 0)
conn.commit()
return total
finally:
conn.close()
def clear_history(self, *, viewer_scope: str) -> int:
"""Mark all dismissed items as cleared for a viewer."""
normalized_scope = normalize_viewer_scope(viewer_scope)
cleared_at = now_utc_iso()
with self._lock:
conn = self._connect()
try:
cursor = conn.execute(
"""
UPDATE activity_view_state
SET cleared_at = ?
WHERE viewer_scope = ?
AND dismissed_at IS NOT NULL
AND cleared_at IS NULL
""",
(cleared_at, normalized_scope),
)
conn.commit()
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
return max(rowcount, 0)
finally:
conn.close()
def clear_item_for_all_viewers(self, *, item_type: str, item_key: str) -> int:
"""Delete a dismissed item record for every viewer."""
normalized_type = _normalize_item_type(item_type)
normalized_key = _normalize_item_key(item_key, item_type=normalized_type)
with self._lock:
conn = self._connect()
try:
cursor = conn.execute(
"""
DELETE FROM activity_view_state
WHERE item_type = ? AND item_key = ?
""",
(normalized_type, normalized_key),
)
conn.commit()
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
return max(rowcount, 0)
finally:
conn.close()
def delete_viewer_scope(self, *, viewer_scope: str) -> int:
"""Delete all activity-view state rows for a viewer scope."""
normalized_scope = normalize_viewer_scope(viewer_scope)
with self._lock:
conn = self._connect()
try:
cursor = conn.execute(
"DELETE FROM activity_view_state WHERE viewer_scope = ?",
(normalized_scope,),
)
conn.commit()
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
return max(rowcount, 0)
finally:
conn.close()
def delete_items(self, *, item_type: str, item_keys: list[str]) -> int:
"""Delete multiple dismissed item records for a given item type."""
normalized_type = _normalize_item_type(item_type)
normalized_keys = [
_normalize_item_key(item_key, item_type=normalized_type) for item_key in item_keys
]
if not normalized_keys:
return 0
with self._lock:
conn = self._connect()
try:
cursor = conn.executemany(
"DELETE FROM activity_view_state WHERE item_type = ? AND item_key = ?",
[(normalized_type, normalized_key) for normalized_key in normalized_keys],
)
conn.commit()
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
return max(rowcount, 0)
finally:
conn.close()
+202 -160
View File
@@ -4,12 +4,14 @@ Registers /api/admin/users CRUD endpoints for managing users.
All endpoints require admin session.
"""
from functools import wraps
from __future__ import annotations
import os
import sqlite3
from typing import Any
from functools import wraps
from typing import TYPE_CHECKING, Any, ParamSpec
from flask import Flask, jsonify, request, session
from flask import Flask, Response, g, jsonify, request, session
from werkzeug.security import generate_password_hash
from shelfmark.config.booklore_settings import (
@@ -26,16 +28,33 @@ from shelfmark.core.auth_modes import (
AUTH_SOURCE_CWA,
AUTH_SOURCE_OIDC,
AUTH_SOURCE_PROXY,
determine_auth_mode,
has_local_password_admin,
is_user_active_for_auth_mode,
load_active_auth_mode,
normalize_auth_source,
)
from shelfmark.core.config import config as app_config
from shelfmark.core.cwa_user_sync import sync_cwa_users_from_rows
from shelfmark.core.logger import setup_logger
from shelfmark.core.settings_registry import load_config_file
from shelfmark.core.user_db import UserDB
if TYPE_CHECKING:
from collections.abc import Callable
from flask.typing import ResponseReturnValue
from shelfmark.core.user_db import UserDB
P = ParamSpec("P")
logger = setup_logger(__name__)
MIN_PASSWORD_LENGTH = 4
_CONFIG_REFRESH_ERRORS = (ImportError, OSError, RuntimeError, TypeError, ValueError)
__all__ = [
"get_booklore_library_options",
"get_booklore_path_options",
"register_admin_routes",
"validate_user_settings",
]
def _get_user_edit_capabilities(
@@ -47,10 +66,12 @@ def _get_user_edit_capabilities(
user.get("auth_source"),
user.get("oidc_subject"),
)
if security_config is None and auth_source == AUTH_SOURCE_OIDC:
security_config = load_config_file("security")
oidc_use_admin_group = bool((security_config or {}).get("OIDC_USE_ADMIN_GROUP", True))
oidc_use_admin_group = bool(
(security_config or {}).get(
"OIDC_USE_ADMIN_GROUP",
app_config.get("OIDC_USE_ADMIN_GROUP", True),
)
)
role_managed_by_oidc_group = auth_source == AUTH_SOURCE_OIDC and oidc_use_admin_group
can_edit_role = auth_source == AUTH_SOURCE_BUILTIN or (
auth_source == AUTH_SOURCE_OIDC and not role_managed_by_oidc_group
@@ -65,37 +86,6 @@ def _get_user_edit_capabilities(
}
def _get_auth_mode():
"""Get current auth mode from config."""
try:
config = load_config_file("security")
return determine_auth_mode(
config,
CWA_DB_PATH,
has_local_admin=has_local_password_admin(),
)
except Exception:
return "none"
def _require_admin(f):
"""Decorator to require admin session for admin routes.
In no-auth mode, everyone has access (is_admin defaults True).
In auth-required modes, requires an authenticated session with admin role.
"""
@wraps(f)
def decorated(*args, **kwargs):
auth_mode = _get_auth_mode()
if auth_mode != "none":
if "user_id" not in session:
return jsonify({"error": "Authentication required"}), 401
if not session.get("is_admin", False):
return jsonify({"error": "Admin access required"}), 403
return f(*args, **kwargs)
return decorated
def _sanitize_user(user: dict) -> dict:
"""Remove sensitive fields from user dict before returning to client."""
sanitized = dict(user)
@@ -103,27 +93,21 @@ def _sanitize_user(user: dict) -> dict:
return sanitized
def _oidc_role_management_message(security_config: dict[str, Any]) -> str:
admin_group = security_config.get("OIDC_ADMIN_GROUP", "")
def _oidc_role_management_message(security_config: dict[str, Any] | None = None) -> str:
admin_group = (security_config or {}).get(
"OIDC_ADMIN_GROUP",
app_config.get("OIDC_ADMIN_GROUP", ""),
)
if admin_group:
return (
"Admin roles for OIDC users are managed by the "
f"'{admin_group}' group in your identity provider"
)
return (
"Disable 'Use Admin Group for Authorization' in security settings "
"to manage roles manually"
"Disable 'Use Admin Group for Authorization' in security settings to manage roles manually"
)
def _is_user_active(user: dict[str, Any], auth_method: str) -> bool:
"""Determine whether a user can authenticate in the current auth mode."""
source = normalize_auth_source(user.get("auth_source"), user.get("oidc_subject"))
if source == AUTH_SOURCE_BUILTIN:
return auth_method in (AUTH_SOURCE_BUILTIN, AUTH_SOURCE_OIDC)
return source == auth_method
def _serialize_user(
user: dict[str, Any],
auth_method: str,
@@ -135,7 +119,7 @@ def _serialize_user(
payload.get("auth_source"),
payload.get("oidc_subject"),
)
payload["is_active"] = _is_user_active(payload, auth_method)
payload["is_active"] = is_user_active_for_auth_mode(payload, auth_method)
payload["edit_capabilities"] = _get_user_edit_capabilities(
payload,
security_config=security_config,
@@ -146,7 +130,8 @@ def _serialize_user(
def _sync_all_cwa_users(user_db: UserDB) -> dict[str, int]:
"""Sync all users from the Calibre-Web database into users.db."""
if not CWA_DB_PATH or not CWA_DB_PATH.exists():
raise FileNotFoundError("Calibre-Web database is not available")
msg = "Calibre-Web database is not available"
raise FileNotFoundError(msg)
db_path = os.fspath(CWA_DB_PATH)
db_uri = f"file:{db_path}?mode=ro&immutable=1"
@@ -164,24 +149,43 @@ def _sync_all_cwa_users(user_db: UserDB) -> dict[str, int]:
def register_admin_routes(app: Flask, user_db: UserDB) -> None:
"""Register admin user management routes on the Flask app."""
def _require_admin(
f: Callable[P, ResponseReturnValue],
) -> Callable[P, ResponseReturnValue]:
"""Require an admin session for admin routes.
In no-auth mode, everyone has access (is_admin defaults True).
In auth-required modes, requires an authenticated session with admin role.
Caches the resolved auth_mode in ``g.auth_mode`` for the request.
"""
@wraps(f)
def decorated(*args: P.args, **kwargs: P.kwargs) -> ResponseReturnValue:
auth_mode = load_active_auth_mode(CWA_DB_PATH, user_db=user_db)
g.auth_mode = auth_mode
if auth_mode != "none":
if "user_id" not in session:
return jsonify({"error": "Authentication required"}), 401
if not session.get("is_admin", False):
return jsonify({"error": "Admin access required"}), 403
return f(*args, **kwargs)
return decorated
@app.route("/api/admin/users", methods=["GET"])
@_require_admin
def admin_list_users():
def admin_list_users() -> Response | tuple[Response, int]:
"""List all users."""
users = user_db.list_users()
auth_mode = _get_auth_mode()
security_config = load_config_file("security")
return jsonify([
_serialize_user(u, auth_mode, security_config=security_config)
for u in users
])
auth_mode = g.auth_mode
return jsonify([_serialize_user(u, auth_mode) for u in users])
@app.route("/api/admin/users", methods=["POST"])
@_require_admin
def admin_create_user():
def admin_create_user() -> Response | tuple[Response, int]:
"""Create a new user with password authentication."""
data = request.get_json() or {}
auth_mode = _get_auth_mode()
auth_mode = g.auth_mode
username = (data.get("username") or "").strip()
password = data.get("password", "")
@@ -190,23 +194,28 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
role = data.get("role", "user")
if auth_mode in {AUTH_SOURCE_PROXY, AUTH_SOURCE_CWA}:
return jsonify({
"error": "Local user creation is disabled in this authentication mode",
"message": (
"Users are provisioned by your external authentication source. "
"Switch to builtin or OIDC mode to create local users."
),
}), 400
return jsonify(
{
"error": "Local user creation is disabled in this authentication mode",
"message": (
"Users are provisioned by your external authentication source. "
"Switch to builtin or OIDC mode to create local users."
),
}
), 400
if not username:
return jsonify({"error": "Username is required"}), 400
if not password or len(password) < 4:
return jsonify({"error": "Password must be at least 4 characters"}), 400
if not password or len(password) < MIN_PASSWORD_LENGTH:
return jsonify(
{"error": f"Password must be at least {MIN_PASSWORD_LENGTH} characters"}
), 400
if role not in ("admin", "user"):
return jsonify({"error": "Role must be 'admin' or 'user'"}), 400
# First user is always admin
if not user_db.list_users():
existing_users = user_db.list_users()
if not existing_users:
role = "admin"
# Check if username already exists
@@ -226,21 +235,22 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
except ValueError:
return jsonify({"error": "Username already exists"}), 409
logger.info(
"Shelfmark user created "
f"(source=manual_admin_create, created_by={session.get('user_id', 'unknown')}, "
f"username={username}, role={role}, auth_source={AUTH_SOURCE_BUILTIN})"
"Shelfmark user created (source=manual_admin_create, created_by=%s, username=%s, role=%s, auth_source=%s)",
session.get("user_id", "unknown"),
username,
role,
AUTH_SOURCE_BUILTIN,
)
return jsonify(
_serialize_user(
user,
_get_auth_mode(),
security_config=load_config_file("security"),
g.auth_mode,
)
), 201
@app.route("/api/admin/users/<int:user_id>", methods=["GET"])
@_require_admin
def admin_get_user(user_id):
def admin_get_user(user_id: int) -> Response | tuple[Response, int]:
"""Get a user by ID with their settings."""
user = user_db.get_user(user_id=user_id)
if not user:
@@ -248,39 +258,42 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
result = _serialize_user(
user,
_get_auth_mode(),
security_config=load_config_file("security"),
g.auth_mode,
)
result["settings"] = user_db.get_user_settings(user_id)
return jsonify(result)
@app.route("/api/admin/users/<int:user_id>", methods=["PUT"])
@_require_admin
def admin_update_user(user_id):
def admin_update_user(user_id: int) -> Response | tuple[Response, int]:
"""Update user fields and/or settings."""
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
data = request.get_json() or {}
security_config = load_config_file("security")
auth_source = normalize_auth_source(
user.get("auth_source"),
user.get("oidc_subject"),
)
capabilities = _get_user_edit_capabilities(user, security_config=security_config)
capabilities = _get_user_edit_capabilities(user)
# Handle optional password update
password = data.get("password", "")
password_hash: str | None = None
if password:
if not capabilities["canSetPassword"]:
return jsonify({
"error": f"Cannot set password for {auth_source.upper()} users",
"message": "Password authentication is only available for local users.",
}), 400
if len(password) < 4:
return jsonify({"error": "Password must be at least 4 characters"}), 400
user_db.update_user(user_id, password_hash=generate_password_hash(password))
return jsonify(
{
"error": f"Cannot set password for {auth_source.upper()} users",
"message": "Password authentication is only available for local users.",
}
), 400
if len(password) < MIN_PASSWORD_LENGTH:
return jsonify(
{"error": f"Password must be at least {MIN_PASSWORD_LENGTH} characters"}
), 400
password_hash = generate_password_hash(password)
# Update user fields
user_fields = {}
@@ -293,40 +306,49 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
role_changed = "role" in user_fields and user_fields["role"] != user.get("role")
email_changed = "email" in user_fields and user_fields["email"] != user.get("email")
display_name_changed = (
"display_name" in user_fields
and user_fields["display_name"] != user.get("display_name")
)
display_name_changed = "display_name" in user_fields and user_fields[
"display_name"
] != user.get("display_name")
if role_changed and not capabilities["canEditRole"]:
if auth_source == AUTH_SOURCE_OIDC:
return jsonify({
"error": "Cannot change role for OIDC user when group-based authorization is enabled",
"message": _oidc_role_management_message(security_config),
}), 400
return jsonify(
{
"error": "Cannot change role for OIDC user when group-based authorization is enabled",
"message": _oidc_role_management_message(),
}
), 400
return jsonify({
"error": f"Cannot change role for {auth_source.upper()} users",
"message": "Role is managed by the external authentication source.",
}), 400
return jsonify(
{
"error": f"Cannot change role for {auth_source.upper()} users",
"message": "Role is managed by the external authentication source.",
}
), 400
if email_changed and not capabilities["canEditEmail"]:
if auth_source == AUTH_SOURCE_CWA:
return jsonify({
"error": "Cannot change email for CWA users",
"message": "Email is synced from Calibre-Web.",
}), 400
return jsonify(
{
"error": "Cannot change email for CWA users",
"message": "Email is synced from Calibre-Web.",
}
), 400
return jsonify({
"error": "Cannot change email for OIDC users",
"message": "Email is managed by your identity provider.",
}), 400
return jsonify(
{
"error": "Cannot change email for OIDC users",
"message": "Email is managed by your identity provider.",
}
), 400
if display_name_changed and not capabilities["canEditDisplayName"]:
return jsonify({
"error": "Cannot change display name for OIDC users",
"message": "Display name is managed by your identity provider.",
}), 400
return jsonify(
{
"error": "Cannot change display name for OIDC users",
"message": "Display name is managed by your identity provider.",
}
), 400
# Allow demoting the last admin account.
# Auth mode resolution automatically falls back to "none" when no
@@ -337,61 +359,78 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
if field in user_fields and user_fields[field] == user.get(field):
user_fields.pop(field)
if user_fields:
user_db.update_user(user_id, **user_fields)
# Update per-user settings
# Validate per-user settings
validated_settings: dict[str, Any] | None = None
if "settings" in data:
if not isinstance(data["settings"], dict):
return jsonify({"error": "Settings must be an object"}), 400
validated_settings, validation_errors = validate_user_settings(data["settings"])
if validation_errors:
return jsonify({
"error": "Invalid settings payload",
"details": validation_errors,
}), 400
return jsonify(
{
"error": "Invalid settings payload",
"details": validation_errors,
}
), 400
# Apply the writes only once the whole payload has been accepted.
if password_hash is not None:
user_fields["password_hash"] = password_hash
if user_fields:
user_db.update_user(user_id, **user_fields)
if validated_settings is not None:
user_db.set_user_settings(user_id, validated_settings)
# Ensure runtime reads see updated per-user overrides immediately.
try:
from shelfmark.core.config import config as app_config
app_config.refresh()
except Exception:
pass
app_config.refresh(force=True)
except _CONFIG_REFRESH_ERRORS as exc:
logger.warning(
"Updated settings for user %s but failed to refresh runtime config: %s",
user_id,
exc,
)
updated = user_db.get_user(user_id=user_id)
if not isinstance(updated, dict):
return jsonify({"error": "User not found"}), 404
result = _serialize_user(
updated,
_get_auth_mode(),
security_config=security_config,
g.auth_mode,
)
result["settings"] = user_db.get_user_settings(user_id)
logger.info(f"Admin updated user {user_id}")
logger.info("Admin updated user %s", user_id)
return jsonify(result)
@app.route("/api/admin/users/sync-cwa", methods=["POST"])
@_require_admin
def admin_sync_cwa_users():
def admin_sync_cwa_users() -> Response | tuple[Response, int]:
"""Manually sync users from Calibre-Web into users.db."""
auth_mode = _get_auth_mode()
if auth_mode != AUTH_SOURCE_CWA:
return jsonify({
"error": "CWA sync is only available when CWA authentication is enabled",
}), 400
if g.auth_mode != AUTH_SOURCE_CWA:
return jsonify(
{
"error": "CWA sync is only available when CWA authentication is enabled",
}
), 400
try:
summary = _sync_all_cwa_users(user_db)
except FileNotFoundError:
return jsonify({
"error": "Calibre-Web database is not available",
"message": "Verify app.db is mounted and readable at /auth/app.db.",
}), 503
except Exception as exc:
logger.error(f"Failed to sync CWA users: {exc}")
return jsonify({
"error": "Failed to sync users from Calibre-Web",
}), 500
return jsonify(
{
"error": "Calibre-Web database is not available",
"message": "Verify app.db is mounted and readable at /auth/app.db.",
}
), 503
except Exception:
logger.exception("Failed to sync CWA users")
return jsonify(
{
"error": "Failed to sync users from Calibre-Web",
}
), 500
message = (
f"Synced {summary['total']} CWA users "
@@ -399,17 +438,19 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
f"{summary.get('deleted', 0)} deleted)."
)
logger.info(message)
return jsonify({
"success": True,
"message": message,
**summary,
})
return jsonify(
{
"success": True,
"message": message,
**summary,
}
)
register_admin_settings_routes(app, user_db, _require_admin)
@app.route("/api/admin/users/<int:user_id>", methods=["DELETE"])
@_require_admin
def admin_delete_user(user_id):
def admin_delete_user(user_id: int) -> Response | tuple[Response, int]:
"""Delete a user."""
# Prevent self-deletion
if session.get("db_user_id") == user_id:
@@ -419,21 +460,22 @@ def register_admin_routes(app: Flask, user_db: UserDB) -> None:
if not user:
return jsonify({"error": "User not found"}), 404
auth_mode = _get_auth_mode()
auth_source = normalize_auth_source(
user.get("auth_source"),
user.get("oidc_subject"),
)
if auth_source == AUTH_SOURCE_CWA and auth_source == auth_mode:
return jsonify({
"error": f"Cannot delete active {auth_source.upper()} users",
"message": f"{auth_source.upper()} users are automatically re-provisioned on login.",
}), 400
if auth_source == AUTH_SOURCE_CWA and auth_source == g.auth_mode:
return jsonify(
{
"error": f"Cannot delete active {auth_source.upper()} users",
"message": f"{auth_source.upper()} users are automatically re-provisioned on login.",
}
), 400
# Allow deleting the last local admin account.
# Auth mode resolution automatically falls back to "none" when no
# local password admin remains.
user_db.delete_user(user_id)
logger.info(f"Admin deleted user {user_id}: {user['username']}")
logger.info("Admin deleted user %s: %s", user_id, user["username"])
return jsonify({"success": True})
+115 -36
View File
@@ -1,6 +1,8 @@
"""Admin settings-introspection routes and settings validation helpers."""
from typing import Any, Callable
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from flask import Flask, jsonify, request
@@ -9,17 +11,35 @@ from shelfmark.config.notifications_settings import (
is_valid_notification_url,
normalize_notification_routes,
)
from shelfmark.config.users_settings import (
SEARCH_PREFERENCE_VALIDATABLE_KEYS,
validate_search_preference_value,
)
from shelfmark.core.config import config as app_config
from shelfmark.core.request_policy import parse_policy_mode, validate_policy_rules
from shelfmark.core.settings_registry import load_config_file
from shelfmark.core.user_settings_overrides import (
build_user_preferences_payload as _build_user_preferences_payload,
)
from shelfmark.core.user_settings_overrides import (
get_ordered_user_overridable_fields as _get_ordered_user_overridable_fields,
)
from shelfmark.core.user_settings_overrides import (
get_settings_registry as _get_settings_registry,
)
from shelfmark.core.user_db import UserDB
from shelfmark.core.request_policy import parse_policy_mode, validate_policy_rules
if TYPE_CHECKING:
from collections.abc import Callable
from flask.typing import ResponseReturnValue
from shelfmark.core.user_db import UserDB
def validate_user_settings(settings: dict[str, Any]) -> tuple[dict[str, Any], list[str]]:
def validate_user_settings(
settings: dict[str, Any],
) -> tuple[dict[str, Any], list[str]]:
"""Validate and normalize per-user settings overrides."""
settings_registry = _get_settings_registry()
field_map = settings_registry.get_settings_field_map()
overridable_map = settings_registry.get_user_overridable_fields()
@@ -37,10 +57,12 @@ def validate_user_settings(settings: dict[str, Any]) -> tuple[dict[str, Any], li
valid[key] = None
continue
if key in {"REQUEST_POLICY_DEFAULT_EBOOK", "REQUEST_POLICY_DEFAULT_AUDIOBOOK"}:
if parse_policy_mode(value) is None:
errors.append(f"Invalid policy mode for {key}: {value}")
continue
if (
key in {"REQUEST_POLICY_DEFAULT_EBOOK", "REQUEST_POLICY_DEFAULT_AUDIOBOOK"}
and parse_policy_mode(value) is None
):
errors.append(f"Invalid policy mode for {key}: {value}")
continue
if key == "REQUEST_POLICY_RULES":
normalized_rules, rule_errors = validate_policy_rules(value)
@@ -59,15 +81,51 @@ def validate_user_settings(settings: dict[str, Any]) -> tuple[dict[str, Any], li
)
if invalid_count:
errors.append(
(
f"Invalid value for {key}: found {invalid_count} invalid URL(s). "
"Use URL values with a valid scheme, e.g. discord://... or ntfys://..."
)
f"Invalid value for {key}: found {invalid_count} invalid URL(s). "
"Use URL values with a valid scheme, e.g. discord://... or ntfys://..."
)
continue
valid[key] = normalized_routes
continue
normalized_search_value, search_validation_error = validate_search_preference_value(
key, value
)
if search_validation_error:
errors.append(search_validation_error)
continue
# Every key the search validator recognises keeps its normalized value;
# a hand-maintained subset here silently dropped normalization for the rest.
if key in SEARCH_PREFERENCE_VALIDATABLE_KEYS:
valid[key] = normalized_search_value
continue
if key == "DOWNLOAD_TO_BROWSER_CONTENT_TYPES":
if not isinstance(value, list):
errors.append(f"Invalid value for {key}: must be a list")
continue
candidate_values = [
str(entry).strip().lower() for entry in value if str(entry).strip()
]
normalized_values: list[str] = []
has_invalid_value = False
for entry in candidate_values:
if entry not in {"book", "audiobook"}:
errors.append(
f"Invalid value for {key}: unsupported content type '{entry}'"
)
has_invalid_value = True
continue
if entry not in normalized_values:
normalized_values.append(entry)
if has_invalid_value:
continue
valid[key] = normalized_values
continue
valid[key] = value
return valid, errors
@@ -76,8 +134,9 @@ def validate_user_settings(settings: dict[str, Any]) -> tuple[dict[str, Any], li
def build_user_notification_test_response(
*,
user_id: int,
payload: Any,
payload: object,
) -> tuple[dict[str, Any], int]:
"""Build a notification test response using effective per-user routes."""
from shelfmark.core.config import config as app_config
routes_input = app_config.get("USER_NOTIFICATION_ROUTES", [], user_id=user_id)
@@ -95,36 +154,40 @@ def build_user_notification_test_response(
def register_admin_settings_routes(
app: Flask,
user_db: UserDB,
require_admin: Callable[[Callable[..., Any]], Callable[..., Any]],
require_admin: Callable[
[Callable[..., ResponseReturnValue]], Callable[..., ResponseReturnValue]
],
) -> None:
"""Register admin endpoints for user-specific settings and defaults."""
@app.route("/api/admin/download-defaults", methods=["GET"])
@require_admin
def admin_download_defaults():
config = load_config_file("downloads")
def admin_download_defaults() -> ResponseReturnValue:
defaults = {
key: ("" if (value := config.get(key, field.default)) is None else value)
key: ("" if (value := app_config.get(key, field.default)) is None else value)
for key, field in _get_ordered_user_overridable_fields("downloads")
}
security_config = load_config_file("security")
defaults["OIDC_ADMIN_GROUP"] = security_config.get("OIDC_ADMIN_GROUP", "")
defaults["OIDC_USE_ADMIN_GROUP"] = security_config.get("OIDC_USE_ADMIN_GROUP", True)
defaults["OIDC_AUTO_PROVISION"] = security_config.get("OIDC_AUTO_PROVISION", True)
defaults["OIDC_ADMIN_GROUP"] = app_config.get("OIDC_ADMIN_GROUP", "")
defaults["OIDC_USE_ADMIN_GROUP"] = app_config.get("OIDC_USE_ADMIN_GROUP", True)
defaults["OIDC_AUTO_PROVISION"] = app_config.get("OIDC_AUTO_PROVISION", True)
return jsonify(defaults)
@app.route("/api/admin/booklore-options", methods=["GET"])
@require_admin
def admin_booklore_options():
def admin_booklore_options() -> ResponseReturnValue:
from shelfmark.core import admin_routes
return jsonify({
"libraries": admin_routes.get_booklore_library_options(),
"paths": admin_routes.get_booklore_path_options(),
})
return jsonify(
{
"libraries": admin_routes.get_booklore_library_options(),
"paths": admin_routes.get_booklore_path_options(),
}
)
@app.route("/api/admin/users/<int:user_id>/delivery-preferences", methods=["GET"])
@require_admin
def admin_get_delivery_preferences(user_id):
def admin_get_delivery_preferences(user_id: int) -> ResponseReturnValue:
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
@@ -136,9 +199,23 @@ def register_admin_settings_routes(
return jsonify(payload)
@app.route("/api/admin/users/<int:user_id>/search-preferences", methods=["GET"])
@require_admin
def admin_get_search_preferences(user_id: int) -> ResponseReturnValue:
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
try:
payload = _build_user_preferences_payload(user_db, user_id, "search_mode")
except ValueError:
return jsonify({"error": "Search mode settings tab not found"}), 500
return jsonify(payload)
@app.route("/api/admin/users/<int:user_id>/notification-preferences", methods=["GET"])
@require_admin
def admin_get_notification_preferences(user_id):
def admin_get_notification_preferences(user_id: int) -> ResponseReturnValue:
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
@@ -152,7 +229,7 @@ def register_admin_settings_routes(
@app.route("/api/admin/users/<int:user_id>/notification-preferences/test", methods=["POST"])
@require_admin
def admin_test_notification_preferences(user_id):
def admin_test_notification_preferences(user_id: int) -> ResponseReturnValue:
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
@@ -166,7 +243,7 @@ def register_admin_settings_routes(
@app.route("/api/admin/settings/overrides-summary", methods=["GET"])
@require_admin
def admin_settings_overrides_summary():
def admin_settings_overrides_summary() -> ResponseReturnValue:
settings_registry = _get_settings_registry()
tab_name = (request.args.get("tab") or "downloads").strip()
@@ -185,11 +262,13 @@ def register_admin_settings_routes(
if key not in user_settings or user_settings[key] is None:
continue
entry = keys_payload.setdefault(key, {"count": 0, "users": []})
entry["users"].append({
"userId": user_record["id"],
"username": user_record["username"],
"value": user_settings[key],
})
entry["users"].append(
{
"userId": user_record["id"],
"username": user_record["username"],
"value": user_settings[key],
}
)
for summary in keys_payload.values():
summary["count"] = len(summary["users"])
@@ -198,7 +277,7 @@ def register_admin_settings_routes(
@app.route("/api/admin/users/<int:user_id>/effective-settings", methods=["GET"])
@require_admin
def admin_get_effective_settings(user_id):
def admin_get_effective_settings(user_id: int) -> ResponseReturnValue:
user = user_db.get_user(user_id=user_id)
if not user:
return jsonify({"error": "User not found"}), 404
+39
View File
@@ -0,0 +1,39 @@
"""Static API-key authentication backed by the SHELFMARK_API_KEY environment variable.
When ``SHELFMARK_API_KEY`` is set, a request carrying that value as a Bearer token or in
``X-Api-Key`` is treated as an admin for that request only. Both headers are
checked, since a reverse proxy in front of Shelfmark may set its own
``Authorization`` header, which would otherwise shadow an operator-supplied
``X-Api-Key``. A candidate that matches neither is ignored so that bearer
tokens forwarded by reverse proxies keep working. The key is never logged.
"""
from __future__ import annotations
import hmac
from shelfmark.config.env import SHELFMARK_API_KEY
def extract_api_key_candidates(
authorization_header: str | None, api_key_header: str | None
) -> list[str]:
"""Return the non-empty credentials a client presented, Bearer token first."""
candidates: list[str] = []
if authorization_header:
scheme, _, token = authorization_header.strip().partition(" ")
token = token.strip()
if scheme.lower() == "bearer" and token:
candidates.append(token)
if api_key_header:
token = api_key_header.strip()
if token:
candidates.append(token)
return candidates
def matches_api_key(candidate: str) -> bool:
"""Constant-time comparison against the configured key. False when unset."""
if not SHELFMARK_API_KEY or not candidate:
return False
return hmac.compare_digest(candidate.encode("utf-8"), SHELFMARK_API_KEY.encode("utf-8"))
+68 -15
View File
@@ -1,7 +1,14 @@
"""Authentication mode, auth-source normalization, and admin access policy helpers."""
from __future__ import annotations
import os
from typing import Any, Mapping
import sqlite3
from pathlib import Path
from typing import TYPE_CHECKING, Any, Protocol, TypeGuard
if TYPE_CHECKING:
from collections.abc import Mapping
AUTH_SOURCE_BUILTIN = "builtin"
AUTH_SOURCE_OIDC = "oidc"
@@ -17,7 +24,18 @@ AUTH_SOURCE_SET = frozenset(AUTH_SOURCES)
_ALWAYS_ADMIN_SETTINGS_TABS = frozenset({"security", "users"})
def has_local_password_admin(user_db: Any | None = None) -> bool:
class _UserDBWithAdminPassword(Protocol):
"""Minimal user DB surface needed for local-admin checks."""
def has_admin_with_password(self) -> bool: ...
def _has_admin_password_api(candidate: object) -> TypeGuard[_UserDBWithAdminPassword]:
"""Return True when *candidate* exposes the admin-password lookup we need."""
return callable(getattr(candidate, "has_admin_with_password", None))
def has_local_password_admin(user_db: object | None = None) -> bool:
"""Return True when at least one local admin with a password exists."""
try:
db = user_db
@@ -25,20 +43,19 @@ def has_local_password_admin(user_db: Any | None = None) -> bool:
from shelfmark.core.user_db import UserDB
config_root = os.environ.get("CONFIG_DIR", "/config")
db = UserDB(os.path.join(config_root, "users.db"))
db = UserDB(str(Path(config_root) / "users.db"))
db.initialize()
return any(
user.get("password_hash") and user.get("role") == "admin"
for user in db.list_users()
)
except Exception:
if not _has_admin_password_api(db):
return False
return db.has_admin_with_password()
except AttributeError, ImportError, OSError, RuntimeError, TypeError, ValueError, sqlite3.Error:
return False
def normalize_auth_source(
source: Any,
oidc_subject: Any = None,
source: object,
oidc_subject: object = None,
) -> str:
"""Resolve a stable auth source value from persisted fields."""
normalized = str(source or "").strip().lower()
@@ -51,17 +68,19 @@ def normalize_auth_source(
def determine_auth_mode(
security_config: Mapping[str, Any],
cwa_db_path: Any | None,
cwa_db_path: object | None,
*,
has_local_admin: bool = True,
disable_local_auth: bool = False,
) -> str:
"""Determine active auth mode from security config and runtime prerequisites."""
auth_mode = security_config.get("AUTH_METHOD", "none")
local_admin_available = has_local_admin or disable_local_auth
if auth_mode == AUTH_SOURCE_CWA and cwa_db_path:
return AUTH_SOURCE_CWA
if auth_mode == AUTH_SOURCE_BUILTIN and has_local_admin:
if auth_mode == AUTH_SOURCE_BUILTIN and local_admin_available:
return AUTH_SOURCE_BUILTIN
if auth_mode == AUTH_SOURCE_PROXY and security_config.get("PROXY_AUTH_USER_HEADER"):
@@ -69,7 +88,7 @@ def determine_auth_mode(
if (
auth_mode == AUTH_SOURCE_OIDC
and has_local_admin
and local_admin_available
and security_config.get("OIDC_DISCOVERY_URL")
and security_config.get("OIDC_CLIENT_ID")
):
@@ -78,9 +97,43 @@ def determine_auth_mode(
return "none"
def load_active_auth_mode(
cwa_db_path: object | None,
*,
user_db: object | None = None,
) -> str:
"""Resolve active auth mode using current security config and runtime prerequisites."""
try:
from shelfmark.config.env import DISABLE_LOCAL_AUTH
from shelfmark.core.config import config as app_config
security_config = {
"AUTH_METHOD": app_config.get("AUTH_METHOD", "none"),
"PROXY_AUTH_USER_HEADER": app_config.get("PROXY_AUTH_USER_HEADER", ""),
"OIDC_DISCOVERY_URL": app_config.get("OIDC_DISCOVERY_URL", ""),
"OIDC_CLIENT_ID": app_config.get("OIDC_CLIENT_ID", ""),
}
return determine_auth_mode(
security_config,
cwa_db_path,
has_local_admin=has_local_password_admin(user_db),
disable_local_auth=DISABLE_LOCAL_AUTH,
)
except ImportError, OSError, RuntimeError, TypeError, ValueError, sqlite3.Error:
return "none"
def is_user_active_for_auth_mode(user: Mapping[str, Any], auth_mode: str) -> bool:
"""Return whether a user can authenticate under the current auth mode."""
source = normalize_auth_source(user.get("auth_source"), user.get("oidc_subject"))
if source == AUTH_SOURCE_BUILTIN:
return auth_mode in (AUTH_SOURCE_BUILTIN, AUTH_SOURCE_OIDC)
return source == auth_mode
def is_settings_or_onboarding_path(path: str) -> bool:
"""Return True when request path targets protected admin settings routes."""
return path.startswith("/api/settings") or path.startswith("/api/onboarding")
return path.startswith(("/api/settings", "/api/onboarding"))
def get_settings_tab_from_path(path: str) -> str | None:
@@ -88,7 +141,7 @@ def get_settings_tab_from_path(path: str) -> str | None:
if not path.startswith("/api/settings/"):
return None
suffix = path[len("/api/settings/"):]
suffix = path[len("/api/settings/") :]
if not suffix:
return None
+112
View File
@@ -0,0 +1,112 @@
"""Comparing and trimming author names for release search.
Lives in core because more than one release source needs it: Prowlarr ranks
results on author agreement (#1293), and IRC both trims the name it searches
for and ranks what comes back.
"""
import re
_AUTHOR_TOKEN_PATTERN = re.compile(r"\w+", re.UNICODE)
_AUTHOR_NOISE_TOKENS = frozenset(
{"jr", "sr", "ii", "iii", "iv", "phd", "md", "dr", "mr", "mrs", "ms", "et", "al", "and", "the"}
)
# Ordering tiers for author agreement between the requested book and what an
# indexer reported. Lower sorts first.
AUTHOR_MATCH = 0
AUTHOR_PARTIAL = 1
AUTHOR_UNKNOWN = 2
AUTHOR_MISMATCH = 3
# A mononym ("Homer") can only ever agree on one token; a longer name needs a
# given name and a surname to agree before it counts as the same person.
_AUTHOR_TOKENS_REQUIRED = 2
def _author_tokens(value: object) -> list[str]:
"""Split an author string into comparable lowercase name tokens."""
if not isinstance(value, str):
return []
tokens = [token.lower() for token in _AUTHOR_TOKEN_PATTERN.findall(value)]
return [token for token in tokens if token not in _AUTHOR_NOISE_TOKENS]
def _author_tokens_compatible(wanted: str, offered: str) -> bool:
"""Treat an abbreviated given name as the name it abbreviates."""
return wanted == offered or wanted.startswith(offered) or offered.startswith(wanted)
def author_affinity(wanted: object, offered: object) -> int:
"""Rank how far an indexer's author field is from the requested author.
Shelfmark ranks on this rather than filtering on it, so a wrong verdict only
costs a release its position in the list, never its visibility. That is what
makes the loose token comparison safe: "Tim"/"Timothy" and "T."/"Timothy"
agree, while a transliteration ("Dostoevsky"/"Dostoyevsky") is merely sorted
last instead of being hidden.
Graded, not binary, because the ways of falling short are not equally bad.
An indexer that reports no author at all must not sort below one that reports
a wrong author, so "no metadata" ranks between agreement and disagreement. And
a name that merely says *less* than the one asked for is not evidence of a
different person: "Petrie" contradicts nothing about "David Petrie", while
"Gordon Petrie" does. That gap matters most where a source is searched by
surname alone (#1331) - the filenames such a search is meant to reach are
exactly the ones filed under a bare surname, and ranking them as wrong put
them below every result that named someone else entirely.
"""
wanted_tokens = _author_tokens(wanted)
offered_tokens = _author_tokens(offered)
if not wanted_tokens or not offered_tokens:
return AUTHOR_UNKNOWN
matched = sum(
1
for wanted_token in wanted_tokens
if any(
_author_tokens_compatible(wanted_token, offered_token)
for offered_token in offered_tokens
)
)
required = min(_AUTHOR_TOKENS_REQUIRED, len(wanted_tokens))
if matched >= required:
return AUTHOR_MATCH
# Too little agreement to call it the same person, so the question is whether
# what was offered *disagrees*. A name every token of which fits the wanted
# name is an abbreviation of it; one carrying a token that fits nothing is a
# different name that happens to share a surname.
if all(
any(
_author_tokens_compatible(wanted_token, offered_token) for wanted_token in wanted_tokens
)
for offered_token in offered_tokens
):
return AUTHOR_PARTIAL
return AUTHOR_MISMATCH
def search_surname(author: object) -> str:
"""The one name token worth sending to a source that matches conjunctively.
Given names are where catalogues disagree - "David Petrie" is filed as
"D. Petrie", "Timothy" as "Tim" - so a query carrying one matches nothing on
a source that requires every term to appear. The surname is the token both
spellings share.
Keeps the author's own capitalisation, because the result is posted to a
public channel, and returns "" when no usable token is left so the caller
searches by title alone rather than by noise.
"""
if not isinstance(author, str):
return ""
tokens = [
token
for token in _AUTHOR_TOKEN_PATTERN.findall(author)
if token.lower() not in _AUTHOR_NOISE_TOKENS
]
if not tokens:
return ""
return tokens[-1]
+55 -39
View File
@@ -4,32 +4,37 @@ import threading
import time
from dataclasses import dataclass
from functools import wraps
from typing import Any, Callable, Dict, Optional, TypeVar
from typing import TYPE_CHECKING, ParamSpec, TypeVar, cast
from shelfmark.core.logger import setup_logger
if TYPE_CHECKING:
from collections.abc import Callable
logger = setup_logger(__name__)
T = TypeVar("T")
P = ParamSpec("P")
R = TypeVar("R")
@dataclass
class CacheEntry:
"""A cached value with expiration time."""
value: Any
value: object
expires_at: float
class CacheService:
"""Thread-safe in-memory cache with TTL support."""
def __init__(self, max_size: int = 1000):
def __init__(self, max_size: int = 1000) -> None:
"""Initialize cache with max_size entries before eviction."""
self._cache: Dict[str, CacheEntry] = {}
self._cache: dict[str, CacheEntry] = {}
self._lock = threading.Lock()
self._max_size = max_size
def get(self, key: str) -> Optional[Any]:
def get(self, key: str) -> object | None:
"""Get cached value if not expired."""
with self._lock:
entry = self._cache.get(key)
@@ -42,17 +47,14 @@ class CacheService:
return entry.value
def set(self, key: str, value: Any, ttl: int) -> None:
def set(self, key: str, value: object, ttl: int) -> None:
"""Cache value with TTL in seconds."""
with self._lock:
# Evict oldest entries if at capacity
if len(self._cache) >= self._max_size:
self._evict_oldest()
self._cache[key] = CacheEntry(
value=value,
expires_at=time.time() + ttl
)
self._cache[key] = CacheEntry(value=value, expires_at=time.time() + ttl)
def invalidate(self, key: str) -> bool:
"""Remove specific cache entry. Returns True if found."""
@@ -62,6 +64,14 @@ class CacheService:
return True
return False
def invalidate_prefix(self, prefix: str) -> int:
"""Remove all cache entries whose keys start with prefix."""
with self._lock:
matching_keys = [key for key in self._cache if key.startswith(prefix)]
for key in matching_keys:
del self._cache[key]
return len(matching_keys)
def clear(self) -> None:
"""Clear all cache entries."""
with self._lock:
@@ -71,10 +81,7 @@ class CacheService:
"""Remove all expired entries. Returns count removed."""
with self._lock:
now = time.time()
expired_keys = [
key for key, entry in self._cache.items()
if entry.expires_at < now
]
expired_keys = [key for key, entry in self._cache.items() if entry.expires_at < now]
for key in expired_keys:
del self._cache[key]
return len(expired_keys)
@@ -86,21 +93,15 @@ class CacheService:
# Remove ~10% of entries, oldest first
entries_to_remove = max(1, len(self._cache) // 10)
sorted_entries = sorted(
self._cache.items(),
key=lambda x: x[1].expires_at
)
sorted_entries = sorted(self._cache.items(), key=lambda x: x[1].expires_at)
for key, _ in sorted_entries[:entries_to_remove]:
del self._cache[key]
def stats(self) -> Dict[str, int]:
def stats(self) -> dict[str, int]:
"""Get cache statistics (size, max_size)."""
with self._lock:
return {
"size": len(self._cache),
"max_size": self._max_size
}
return {"size": len(self._cache), "max_size": self._max_size}
# Global cache instance for metadata providers
@@ -112,23 +113,38 @@ def get_metadata_cache() -> CacheService:
return _metadata_cache
def cache_key(*args, **kwargs) -> str:
def cache_key(*args: object, **kwargs: object) -> str:
"""Generate cache key from arguments."""
parts = [str(arg) for arg in args]
parts.extend(f"{k}={v}" for k, v in sorted(kwargs.items()))
return ":".join(parts)
def _coerce_ttl_seconds(value: object, *, default: int) -> int:
"""Normalize cache TTL values read from config or decorator arguments."""
if isinstance(value, bool):
return default
if isinstance(value, int):
return value if value > 0 else default
if isinstance(value, str):
stripped = value.strip()
if stripped.isdigit():
parsed = int(stripped)
return parsed if parsed > 0 else default
return default
def cacheable(
ttl: Optional[int] = None,
ttl_key: Optional[str] = None,
ttl: int | None = None,
ttl_key: str | None = None,
ttl_default: int = 300,
key_prefix: str = ""
):
"""Decorator for caching function results. Use ttl (static) or ttl_key (from config)."""
def decorator(func: Callable[..., T]) -> Callable[..., T]:
key_prefix: str = "",
) -> Callable[[Callable[P, R]], Callable[P, R]]:
"""Cache function results with a static or config-backed TTL."""
def decorator(func: Callable[P, R]) -> Callable[P, R]:
@wraps(func)
def wrapper(*args, **kwargs) -> T:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
# Check if metadata caching is enabled
from shelfmark.core.config import config
@@ -140,7 +156,10 @@ def cacheable(
if ttl is not None:
effective_ttl = ttl
elif ttl_key:
effective_ttl = config.get(ttl_key, ttl_default)
effective_ttl = _coerce_ttl_seconds(
config.get(ttl_key, ttl_default),
default=ttl_default,
)
else:
effective_ttl = ttl_default
@@ -148,16 +167,12 @@ def cacheable(
# Skip 'self' argument if present (first arg of method)
cache_args = args[1:] if args and hasattr(args[0], func.__name__) else args
key = cache_key(
key_prefix or func.__name__,
*cache_args,
**kwargs
)
key = cache_key(key_prefix or func.__name__, *cache_args, **kwargs)
# Check cache
cached = _metadata_cache.get(key)
if cached is not None:
return cached
return cast("R", cached)
# Execute function and cache result
result = func(*args, **kwargs)
@@ -169,4 +184,5 @@ def cacheable(
return result
return wrapper
return decorator
+79 -55
View File
@@ -2,72 +2,92 @@
import os
import sqlite3
import time
from importlib import import_module
from pathlib import Path
from threading import Lock
from typing import Any, Dict, Optional
from typing import TYPE_CHECKING, Any, Self
if TYPE_CHECKING:
from types import ModuleType
from shelfmark.core.user_db import UserDB
# Import lazily to avoid circular imports
_registry_module = None
_env_module = None
_user_db_module = None
_SETTINGS_REFRESH_COOLDOWN_SECONDS = 0.05
def _get_registry():
def _get_registry() -> ModuleType:
"""Lazy import of settings registry to avoid circular imports."""
global _registry_module
if _registry_module is None:
from shelfmark.core import settings_registry
_registry_module = settings_registry
return _registry_module
def _get_env():
def _get_env() -> ModuleType:
"""Lazy import of env module for fallback values."""
global _env_module
if _env_module is None:
from shelfmark.config import env
_env_module = env
return _env_module
def _get_user_db_module():
def _get_user_db_module() -> type[UserDB]:
"""Lazy import of user DB module to avoid optional dependency loops."""
global _user_db_module
if _user_db_module is None:
from shelfmark.core.user_db import UserDB
_user_db_module = UserDB
return _user_db_module
class Config:
"""
Dynamic configuration singleton that provides live settings access.
"""Dynamic configuration singleton that provides live settings access.
Settings are resolved with priority: ENV var > config file > default.
Values are cached for performance and can be refreshed when settings change.
"""
_instance: Optional['Config'] = None
_instance: Self | None = None
_lock = Lock()
def __new__(cls) -> 'Config':
def __new__(cls) -> Self:
"""Return the shared configuration singleton instance."""
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
instance = cls._instance
if instance is None:
msg = "Config singleton failed to initialize"
raise RuntimeError(msg)
return instance
def __init__(self):
def __init__(self) -> None:
"""Initialize caches and backing stores for the singleton."""
if self._initialized:
return
self._cache: Dict[str, Any] = {}
self._field_map: Dict[str, tuple] = {} # key -> (field, tab_name)
self._cache: dict[str, Any] = {}
self._field_map: dict[str, tuple] = {} # key -> (field, tab_name)
self._cache_lock = Lock()
self._user_settings_cache: Dict[int, Dict[str, Any]] = {}
self._user_settings_cache: dict[int, dict[str, Any]] = {}
self._user_settings_cache_lock = Lock()
self._user_db = None
self._user_db_load_attempted = False
self._initialized = True
self._loaded = False
self._last_refresh_time: float = 0.0
def _ensure_loaded(self) -> None:
"""Ensure settings are loaded from the registry."""
@@ -83,10 +103,12 @@ class Config:
# Ensure all settings modules are imported before loading
# This handles cases where config is accessed before settings are registered
try:
import shelfmark.config.settings # noqa: F401 - main app settings
import shelfmark.config.notifications_settings # noqa: F401 - notifications settings
import shelfmark.release_sources # noqa: F401 - plugin settings
import shelfmark.metadata_providers # noqa: F401 - plugin settings
import_module("shelfmark.config.notifications_settings")
import_module("shelfmark.config.security")
import_module("shelfmark.config.settings")
import_module("shelfmark.config.users_settings")
import_module("shelfmark.metadata_providers")
import_module("shelfmark.release_sources")
except ImportError:
pass
@@ -94,7 +116,7 @@ class Config:
# On first load, sync ENV values to config files
# This ensures ENV values persist even if ENV vars are later removed
if not hasattr(self, '_env_synced'):
if not hasattr(self, "_env_synced"):
registry.sync_env_to_config()
self._env_synced = True
@@ -102,28 +124,27 @@ class Config:
self._field_map.clear()
self._cache.clear()
for tab in registry.get_all_settings_tabs():
for field in tab.fields:
# Skip action buttons and headings - they don't have values
if isinstance(field, (registry.ActionButton, registry.HeadingField)):
continue
key = field.key
self._field_map[key] = (field, tab.name)
# Load current value
value = registry.get_setting_value(field, tab.name)
self._cache[key] = value
for key, (field, tab_name) in registry.get_settings_field_map().items():
self._field_map[key] = (field, tab_name)
self._cache[key] = registry.get_setting_value(field, tab_name)
self._loaded = True
def refresh(self) -> None:
"""
Refresh all cached settings from config files.
def refresh(self, *, force: bool = False) -> None:
"""Refresh all cached settings from config files.
Call this after settings are updated via the UI to ensure
the config singleton reflects the new values.
Multiple calls within a short window (50 ms) are coalesced to
avoid redundant disk I/O when several helpers each call refresh()
during the same request. Pass ``force=True`` to bypass the guard
(e.g. after a settings write).
"""
now = time.monotonic()
if not force and (now - self._last_refresh_time) < _SETTINGS_REFRESH_COOLDOWN_SECONDS:
return
with self._cache_lock:
self._loaded = False
self._load_settings()
@@ -131,8 +152,9 @@ class Config:
self._user_settings_cache.clear()
self._user_db = None
self._user_db_load_attempted = False
self._last_refresh_time = time.monotonic()
def _get_user_db(self):
def _get_user_db(self) -> UserDB | None:
"""Get or initialize a UserDB handle if available."""
if self._user_db is not None:
return self._user_db
@@ -142,16 +164,17 @@ class Config:
self._user_db_load_attempted = True
try:
user_db_cls = _get_user_db_module()
db_path = os.path.join(os.environ.get("CONFIG_DIR", "/config"), "users.db")
db_path = str(Path(os.environ.get("CONFIG_DIR", "/config")) / "users.db")
user_db = user_db_cls(db_path)
user_db.initialize()
self._user_db = user_db
return self._user_db
except Exception:
except ImportError, OSError, sqlite3.Error:
# Multi-user support is optional; fall back to global config when unavailable.
return None
else:
self._user_db = user_db
return self._user_db
def _get_user_settings(self, user_id: int) -> Dict[str, Any]:
def _get_user_settings(self, user_id: int) -> dict[str, Any]:
"""Get cached per-user settings from user DB."""
with self._user_settings_cache_lock:
if user_id in self._user_settings_cache:
@@ -163,7 +186,7 @@ class Config:
try:
settings = user_db.get_user_settings(user_id)
except (sqlite3.OperationalError, OSError, ValueError, TypeError):
except sqlite3.OperationalError, OSError, ValueError, TypeError:
return {}
if not isinstance(settings, dict):
@@ -173,14 +196,13 @@ class Config:
self._user_settings_cache[user_id] = settings
return settings
def _get_user_override(self, user_id: int, key: str) -> Any:
def _get_user_override(self, user_id: int, key: str) -> object:
"""Get a user override for a specific key."""
user_settings = self._get_user_settings(user_id)
return user_settings.get(key)
def get(self, key: str, default: Any = None, user_id: Optional[int] = None) -> Any:
"""
Get a setting value by key.
def get(self, key: str, default: object = None, user_id: int | None = None) -> object:
"""Get a setting value by key.
Args:
key: The setting key (e.g., 'MAX_RETRY')
@@ -189,6 +211,7 @@ class Config:
Returns:
The setting value, or default if not found
"""
self._ensure_loaded()
@@ -208,15 +231,15 @@ class Config:
return self._cache.get(key, default)
def __getattr__(self, name: str) -> Any:
"""
Allow attribute-style access to settings.
def __getattr__(self, name: str) -> object:
"""Allow attribute-style access to settings.
Example: config.MAX_RETRY instead of config.get('MAX_RETRY')
"""
# Avoid recursion for internal attributes
if name.startswith('_'):
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
if name.startswith("_"):
msg = f"'{type(self).__name__}' object has no attribute '{name}'"
raise AttributeError(msg)
self._ensure_loaded()
@@ -229,17 +252,18 @@ class Config:
if hasattr(env, name):
return getattr(env, name)
raise AttributeError(f"Setting '{name}' not found in config or env")
msg = f"Setting '{name}' not found in config or env"
raise AttributeError(msg)
def is_from_env(self, key: str) -> bool:
"""
Check if a setting's value comes from an environment variable.
"""Check if a setting's value comes from an environment variable.
Args:
key: The setting key
Returns:
True if the value is set via ENV var, False otherwise
"""
self._ensure_loaded()
@@ -250,12 +274,12 @@ class Config:
registry = _get_registry()
return registry.is_value_from_env(field)
def get_all(self) -> Dict[str, Any]:
"""
Get all cached settings as a dictionary.
def get_all(self) -> dict[str, Any]:
"""Get all cached settings as a dictionary.
Returns:
Dict of all setting keys to their current values
"""
self._ensure_loaded()
return dict(self._cache)
+17 -8
View File
@@ -2,16 +2,20 @@
from __future__ import annotations
from typing import Any, Iterable
from typing import TYPE_CHECKING, Any
from shelfmark.core.auth_modes import AUTH_SOURCE_CWA, normalize_auth_source
from shelfmark.core.external_user_linking import upsert_external_user
from shelfmark.core.user_db import UserDB
if TYPE_CHECKING:
from collections.abc import Iterable
from shelfmark.core.user_db import UserDB
_CWA_ALIAS_SUFFIX = "__cwa"
def _normalize_email(value: Any) -> str | None:
def _normalize_email(value: object) -> str | None:
if value is None:
return None
email = str(value).strip()
@@ -35,12 +39,14 @@ def upsert_cwa_user(
email=normalized_email,
role=role,
allow_email_link=True,
sync_username=True,
collision_strategy=collision_strategy,
alias_suffix=_CWA_ALIAS_SUFFIX,
context=context,
)
if user is None:
raise RuntimeError("Unexpected CWA user sync result: no user returned")
msg = "Unexpected CWA user sync result: no user returned"
raise RuntimeError(msg)
return user, action
@@ -73,10 +79,13 @@ def sync_cwa_users_from_rows(
deleted = 0
for existing_user in user_db.list_users():
if normalize_auth_source(
existing_user.get("auth_source"),
existing_user.get("oidc_subject"),
) != AUTH_SOURCE_CWA:
if (
normalize_auth_source(
existing_user.get("auth_source"),
existing_user.get("oidc_subject"),
)
!= AUTH_SOURCE_CWA
):
continue
existing_id = int(existing_user.get("id") or 0)
+437
View File
@@ -0,0 +1,437 @@
"""Persistence helpers for canonical download activity rows."""
from __future__ import annotations
import json
import sqlite3
import threading
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, SupportsIndex, SupportsInt, TypeGuard
from shelfmark.core.logger import setup_logger
from shelfmark.core.models import TERMINAL_QUEUE_STATUSES
from shelfmark.core.request_helpers import (
normalize_optional_positive_int,
normalize_optional_text,
now_utc_iso,
)
logger = setup_logger(__name__)
VALID_TERMINAL_STATUSES = frozenset(s.value for s in TERMINAL_QUEUE_STATUSES)
ACTIVE_DOWNLOAD_STATUS = "active"
VALID_ORIGINS = frozenset({"direct", "requested"})
def _is_convertible_to_int(
value: object,
) -> TypeGuard[str | bytes | bytearray | SupportsInt | SupportsIndex]:
"""Return True when *value* can be safely passed to ``int``."""
return (
isinstance(value, (str, bytes, bytearray))
or hasattr(value, "__int__")
or hasattr(value, "__index__")
)
def _coerce_int_value(value: object) -> int:
"""Normalize int-like values and raise TypeError for unsupported inputs."""
if isinstance(value, bool) or not _is_convertible_to_int(value):
msg = "limit must be an integer"
raise TypeError(msg)
return int(value)
def _normalize_task_id(task_id: object) -> str:
normalized = normalize_optional_text(task_id)
if normalized is None:
msg = "task_id must be a non-empty string"
raise ValueError(msg)
return normalized
def _normalize_origin(origin: object) -> str:
normalized = normalize_optional_text(origin)
if normalized is None:
return "direct"
lowered = normalized.lower()
if lowered not in VALID_ORIGINS:
msg = "origin must be one of: direct, requested"
raise ValueError(msg)
return lowered
def _normalize_final_status(final_status: object) -> str:
normalized = normalize_optional_text(final_status)
if normalized is None:
msg = "final_status must be a non-empty string"
raise ValueError(msg)
lowered = normalized.lower()
if lowered not in VALID_TERMINAL_STATUSES:
msg = "final_status must be one of: complete, error, cancelled"
raise ValueError(msg)
return lowered
def _normalize_limit(value: object, *, default: int, minimum: int, maximum: int) -> int:
if value is None:
return default
try:
parsed = _coerce_int_value(value)
except (TypeError, ValueError) as exc:
msg = "limit must be an integer"
raise ValueError(msg) from exc
if parsed < minimum:
return minimum
if parsed > maximum:
return maximum
return parsed
class DownloadHistoryService:
"""Service for persisted canonical download activity rows."""
def __init__(self, db_path: str) -> None:
"""Initialize the service with the SQLite history database path."""
self._db_path = db_path
self._lock = threading.Lock()
def _connect(self) -> sqlite3.Connection:
conn = sqlite3.connect(self._db_path)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
return conn
@classmethod
def _normalize_row_dict(cls, row: dict[str, Any] | None) -> dict[str, Any] | None:
if row is None:
return None
normalized = dict(row)
normalized["retry_payload"] = cls._deserialize_retry_payload(
normalized.get("retry_payload")
)
return normalized
@classmethod
def _row_to_dict(cls, row: sqlite3.Row | None) -> dict[str, Any] | None:
return cls._normalize_row_dict(dict(row) if row is not None else None)
@staticmethod
def _to_item_key(task_id: str) -> str:
return f"download:{task_id}"
@staticmethod
def _resolve_existing_download_path(value: object) -> str | None:
normalized = normalize_optional_text(value)
if normalized is None:
return None
return normalized if Path(normalized).exists() else None
@staticmethod
def _serialize_retry_payload(payload: object) -> str | None:
if payload is None:
return None
try:
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
except (TypeError, ValueError) as exc:
msg = "retry_payload must be JSON-serializable"
raise ValueError(msg) from exc
@staticmethod
def _deserialize_retry_payload(value: object) -> dict[str, Any] | None:
if isinstance(value, dict):
return dict(value)
normalized = normalize_optional_text(value)
if normalized is None:
return None
try:
parsed = json.loads(normalized)
except json.JSONDecodeError:
return None
return parsed if isinstance(parsed, dict) else None
@staticmethod
def _has_staged_retry_source(retry_payload: dict[str, Any]) -> bool:
staged_path = retry_payload.get("staged_path")
normalized_staged_path = normalize_optional_text(staged_path)
if normalized_staged_path is None:
return False
return Path(normalized_staged_path).exists()
@staticmethod
def _can_retry_without_staged_source(retry_payload: dict[str, Any]) -> bool:
return bool(retry_payload.get("can_retry_without_staged_source", True))
@staticmethod
def is_retry_available(row: dict[str, Any]) -> bool:
"""Return whether a persisted download row can be retried."""
final_status = (
str(row.get("retry_final_status") or row.get("final_status") or "").strip().lower()
)
retry_payload = DownloadHistoryService._deserialize_retry_payload(row.get("retry_payload"))
if retry_payload is None:
return False
has_staged_retry_source = DownloadHistoryService._has_staged_retry_source(retry_payload)
can_retry_without_staged_source = DownloadHistoryService._can_retry_without_staged_source(
retry_payload
)
request_id = normalize_optional_positive_int(row.get("request_id"), "request_id")
if request_id is None:
if final_status in {ACTIVE_DOWNLOAD_STATUS, "cancelled"}:
return can_retry_without_staged_source
if final_status == "error":
return has_staged_retry_source or can_retry_without_staged_source
return False
if final_status in {ACTIVE_DOWNLOAD_STATUS, "cancelled"}:
return can_retry_without_staged_source
if final_status != "error":
return False
return has_staged_retry_source
@staticmethod
def to_download_payload(row: dict[str, Any]) -> dict[str, Any]:
"""Build the sidebar/history download payload for a persisted row."""
return {
"id": row.get("task_id"),
"title": row.get("title"),
"author": row.get("author"),
"format": row.get("format"),
"size": row.get("size"),
"preview": row.get("preview"),
"content_type": row.get("content_type"),
"source": row.get("source"),
"source_display_name": row.get("source_display_name"),
"downloads": row.get("downloads"),
"status_message": row.get("status_message"),
"download_path": DownloadHistoryService._resolve_existing_download_path(
row.get("download_path")
),
"added_time": DownloadHistoryService._iso_to_epoch(row.get("queued_at")),
"user_id": row.get("user_id"),
"username": row.get("username"),
"request_id": row.get("request_id"),
"retry_available": DownloadHistoryService.is_retry_available(row),
}
@staticmethod
def _iso_to_epoch(value: object) -> float | None:
if not isinstance(value, str) or not value.strip():
return None
normalized = value.strip().replace("Z", "+00:00")
try:
parsed = datetime.fromisoformat(normalized)
except ValueError:
return None
if parsed.tzinfo is None:
parsed = parsed.replace(tzinfo=UTC)
return parsed.timestamp()
@classmethod
def to_history_row(cls, row: dict[str, Any], *, dismissed_at: str) -> dict[str, Any]:
"""Build the activity-history payload for a persisted download row."""
task_id = str(row.get("task_id") or "").strip()
item_key = cls._to_item_key(task_id)
download_payload = cls.to_download_payload(row)
# Clear stale progress messages for non-error terminal states.
if row.get("final_status") in ("complete", "cancelled"):
download_payload["status_message"] = None
return {
"id": item_key,
"user_id": row.get("user_id"),
"item_type": "download",
"item_key": item_key,
"dismissed_at": dismissed_at,
"snapshot": {
"kind": "download",
"download": download_payload,
},
"origin": row.get("origin"),
"final_status": row.get("final_status"),
"terminal_at": row.get("terminal_at"),
"request_id": row.get("request_id"),
"source_id": task_id or None,
}
def record_download(
self,
*,
task_id: str,
user_id: int | None,
username: str | None,
request_id: int | None,
source: str,
source_display_name: str | None,
title: str,
author: str | None,
file_format: str | None,
size: str | None,
preview: str | None,
content_type: str | None,
downloads: int | None,
origin: str,
retry_payload: dict[str, Any] | None = None,
) -> None:
"""Record a download at queue time with final_status='active'.
On first queue: inserts a new row.
On retry (row already exists): resets the row back to 'active'
so the normal finalize path works when the retry completes.
"""
normalized_task_id = _normalize_task_id(task_id)
normalized_user_id = normalize_optional_positive_int(user_id, "user_id")
normalized_request_id = normalize_optional_positive_int(request_id, "request_id")
normalized_source = normalize_optional_text(source)
if normalized_source is None:
msg = "source must be a non-empty string"
raise ValueError(msg)
normalized_title = normalize_optional_text(title)
if normalized_title is None:
msg = "title must be a non-empty string"
raise ValueError(msg)
normalized_origin = _normalize_origin(origin)
normalized_retry_payload = self._serialize_retry_payload(retry_payload)
recorded_at = now_utc_iso()
with self._lock:
conn = self._connect()
try:
conn.execute(
"""
INSERT INTO download_history (
task_id, user_id, username, request_id,
source, source_display_name,
title, author, format, size, preview, content_type,
origin, final_status,
status_message, download_path, retry_payload,
queued_at, terminal_at, downloads
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, ?, ?, ?)
ON CONFLICT(task_id) DO UPDATE SET
final_status = 'active',
status_message = NULL,
download_path = NULL,
retry_payload = excluded.retry_payload,
terminal_at = ?,
downloads = excluded.downloads
""",
(
normalized_task_id,
normalized_user_id,
normalize_optional_text(username),
normalized_request_id,
normalized_source,
normalize_optional_text(source_display_name),
normalized_title,
normalize_optional_text(author),
normalize_optional_text(file_format),
normalize_optional_text(size),
normalize_optional_text(preview),
normalize_optional_text(content_type),
normalized_origin,
normalized_retry_payload,
recorded_at,
recorded_at,
downloads,
recorded_at,
),
)
conn.commit()
finally:
conn.close()
def finalize_download(
self,
*,
task_id: str,
final_status: str,
status_message: str | None = None,
download_path: str | None = None,
retry_payload: dict[str, Any] | None = None,
) -> None:
"""Update an existing download row to its terminal state."""
normalized_task_id = _normalize_task_id(task_id)
normalized_final_status = _normalize_final_status(final_status)
normalized_status_message = normalize_optional_text(status_message)
normalized_download_path = normalize_optional_text(download_path)
normalized_retry_payload = self._serialize_retry_payload(retry_payload)
effective_terminal_at = now_utc_iso()
with self._lock:
conn = self._connect()
try:
cursor = conn.execute(
"""
UPDATE download_history
SET final_status = ?,
status_message = ?,
download_path = ?,
retry_payload = COALESCE(?, retry_payload),
terminal_at = ?
WHERE task_id = ? AND final_status = 'active'
""",
(
normalized_final_status,
normalized_status_message,
normalized_download_path,
normalized_retry_payload,
effective_terminal_at,
normalized_task_id,
),
)
rowcount = int(cursor.rowcount) if cursor.rowcount is not None else 0
if rowcount < 1:
logger.warning(
"finalize_download: no active row found for task_id=%s (may have been missed at queue time)",
normalized_task_id,
)
conn.commit()
finally:
conn.close()
def get_by_task_id(self, task_id: str) -> dict[str, Any] | None:
"""Return a persisted download row for the given task id."""
normalized_task_id = _normalize_task_id(task_id)
conn = self._connect()
try:
row = conn.execute(
"SELECT * FROM download_history WHERE task_id = ?",
(normalized_task_id,),
).fetchone()
return self._row_to_dict(row)
finally:
conn.close()
def list_recent(
self,
*,
user_id: int | None,
limit: int = 200,
) -> list[dict[str, Any]]:
"""Return recent persisted download rows, optionally scoped to one user."""
normalized_user_id = normalize_optional_positive_int(user_id, "user_id")
normalized_limit = _normalize_limit(limit, default=200, minimum=1, maximum=1000)
query = "SELECT * FROM download_history"
params: list[Any] = []
if normalized_user_id is not None:
query += " WHERE user_id = ?"
params.append(normalized_user_id)
query += " ORDER BY terminal_at DESC, id DESC LIMIT ?"
params.append(normalized_limit)
conn = self._connect()
try:
rows = conn.execute(query, params).fetchall()
result: list[dict[str, Any]] = []
for row in rows:
normalized = self._normalize_row_dict(dict(row))
if normalized is not None:
result.append(normalized)
return result
finally:
conn.close()
+116 -33
View File
@@ -3,11 +3,13 @@
from __future__ import annotations
import re
from typing import Any, Literal
from typing import TYPE_CHECKING, Any, Literal
from shelfmark.core.auth_modes import normalize_auth_source
from shelfmark.core.logger import setup_logger
from shelfmark.core.user_db import UserDB
if TYPE_CHECKING:
from shelfmark.core.user_db import UserDB
UNSET = object()
@@ -21,18 +23,18 @@ MatchReason = Literal[
logger = setup_logger(__name__)
def _normalize_username(value: Any) -> str:
def _normalize_username(value: object) -> str:
return str(value or "").strip()
def _normalize_email(value: Any) -> str | None:
def _normalize_email(value: object) -> str | None:
if value is None:
return None
email = str(value).strip()
return email or None
def _normalize_display_name(value: Any) -> str | None:
def _normalize_display_name(value: object) -> str | None:
if value is None:
return None
name = str(value).strip()
@@ -43,11 +45,13 @@ def _email_key(value: str | None) -> str:
return (value or "").strip().lower()
def _normalize_role(value: Any) -> str:
def _normalize_role(value: object) -> str:
return "admin" if str(value or "").strip().lower() == "admin" else "user"
def _get_by_subject(user_db: UserDB, subject_field: str | None, subject: str | None) -> dict[str, Any] | None:
def _get_by_subject(
user_db: UserDB, subject_field: str | None, subject: str | None
) -> dict[str, Any] | None:
if not subject_field or not subject:
return None
if subject_field == "oidc_subject":
@@ -56,6 +60,7 @@ def _get_by_subject(user_db: UserDB, subject_field: str | None, subject: str | N
def find_unique_user_by_email(user_db: UserDB, email: str | None) -> dict[str, Any] | None:
"""Return the unique local user matching an email address, if any."""
key = _email_key(_normalize_email(email))
if not key:
return None
@@ -83,10 +88,14 @@ def find_external_user_match(
return by_subject, "subject_match"
by_username = user_db.get_user(username=normalized_username)
if by_username and normalize_auth_source(
by_username.get("auth_source"),
by_username.get("oidc_subject"),
) == auth_source:
if (
by_username
and normalize_auth_source(
by_username.get("auth_source"),
by_username.get("oidc_subject"),
)
== auth_source
):
return by_username, "existing_source_username_match"
if allow_email_link:
@@ -99,6 +108,7 @@ def _build_updates(
auth_source: str,
role: str,
sync_role: bool,
username: str | object,
email: str | None | object,
display_name: str | None | object,
subject_field: str | None,
@@ -107,6 +117,8 @@ def _build_updates(
updates: dict[str, Any] = {"auth_source": auth_source}
if sync_role:
updates["role"] = _normalize_role(role)
if username is not UNSET:
updates["username"] = _normalize_username(username)
if email is not UNSET:
updates["email"] = _normalize_email(email)
if display_name is not UNSET:
@@ -116,10 +128,17 @@ def _build_updates(
return updates
def _next_suffix_username(user_db: UserDB, base_username: str) -> str:
def _next_suffix_username(
user_db: UserDB,
base_username: str,
*,
exclude_user_id: int | None = None,
) -> str:
candidate = base_username
suffix = 1
while user_db.get_user(username=candidate):
while existing := user_db.get_user(username=candidate):
if exclude_user_id is not None and int(existing.get("id") or 0) == exclude_user_id:
return candidate
candidate = f"{base_username}_{suffix}"
suffix += 1
return candidate
@@ -133,13 +152,14 @@ def _find_existing_alias_user(
) -> dict[str, Any] | None:
pattern = re.compile(rf"^{re.escape(alias_base)}(?:_\d+)?$")
candidates = [
user for user in user_db.list_users()
user
for user in user_db.list_users()
if pattern.match(str(user.get("username") or ""))
and normalize_auth_source(user.get("auth_source"), user.get("oidc_subject")) == auth_source
]
if not candidates:
return None
return sorted(candidates, key=lambda user: int(user.get("id") or 0))[0]
return min(candidates, key=lambda user: int(user.get("id") or 0), default=None)
def _resolve_create_username(
@@ -158,7 +178,11 @@ def _resolve_create_username(
return None, existing, "username_collision_takeover"
if strategy == "suffix":
return _next_suffix_username(user_db, requested_username), None, "username_collision_suffix"
return (
_next_suffix_username(user_db, requested_username),
None,
"username_collision_suffix",
)
alias_base = f"{requested_username}{alias_suffix}"
alias_existing = _find_existing_alias_user(
@@ -171,6 +195,38 @@ def _resolve_create_username(
return _next_suffix_username(user_db, alias_base), None, "username_collision_alias"
def _resolve_update_username(
user_db: UserDB,
*,
current_user: dict[str, Any],
requested_username: str,
strategy: CollisionStrategy,
alias_suffix: str,
) -> str:
current_user_id = int(current_user["id"])
existing = user_db.get_user(username=requested_username)
if existing is None or int(existing.get("id") or 0) == current_user_id:
return requested_username
if strategy == "suffix":
return _next_suffix_username(
user_db,
requested_username,
exclude_user_id=current_user_id,
)
if strategy == "alias":
return _next_suffix_username(
user_db,
f"{requested_username}{alias_suffix}",
exclude_user_id=current_user_id,
)
# `takeover` can select an existing row during creation, but once an
# identity is already matched it must never replace a different username
# owner. Preserve the matched row's current collision-free name instead.
return str(current_user["username"])
def upsert_external_user(
user_db: UserDB,
*,
@@ -183,6 +239,7 @@ def upsert_external_user(
subject: str | None = None,
allow_email_link: bool = False,
sync_role: bool = True,
sync_username: bool = False,
allow_create: bool = True,
collision_strategy: CollisionStrategy = "takeover",
alias_suffix: str | None = None,
@@ -197,7 +254,8 @@ def upsert_external_user(
"""
normalized_username = _normalize_username(username)
if not normalized_username:
raise ValueError("External username is required")
msg = "External username is required"
raise ValueError(msg)
normalized_email = _normalize_email(email) if email is not UNSET else None
normalized_display_name = (
@@ -214,10 +272,26 @@ def upsert_external_user(
subject=subject,
allow_email_link=allow_email_link,
)
resolved_alias_suffix = alias_suffix or f"__{auth_source}"
update_username: str | object = UNSET
if (
matched is not None
and sync_username
and normalize_auth_source(matched.get("auth_source"), matched.get("oidc_subject"))
== auth_source
):
update_username = _resolve_update_username(
user_db,
current_user=matched,
requested_username=normalized_username,
strategy=collision_strategy,
alias_suffix=resolved_alias_suffix,
)
updates = _build_updates(
auth_source=auth_source,
role=normalized_role,
sync_role=sync_role,
username=update_username,
email=normalized_email if email is not UNSET else UNSET,
display_name=normalized_display_name if display_name is not UNSET else UNSET,
subject_field=subject_field,
@@ -227,22 +301,25 @@ def upsert_external_user(
user_db.update_user(matched["id"], **updates)
mapped = user_db.get_user(user_id=matched["id"]) or matched
logger.info(
"External user mapped to existing Shelfmark user "
f"(source={auth_source}, context={context or 'unspecified'}, reason={match_reason}, "
f"external_username={normalized_username}, shelfmark_user_id={mapped['id']}, "
f"shelfmark_username={mapped['username']})"
"External user mapped to existing Shelfmark user (source=%s, context=%s, reason=%s, external_username=%s, shelfmark_user_id=%s, shelfmark_username=%s)",
auth_source,
context or "unspecified",
match_reason,
normalized_username,
mapped["id"],
mapped["username"],
)
return mapped, "updated"
if not allow_create:
logger.info(
"External user could not be mapped and creation is disabled "
f"(source={auth_source}, context={context or 'unspecified'}, "
f"external_username={normalized_username})"
"External user could not be mapped and creation is disabled (source=%s, context=%s, external_username=%s)",
auth_source,
context or "unspecified",
normalized_username,
)
return None, "not_found"
resolved_alias_suffix = alias_suffix or f"__{auth_source}"
create_username, takeover_target, create_reason = _resolve_create_username(
user_db,
auth_source=auth_source,
@@ -254,10 +331,13 @@ def upsert_external_user(
user_db.update_user(takeover_target["id"], **updates)
mapped = user_db.get_user(user_id=takeover_target["id"]) or takeover_target
logger.info(
"External user mapped to existing Shelfmark user "
f"(source={auth_source}, context={context or 'unspecified'}, reason={create_reason}, "
f"external_username={normalized_username}, shelfmark_user_id={mapped['id']}, "
f"shelfmark_username={mapped['username']})"
"External user mapped to existing Shelfmark user (source=%s, context=%s, reason=%s, external_username=%s, shelfmark_user_id=%s, shelfmark_username=%s)",
auth_source,
context or "unspecified",
create_reason,
normalized_username,
mapped["id"],
mapped["username"],
)
return mapped, "updated"
@@ -275,9 +355,12 @@ def upsert_external_user(
created = user_db.create_user(**create_kwargs)
logger.info(
"External user created Shelfmark user "
f"(source={auth_source}, context={context or 'unspecified'}, reason={create_reason}, "
f"external_username={normalized_username}, shelfmark_user_id={created['id']}, "
f"shelfmark_username={created['username']})"
"External user created Shelfmark user (source=%s, context=%s, reason=%s, external_username=%s, shelfmark_user_id=%s, shelfmark_username=%s)",
auth_source,
context or "unspecified",
create_reason,
normalized_username,
created["id"],
created["username"],
)
return created, "created"
+221 -120
View File
@@ -1,37 +1,45 @@
"""Disk-based image cache with LRU eviction."""
import ipaddress
import json
import os
import socket
import threading
import time
from http import HTTPStatus
from io import BytesIO
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
from typing import TYPE_CHECKING, Any
from urllib.parse import urljoin, urlparse
import requests
from shelfmark.core.logger import setup_logger
from shelfmark.core.request_helpers import coerce_int
from shelfmark.download.network import get_ssl_verify
if TYPE_CHECKING:
from pathlib import Path
logger = setup_logger(__name__)
# Image type detection via magic bytes
IMAGE_SIGNATURES = {
b'\xff\xd8\xff': ('image/jpeg', 'jpg'),
b'\x89PNG\r\n\x1a\n': ('image/png', 'png'),
b'GIF87a': ('image/gif', 'gif'),
b'GIF89a': ('image/gif', 'gif'),
b'RIFF': ('image/webp', 'webp'), # WebP starts with RIFF
b"\xff\xd8\xff": ("image/jpeg", "jpg"),
b"\x89PNG\r\n\x1a\n": ("image/png", "png"),
b"GIF87a": ("image/gif", "gif"),
b"GIF89a": ("image/gif", "gif"),
b"RIFF": ("image/webp", "webp"), # WebP starts with RIFF
}
# HTTP headers for image fetching
FETCH_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/129.0.0.0 Safari/537.36',
'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/129.0.0.0 Safari/537.36",
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
}
# Maximum image size to fetch (5 MB)
MAX_IMAGE_SIZE = 5 * 1024 * 1024
MAX_REDIRECTS = 5
# Negative cache TTL (for failed fetches) - 1 hour
NEGATIVE_CACHE_TTL = 3600
@@ -40,8 +48,11 @@ NEGATIVE_CACHE_TTL = 3600
# Short enough to retry soon, long enough to prevent spam during one page view
TRANSIENT_CACHE_TTL = 60
_MIN_WEBP_HEADER_LENGTH = 12
HTTP_NOT_FOUND = HTTPStatus.NOT_FOUND
def _detect_image_type(data: bytes) -> Optional[Tuple[str, str]]:
def _detect_image_type(data: bytes) -> tuple[str, str] | None:
"""Detect image type from magic bytes.
Args:
@@ -49,14 +60,15 @@ def _detect_image_type(data: bytes) -> Optional[Tuple[str, str]]:
Returns:
Tuple of (content_type, extension) or None if not recognized
"""
for signature, (content_type, ext) in IMAGE_SIGNATURES.items():
if data.startswith(signature):
return content_type, ext
# Special case for WebP - check for WEBP after RIFF
if data.startswith(b'RIFF') and len(data) > 12 and data[8:12] == b'WEBP':
return 'image/webp', 'webp'
if data.startswith(b"RIFF") and len(data) > _MIN_WEBP_HEADER_LENGTH and data[8:12] == b"WEBP":
return "image/webp", "webp"
return None
@@ -64,20 +76,21 @@ def _detect_image_type(data: bytes) -> Optional[Tuple[str, str]]:
class ImageCacheService:
"""Persistent image cache with LRU eviction and TTL support."""
def __init__(self, cache_dir: Path, max_size_mb: int = 500, ttl_seconds: int = 0):
def __init__(self, cache_dir: Path, max_size_mb: int = 500, ttl_seconds: int = 0) -> None:
"""Initialize the image cache.
Args:
cache_dir: Directory to store cached images
max_size_mb: Maximum cache size in megabytes
ttl_seconds: Time-to-live in seconds (0 = forever)
"""
self.cache_dir = cache_dir
self.max_size_bytes = max_size_mb * 1024 * 1024
self.ttl_seconds = ttl_seconds
self.index_path = cache_dir / "cache_index.json"
self._lock = threading.RLock()
self._index: Dict[str, Dict[str, Any]] = {}
self._index: dict[str, dict[str, Any]] = {}
# Stats tracking
self._hits = 0
@@ -97,9 +110,9 @@ class ImageCacheService:
return
try:
with open(self.index_path, 'r') as f:
with self.index_path.open() as f:
self._index = json.load(f)
except (json.JSONDecodeError, IOError):
except OSError, json.JSONDecodeError:
self._index = {}
def _sync_index_with_files(self) -> None:
@@ -109,12 +122,12 @@ class ImageCacheService:
- Removes entries for files that no longer exist (non-negative only)
- Preserves negative cache entries (they have no files)
"""
image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.webp'}
image_extensions = {".jpg", ".jpeg", ".png", ".gif", ".webp"}
added_count = 0
removed_count = 0
# Build set of files that exist on disk
existing_files: Dict[str, Path] = {}
existing_files: dict[str, Path] = {}
for file_path in self.cache_dir.iterdir():
if not file_path.is_file():
continue
@@ -127,31 +140,31 @@ class ImageCacheService:
if cache_id in self._index:
continue
ext = file_path.suffix.lstrip('.')
ext = file_path.suffix.lstrip(".")
stat = file_path.stat()
# Detect content type
try:
with open(file_path, 'rb') as f:
with file_path.open("rb") as f:
header = f.read(16)
detected = _detect_image_type(header)
content_type = detected[0] if detected else f'image/{ext}'
except IOError:
content_type = f'image/{ext}'
content_type = detected[0] if detected else f"image/{ext}"
except OSError:
content_type = f"image/{ext}"
self._index[cache_id] = {
'ext': ext,
'content_type': content_type,
'size': stat.st_size,
'cached_at': stat.st_mtime,
'accessed_at': stat.st_mtime,
"ext": ext,
"content_type": content_type,
"size": stat.st_size,
"cached_at": stat.st_mtime,
"accessed_at": stat.st_mtime,
}
added_count += 1
# Remove index entries for missing files (skip negative cache entries)
stale_entries = []
for cache_id, entry in self._index.items():
if entry.get('negative', False):
if entry.get("negative", False):
continue # Negative entries don't have files
if cache_id not in existing_files:
stale_entries.append(cache_id)
@@ -167,39 +180,39 @@ class ImageCacheService:
"""Save cache index to disk."""
try:
# Write to temp file first, then rename for atomicity
temp_path = self.index_path.with_suffix('.tmp')
with open(temp_path, 'w') as f:
temp_path = self.index_path.with_suffix(".tmp")
with temp_path.open("w") as f:
json.dump(self._index, f)
temp_path.rename(self.index_path)
except IOError:
except OSError:
pass
def _get_image_path(self, cache_id: str, ext: str) -> Path:
"""Get the file path for a cached image."""
return self.cache_dir / f"{cache_id}.{ext}"
def _is_expired(self, entry: Dict[str, Any]) -> bool:
def _is_expired(self, entry: dict[str, Any]) -> bool:
"""Check if a cache entry is expired."""
if self.ttl_seconds == 0:
return False
return (time.time() - entry.get('cached_at', 0)) > self.ttl_seconds
return (time.time() - entry.get("cached_at", 0)) > self.ttl_seconds
def _is_negative_expired(self, entry: Dict[str, Any]) -> bool:
def _is_negative_expired(self, entry: dict[str, Any]) -> bool:
"""Check if a negative cache entry is expired.
Transient failures (timeouts) expire after TRANSIENT_CACHE_TTL (60s).
Permanent failures (404s) expire after NEGATIVE_CACHE_TTL (1 hour).
"""
if not entry.get('negative', False):
if not entry.get("negative", False):
return False
cached_at = entry.get('cached_at', 0)
ttl = TRANSIENT_CACHE_TTL if entry.get('transient', False) else NEGATIVE_CACHE_TTL
cached_at = entry.get("cached_at", 0)
ttl = TRANSIENT_CACHE_TTL if entry.get("transient", False) else NEGATIVE_CACHE_TTL
return (time.time() - cached_at) > ttl
def _calculate_total_size(self) -> int:
"""Calculate total size of cached images."""
return sum(entry.get('size', 0) for entry in self._index.values())
return sum(entry.get("size", 0) for entry in self._index.values())
def _evict_if_needed(self, required_space: int = 0) -> None:
"""Evict old entries if cache is over size limit.
@@ -213,10 +226,7 @@ class ImageCacheService:
return
# Sort entries by accessed_at (oldest first)
sorted_entries = sorted(
self._index.items(),
key=lambda x: x[1].get('accessed_at', 0)
)
sorted_entries = sorted(self._index.items(), key=lambda x: x[1].get("accessed_at", 0))
evicted_count = 0
for cache_id, entry in sorted_entries:
@@ -224,23 +234,23 @@ class ImageCacheService:
break
# Delete the image file
ext = entry.get('ext', 'jpg')
ext = entry.get("ext", "jpg")
image_path = self._get_image_path(cache_id, ext)
try:
if image_path.exists():
image_path.unlink()
except IOError:
except OSError:
pass
# Update tracking
current_size -= entry.get('size', 0)
current_size -= entry.get("size", 0)
del self._index[cache_id]
evicted_count += 1
if evicted_count > 0:
self._save_index()
def get(self, cache_id: str) -> Optional[Tuple[bytes, str]]:
def get(self, cache_id: str) -> tuple[bytes, str] | None:
"""Get a cached image.
Args:
@@ -248,6 +258,7 @@ class ImageCacheService:
Returns:
Tuple of (image_data, content_type) or None if not cached/expired
"""
with self._lock:
entry = self._index.get(cache_id)
@@ -261,7 +272,7 @@ class ImageCacheService:
return None
# Check for negative cache (failed fetch)
if entry.get('negative', False):
if entry.get("negative", False):
if self._is_negative_expired(entry):
# Negative cache expired, allow retry
del self._index[cache_id]
@@ -274,12 +285,12 @@ class ImageCacheService:
# Check for expired entry
if self._is_expired(entry):
# Remove expired entry
ext = entry.get('ext', 'jpg')
ext = entry.get("ext", "jpg")
image_path = self._get_image_path(cache_id, ext)
try:
if image_path.exists():
image_path.unlink()
except IOError:
except OSError:
pass
del self._index[cache_id]
self._save_index()
@@ -287,9 +298,10 @@ class ImageCacheService:
return None
# Try to read the cached image
ext = entry.get('ext', 'jpg')
content_type = entry.get('content_type', 'image/jpeg')
ext = entry.get("ext", "jpg")
content_type = entry.get("content_type", "image/jpeg")
image_path = self._get_image_path(cache_id, ext)
result: tuple[bytes, str] | None = None
try:
if not image_path.exists():
@@ -299,19 +311,20 @@ class ImageCacheService:
self._misses += 1
return None
with open(image_path, 'rb') as f:
with image_path.open("rb") as f:
data = f.read()
# Update accessed time
entry['accessed_at'] = time.time()
entry["accessed_at"] = time.time()
self._save_index()
result = data, content_type
self._hits += 1
return data, content_type
except IOError:
except OSError:
self._misses += 1
return None
else:
self._hits += 1
return result
def put(self, cache_id: str, data: bytes, content_type: str) -> bool:
"""Store an image in the cache.
@@ -323,24 +336,24 @@ class ImageCacheService:
Returns:
True if stored successfully
"""
with self._lock:
# Detect image type for extension
detected = _detect_image_type(data)
if detected:
content_type, ext = detected
# Fall back to content-type header
elif "jpeg" in content_type or "jpg" in content_type:
ext = "jpg"
elif "png" in content_type:
ext = "png"
elif "gif" in content_type:
ext = "gif"
elif "webp" in content_type:
ext = "webp"
else:
# Fall back to content-type header
if 'jpeg' in content_type or 'jpg' in content_type:
ext = 'jpg'
elif 'png' in content_type:
ext = 'png'
elif 'gif' in content_type:
ext = 'gif'
elif 'webp' in content_type:
ext = 'webp'
else:
ext = 'jpg' # Default
ext = "jpg" # Default
image_size = len(data)
@@ -350,36 +363,37 @@ class ImageCacheService:
# Write image to disk
image_path = self._get_image_path(cache_id, ext)
try:
with open(image_path, 'wb') as f:
with image_path.open("wb") as f:
f.write(data)
except IOError:
except OSError:
return False
# Update index
now = time.time()
self._index[cache_id] = {
'ext': ext,
'content_type': content_type,
'size': image_size,
'cached_at': now,
'accessed_at': now,
'negative': False,
"ext": ext,
"content_type": content_type,
"size": image_size,
"cached_at": now,
"accessed_at": now,
"negative": False,
}
self._save_index()
return True
def put_negative(self, cache_id: str, transient: bool = False) -> None:
def put_negative(self, cache_id: str, *, transient: bool = False) -> None:
"""Store a negative cache entry (failed fetch).
Args:
cache_id: Cache key
transient: If True, uses shorter TTL (for timeouts/connection errors)
"""
with self._lock:
self._index[cache_id] = {
'negative': True,
'transient': transient,
'cached_at': time.time(),
"negative": True,
"transient": transient,
"cached_at": time.time(),
}
self._save_index()
@@ -391,6 +405,7 @@ class ImageCacheService:
Returns:
True if entry existed and was deleted
"""
with self._lock:
entry = self._index.get(cache_id)
@@ -398,13 +413,13 @@ class ImageCacheService:
return False
# Delete file if it exists
if not entry.get('negative', False):
ext = entry.get('ext', 'jpg')
if not entry.get("negative", False):
ext = entry.get("ext", "jpg")
image_path = self._get_image_path(cache_id, ext)
try:
if image_path.exists():
image_path.unlink()
except IOError:
except OSError:
pass
del self._index[cache_id]
@@ -416,19 +431,20 @@ class ImageCacheService:
Returns:
Number of entries cleared
"""
with self._lock:
count = len(self._index)
# Delete all image files
for cache_id, entry in self._index.items():
if not entry.get('negative', False):
ext = entry.get('ext', 'jpg')
if not entry.get("negative", False):
ext = entry.get("ext", "jpg")
image_path = self._get_image_path(cache_id, ext)
try:
if image_path.exists():
image_path.unlink()
except IOError:
except OSError:
pass
# Clear index
@@ -441,31 +457,113 @@ class ImageCacheService:
return count
def stats(self) -> Dict[str, Any]:
def stats(self) -> dict[str, Any]:
"""Get cache statistics.
Returns:
Dict with size, count, hit rate, etc.
"""
with self._lock:
total_size = self._calculate_total_size()
entry_count = len(self._index)
negative_count = sum(1 for e in self._index.values() if e.get('negative', False))
negative_count = sum(1 for e in self._index.values() if e.get("negative", False))
total_requests = self._hits + self._misses
hit_rate = (self._hits / total_requests * 100) if total_requests > 0 else 0
return {
'entry_count': entry_count,
'negative_count': negative_count,
'total_size_bytes': total_size,
'total_size_mb': round(total_size / (1024 * 1024), 2),
'max_size_mb': self.max_size_bytes / (1024 * 1024),
'hits': self._hits,
'misses': self._misses,
'hit_rate': round(hit_rate, 1),
"entry_count": entry_count,
"negative_count": negative_count,
"total_size_bytes": total_size,
"total_size_mb": round(total_size / (1024 * 1024), 2),
"max_size_mb": self.max_size_bytes / (1024 * 1024),
"hits": self._hits,
"misses": self._misses,
"hit_rate": round(hit_rate, 1),
}
def fetch_and_cache(self, cache_id: str, url: str) -> Optional[Tuple[bytes, str]]:
@staticmethod
def _prepare_safe_url(url: str) -> str | None:
"""Prepare and validate a URL before fetching it."""
if "\\" in url or any(ord(char) < 32 for char in url):
return None
try:
prepared = requests.Request("GET", url).prepare()
prepared_url = prepared.url
if not isinstance(prepared_url, str):
return None
parsed = urlparse(prepared_url)
hostname = parsed.hostname
except requests.exceptions.RequestException, ValueError:
return None
if not prepared_url:
return None
if "\\" in prepared_url or any(ord(char) < 32 for char in prepared_url):
return None
netloc_lower = parsed.netloc.lower()
if "%2f" in netloc_lower or "%5c" in netloc_lower:
return None
if parsed.scheme not in ("http", "https"):
return None
if not hostname:
return None
try:
resolved = socket.getaddrinfo(hostname, None)
for _, _, _, _, sockaddr in resolved:
ip = ipaddress.ip_address(sockaddr[0])
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
return None
except socket.gaierror, ValueError:
return None
return prepared_url
@staticmethod
def _is_safe_url(url: str) -> bool:
"""Check that a URL is safe to fetch (no SSRF to internal resources)."""
return ImageCacheService._prepare_safe_url(url) is not None
def _fetch_safe_response(self, url: str) -> requests.Response | None:
"""Fetch a URL after validating the initial URL and each redirect."""
current_url = self._prepare_safe_url(url)
if not current_url:
logger.warning("Blocked request to disallowed URL: %s", url)
return None
for _ in range(MAX_REDIRECTS + 1):
response = requests.get(
current_url,
timeout=(5, 10),
headers=FETCH_HEADERS,
stream=True,
verify=get_ssl_verify(current_url),
allow_redirects=False,
)
if not response.is_redirect:
return response
location = response.headers.get("location")
response.close()
if not location:
return None
redirect_url = urljoin(current_url, location)
next_url = self._prepare_safe_url(redirect_url)
if not next_url:
logger.warning("Blocked redirect to disallowed URL: %s", redirect_url)
return None
current_url = next_url
return None
def fetch_and_cache(self, cache_id: str, url: str) -> tuple[bytes, str] | None:
"""Fetch an image from URL and cache it.
Args:
@@ -474,20 +572,18 @@ class ImageCacheService:
Returns:
Tuple of (image_data, content_type) or None on failure
"""
try:
response = requests.get(
url,
timeout=(5, 10),
headers=FETCH_HEADERS,
stream=True,
)
"""
cached_data: tuple[bytes, str] | None = None
try:
response = self._fetch_safe_response(url)
if response is None:
return None
response.raise_for_status()
# Validate content type
content_type = response.headers.get('content-type', '')
if not content_type.startswith('image/'):
content_type = response.headers.get("content-type", "")
if not content_type.startswith("image/"):
self.put_negative(cache_id)
return None
@@ -511,9 +607,7 @@ class ImageCacheService:
detected = _detect_image_type(image_data)
if detected:
content_type = detected[0]
return image_data, content_type
return None
cached_data = image_data, content_type
except requests.exceptions.Timeout:
self.put_negative(cache_id, transient=True)
@@ -522,15 +616,17 @@ class ImageCacheService:
self.put_negative(cache_id, transient=True)
return None
except requests.exceptions.HTTPError as e:
is_404 = e.response is not None and e.response.status_code == 404
is_404 = e.response is not None and e.response.status_code == HTTP_NOT_FOUND
self.put_negative(cache_id, transient=not is_404)
return None
except Exception:
except requests.exceptions.RequestException:
return None
else:
return cached_data
# Singleton instance (initialized lazily when config is available)
_instance: Optional[ImageCacheService] = None
_instance: ImageCacheService | None = None
_instance_lock = threading.Lock()
@@ -544,12 +640,12 @@ def get_image_cache() -> ImageCacheService:
if _instance is None:
with _instance_lock:
if _instance is None:
from shelfmark.core.config import config
from shelfmark.config.env import CONFIG_DIR
from shelfmark.core.config import config
cache_dir = CONFIG_DIR / "covers"
max_size_mb = config.get("COVERS_CACHE_MAX_SIZE_MB", 500)
ttl_days = config.get("COVERS_CACHE_TTL", 0)
max_size_mb = coerce_int(config.get("COVERS_CACHE_MAX_SIZE_MB", 500), 500)
ttl_days = coerce_int(config.get("COVERS_CACHE_TTL", 0), 0)
ttl_seconds = ttl_days * 86400 if ttl_days > 0 else 0
_instance = ImageCacheService(
@@ -557,7 +653,12 @@ def get_image_cache() -> ImageCacheService:
max_size_mb=max_size_mb,
ttl_seconds=ttl_seconds,
)
logger.debug(f"Initialized image cache: {cache_dir} (max {max_size_mb}MB, TTL {ttl_days} days)")
logger.debug(
"Initialized image cache: %s (max %sMB, TTL %s days)",
cache_dir,
max_size_mb,
ttl_days,
)
return _instance
+138
View File
@@ -0,0 +1,138 @@
"""Canonical language resolution shared by every release source.
Release sources report a language in whatever shape their upstream uses: a
two-letter code, an ISO 639-2 three-letter code in either the bibliographic or
terminological form, or an English name. They all need the same ISO 639-1 code
out the other side, so the aliases live in one place (``data/book-languages.json``)
and adding a language means editing one file.
"""
import json
import threading
import unicodedata
from pathlib import Path
from shelfmark.core.logger import setup_logger
logger = setup_logger(__name__)
LANGUAGE_DATA_PATH = Path(__file__).resolve().parents[1].parent / "data" / "book-languages.json"
# Values a source uses to mean "we could not tell".
LANGUAGE_PLACEHOLDERS = frozenset({"", "-", "--", "unknown", "unk", "n/a", "na", "none", "null"})
_ALIAS_TO_CODE: dict[str, str] | None = None
_CODE_TO_NAME: dict[str, str] | None = None
_LOCK = threading.Lock()
# Separators that stand in for the hyphen in a subtag. The dashes turn up in
# codes copied from web pages -- "zhHant" used U+2011, which renders close
# enough to both a hyphen and an underscore to go unnoticed -- and the
# underscore is the spelling Direct Download accepted before this module existed.
_SUBTAG_SEPARATORS = dict.fromkeys(map(ord, "‐‑‒–—―−﹘﹣-_"), "-")
def _fold(value: str) -> str:
"""Casefold, strip accents, and normalize subtag separators, so 'Español'
and 'espanol', or 'zh-Hant', 'zhHant' and 'zh_Hant', all match."""
decomposed = unicodedata.normalize("NFKD", value).translate(_SUBTAG_SEPARATORS)
stripped = "".join(ch for ch in decomposed if not unicodedata.combining(ch))
return " ".join(stripped.split()).casefold()
def _load() -> tuple[dict[str, str], dict[str, str]]:
global _ALIAS_TO_CODE, _CODE_TO_NAME
if _ALIAS_TO_CODE is not None and _CODE_TO_NAME is not None:
return _ALIAS_TO_CODE, _CODE_TO_NAME
with _LOCK:
if _ALIAS_TO_CODE is not None and _CODE_TO_NAME is not None:
return _ALIAS_TO_CODE, _CODE_TO_NAME
alias_to_code: dict[str, str] = {}
code_to_name: dict[str, str] = {}
try:
raw = json.loads(LANGUAGE_DATA_PATH.read_text(encoding="utf-8"))
except OSError, ValueError:
logger.exception("Failed to load language data from %s", LANGUAGE_DATA_PATH)
raw = []
if not isinstance(raw, list):
logger.warning("Language data at %s is not a list", LANGUAGE_DATA_PATH)
raw = []
for item in raw:
if not isinstance(item, dict):
continue
code = str(item.get("code") or "").strip()
name = str(item.get("language") or "").strip()
if not code:
continue
code_to_name.setdefault(code, name or code)
for candidate in (code, name, *(item.get("aliases") or [])):
folded = _fold(str(candidate))
if folded and folded not in LANGUAGE_PLACEHOLDERS:
alias_to_code.setdefault(folded, code)
_ALIAS_TO_CODE = alias_to_code
_CODE_TO_NAME = code_to_name
return alias_to_code, code_to_name
def normalize_language(value: object) -> str | None:
"""Resolve any known spelling of a language to its ISO 639-1 code.
Accepts a two-letter code, an ISO 639-2 three-letter code in either the
bibliographic or terminological form, or an English name. Returns None for
anything unrecognised or for the placeholders a source uses to say it does
not know, so callers can treat "no language" uniformly.
"""
if value is None:
return None
folded = _fold(str(value))
if not folded or folded in LANGUAGE_PLACEHOLDERS:
return None
alias_to_code, _ = _load()
return alias_to_code.get(folded)
def language_name(code: str | None) -> str | None:
"""Return the English name for a language code, or None if unknown."""
if not code:
return None
_, code_to_name = _load()
return code_to_name.get(str(code).strip())
def language_alias_map() -> dict[str, str]:
"""Every known alias mapped to its code, for callers doing their own matching.
Direct Download scans free-text paths and needs the whole alias set up front
to look for, rather than resolving one candidate at a time.
"""
alias_to_code, _ = _load()
return dict(alias_to_code)
def supported_book_languages() -> list[dict[str, str]]:
"""The selectable languages, as ``{"language": ..., "code": ...}``.
Aliases are an implementation detail of resolution, so they are left out of
what the settings dropdown and the API hand to clients.
"""
_, code_to_name = _load()
return [{"language": name, "code": code} for code, name in code_to_name.items()]
def known_language_codes() -> frozenset[str]:
"""Every ISO 639-1 code the bundled language data defines."""
_, code_to_name = _load()
return frozenset(code_to_name)
+112 -48
View File
@@ -2,62 +2,91 @@
import logging
import sys
from pathlib import Path
from collections.abc import Mapping
from logging.handlers import RotatingFileHandler
from typing import Any
from threading import Lock
from typing import TYPE_CHECKING
from shelfmark.config.env import LOG_FILE, ENABLE_LOGGING, LOG_LEVEL
from shelfmark.config.env import ENABLE_LOGGING, LOG_FILE, LOG_LEVEL
if TYPE_CHECKING:
from pathlib import Path
_file_handlers: dict[Path, RotatingFileHandler] = {}
_file_handlers_lock = Lock()
class CustomLogger(logging.Logger):
"""Custom logger class with additional error_trace method."""
def error_trace(self, msg: Any, *args: Any, **kwargs: Any) -> None:
def error_trace(self, msg: object, *args: object, **kwargs: object) -> None:
"""Log an error message with full stack trace."""
self.log_resource_usage()
kwargs.pop('exc_info', None)
self.error(msg, *args, exc_info=True, **kwargs)
stack_info, stacklevel, extra = _extract_log_kwargs(kwargs)
self.error(
msg,
*args,
exc_info=True,
stack_info=stack_info,
stacklevel=stacklevel,
extra=extra,
)
def warning_trace(self, msg: Any, *args: Any, **kwargs: Any) -> None:
"""Log a warning message with full stack trace."""
self.log_resource_usage()
kwargs.pop('exc_info', None)
self.warning(msg, *args, exc_info=True, **kwargs)
def info_trace(self, msg: Any, *args: Any, **kwargs: Any) -> None:
"""Log an info message (stack trace only if exception active)."""
kwargs.pop('exc_info', None)
# Only include exc_info if there's actually an exception
has_exception = sys.exc_info()[0] is not None
self.info(msg, *args, exc_info=has_exception, **kwargs)
def debug_trace(self, msg: Any, *args: Any, **kwargs: Any) -> None:
def debug_trace(self, msg: object, *args: object, **kwargs: object) -> None:
"""Log a debug message (stack trace only if exception active)."""
kwargs.pop('exc_info', None)
stack_info, stacklevel, extra = _extract_log_kwargs(kwargs)
# Only include exc_info if there's actually an exception
has_exception = sys.exc_info()[0] is not None
self.debug(msg, *args, exc_info=has_exception, **kwargs)
self.debug(
msg,
*args,
exc_info=has_exception,
stack_info=stack_info,
stacklevel=stacklevel,
extra=extra,
)
def log_resource_usage(self):
# Best-effort only; this should never raise during exception logging.
def log_resource_usage(self) -> None:
"""Log best-effort CPU and memory usage for the current container."""
try:
import psutil
except ImportError:
return
# Best-effort only; this should never raise during exception logging.
try:
def _get_process_rss_mb(proc: object) -> float | None:
try:
proc_info = getattr(proc, "info", None)
if not isinstance(proc_info, Mapping):
return None
mem = proc_info.get("memory_info")
rss = getattr(mem, "rss", None)
if isinstance(rss, int | float):
return rss / (1024 * 1024)
except (
psutil.NoSuchProcess,
psutil.AccessDenied,
KeyError,
AttributeError,
):
return None
return None
# Sum RSS of all processes for actual app memory (container-friendly),
# but fall back gracefully on platforms that restrict process enumeration.
app_memory_mb = 0.0
try:
for proc in psutil.process_iter(['memory_info']):
try:
mem = proc.info.get('memory_info')
if mem:
app_memory_mb += mem.rss / (1024 * 1024)
except (psutil.NoSuchProcess, psutil.AccessDenied, KeyError, AttributeError):
continue
except (PermissionError, psutil.AccessDenied, OSError):
for proc in psutil.process_iter(["memory_info"]):
proc_rss_mb = _get_process_rss_mb(proc)
if proc_rss_mb is not None:
app_memory_mb += proc_rss_mb
except PermissionError, psutil.AccessDenied, OSError:
try:
app_memory_mb = psutil.Process().memory_info().rss / (1024 * 1024)
except Exception:
except AttributeError, OSError, psutil.Error:
app_memory_mb = 0.0
memory = psutil.virtual_memory()
@@ -68,11 +97,52 @@ class CustomLogger(logging.Logger):
f"Container Memory: App={app_memory_mb:.2f} MB, System={system_used_mb:.2f} MB, "
f"Available={available_mb:.2f} MB, CPU: {cpu_percent:.2f}%"
)
except Exception:
except AttributeError, OSError, psutil.Error:
# Avoid breaking the original log call if psutil is missing or restricted.
return
def _extract_log_kwargs(
kwargs: Mapping[str, object],
) -> tuple[bool, int, Mapping[str, object] | None]:
stack_info = kwargs.get("stack_info")
normalized_stack_info = stack_info if isinstance(stack_info, bool) else False
stacklevel = kwargs.get("stacklevel")
normalized_stacklevel = stacklevel if isinstance(stacklevel, int) else 1
extra = kwargs.get("extra")
normalized_extra = _normalize_log_extra(extra)
return normalized_stack_info, normalized_stacklevel, normalized_extra
def _normalize_log_extra(value: object) -> Mapping[str, object] | None:
if not isinstance(value, Mapping):
return None
if all(isinstance(key, str) for key in value):
return value
return None
def _get_file_handler(log_file: Path, formatter: logging.Formatter) -> RotatingFileHandler:
"""Return the process-wide rotating handler for a log file."""
with _file_handlers_lock:
handler = _file_handlers.get(log_file)
if handler is None:
log_file.parent.mkdir(parents=True, exist_ok=True)
handler = RotatingFileHandler(
log_file,
maxBytes=10485760, # 10MB
backupCount=5,
)
handler.setFormatter(formatter)
_file_handlers[log_file] = handler
return handler
def setup_logger(name: str, log_file: Path = LOG_FILE) -> CustomLogger:
"""Set up and configure a logger instance.
@@ -82,6 +152,7 @@ def setup_logger(name: str, log_file: Path = LOG_FILE) -> CustomLogger:
Returns:
CustomLogger: Configured logger instance with error_trace method
"""
# Register our custom logger class
logging.setLoggerClass(CustomLogger)
@@ -92,36 +163,29 @@ def setup_logger(name: str, log_file: Path = LOG_FILE) -> CustomLogger:
logger.setLevel(log_level)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
"%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s"
)
# Console handler for Docker output
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
console_handler.setLevel(log_level)
console_handler.addFilter(lambda record: record.levelno < logging.ERROR) # Only allow logs below ERROR to stdout
console_handler.addFilter(
lambda record: record.levelno < logging.ERROR
) # Only allow logs below ERROR to stdout
logger.addHandler(console_handler)
# Error handler for stderr
error_handler = logging.StreamHandler(sys.stderr)
error_handler.setLevel(logging.ERROR) # Error and above go to stderr
error_handler.setLevel(logging.ERROR) # Error and above go to stderr
error_handler.setFormatter(formatter)
logger.addHandler(error_handler)
# File handler if log file is specified
try:
if ENABLE_LOGGING:
# Create log directory if it doesn't exist
log_dir = log_file.parent
log_dir.mkdir(parents=True, exist_ok=True)
file_handler = RotatingFileHandler(
log_file,
maxBytes=10485760, # 10MB
backupCount=5
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
except Exception as e:
logger.addHandler(_get_file_handler(log_file, formatter))
except (OSError, TypeError, ValueError) as e:
logger.error_trace(f"Failed to create log file: {e}", exc_info=True)
return logger
+175 -166
View File
@@ -1,254 +1,263 @@
"""Centralized mirror configuration for all download sources."""
"""Centralized mirror configuration for direct-download sources."""
from typing import List
from __future__ import annotations
from typing import TYPE_CHECKING
from shelfmark.core.utils import normalize_http_url
# Lazy import to avoid circular imports
if TYPE_CHECKING:
from shelfmark.core.config import Config
_config_module = None
def _get_config():
def _get_config() -> Config:
"""Lazy import of config module to avoid circular imports."""
global _config_module
if _config_module is None:
from shelfmark.core.config import config
_config_module = config
return _config_module
# Default mirror lists (hardcoded fallbacks)
DEFAULT_AA_MIRRORS = [
"https://annas-archive.gl",
"https://annas-archive.li",
]
# Mirror URLs are intentionally user-supplied only.
DEFAULT_AA_MIRRORS: list[str] = []
DEFAULT_LIBGEN_MIRRORS: list[str] = []
DEFAULT_ZLIB_MIRRORS: list[str] = []
DEFAULT_WELIB_MIRRORS: list[str] = []
DEFAULT_LIBGEN_MIRRORS = [
"https://libgen.gl",
"https://libgen.li",
"https://libgen.bz",
"https://libgen.la",
"https://libgen.vg",
]
DEFAULT_ZLIB_MIRRORS = [
"https://z-lib.fm",
"https://z-lib.gs",
"https://z-lib.id",
"https://z-library.sk",
"https://zlibrary-global.se",
]
DEFAULT_WELIB_MIRRORS = [
"https://welib.org",
]
_DOWNLOAD_SOURCE_MIRROR_LABELS = {
"aa-fast": "Anna's Archive",
"aa-slow": "Anna's Archive",
"aa-slow-nowait": "Anna's Archive",
"aa-slow-wait": "Anna's Archive",
"libgen": "LibGen",
"zlib": "Z-Library",
"welib": "Welib",
}
def _normalize_mirror_url(url: str) -> str:
return normalize_http_url(url, default_scheme="https")
def get_aa_mirrors() -> List[str]:
"""
Get Anna's Archive mirrors.
def _string_config_value(value: object) -> str:
"""Normalize mirror-related config values to strings."""
return value if isinstance(value, str) else str(value or "")
Returns:
Ordered list of AA mirror URLs.
If AA_MIRROR_URLS is configured, it is treated as the full list.
Otherwise, defaults are used and AA_ADDITIONAL_URLS (legacy) is appended.
def _normalize_configured_urls(value: object) -> list[str]:
"""Normalize list or comma-separated mirror config into unique URLs."""
if isinstance(value, list):
parts = value
elif isinstance(value, str) and value.strip():
parts = value.split(",")
else:
return []
Notes:
- The list is used to populate the AA mirror dropdown in Settings.
- When AA_BASE_URL is set to 'auto', mirrors are tried in the order listed.
"""
normalized_urls: list[str] = []
for raw_url in parts:
normalized = _normalize_mirror_url(str(raw_url))
if normalized and normalized not in normalized_urls:
normalized_urls.append(normalized)
return normalized_urls
def _get_primary_mirror_url(key: str) -> str | None:
"""Return a configured primary mirror URL, if present."""
config = _get_config()
primary = _normalize_mirror_url(_string_config_value(config.get(key, "")))
return primary or None
def _build_primary_and_additional_mirrors(primary_key: str, additional_key: str) -> list[str]:
"""Build an ordered mirror list from primary + additional config values."""
config = _get_config()
mirrors: list[str] = []
configured_list = config.get("AA_MIRROR_URLS", None)
if isinstance(configured_list, list):
for url in configured_list:
normalized = _normalize_mirror_url(str(url))
if normalized and normalized not in mirrors:
mirrors.append(normalized)
elif isinstance(configured_list, str) and configured_list.strip():
# Allow comma-separated env/manual configs.
for url in configured_list.split(","):
normalized = _normalize_mirror_url(url)
if normalized and normalized not in mirrors:
mirrors.append(normalized)
primary = _get_primary_mirror_url(primary_key)
if primary:
mirrors.append(primary)
if not mirrors:
mirrors = [_normalize_mirror_url(url) for url in DEFAULT_AA_MIRRORS]
mirrors = [url for url in mirrors if url]
# Backwards-compatible append-only behavior for legacy configs/env.
additional = config.get("AA_ADDITIONAL_URLS", "")
if additional:
for url in additional.split(","):
normalized = _normalize_mirror_url(url)
if normalized and normalized not in mirrors:
mirrors.append(normalized)
for url in _normalize_configured_urls(config.get(additional_key, "")):
if url not in mirrors:
mirrors.append(url)
return mirrors
def get_libgen_mirrors() -> List[str]:
"""
Get LibGen mirrors: defaults + any additional from config.
def get_aa_mirrors() -> list[str]:
"""Get Anna's Archive mirrors.
Returns:
List of LibGen mirror URLs (defaults first, then custom additions).
Ordered list of user-configured AA mirror URLs.
Notes:
- The list is used to populate the AA mirror dropdown in Settings.
- When AA_BASE_URL is set to 'auto', mirrors are tried in the order listed.
"""
mirrors = [_normalize_mirror_url(url) for url in DEFAULT_LIBGEN_MIRRORS]
mirrors = [url for url in mirrors if url]
config = _get_config()
additional = config.get("LIBGEN_ADDITIONAL_URLS", "")
if additional:
for url in additional.split(","):
normalized = _normalize_mirror_url(url)
if normalized and normalized not in mirrors:
mirrors.append(normalized)
return mirrors
configured_list = _normalize_configured_urls(config.get("AA_MIRROR_URLS", None))
if configured_list:
return configured_list
return _normalize_configured_urls(config.get("AA_ADDITIONAL_URLS", ""))
def get_zlib_mirrors() -> List[str]:
def has_aa_mirror_configuration() -> bool:
"""Return True when direct-download search has at least one AA base URL to use."""
if get_aa_mirrors():
return True
configured_base_url = normalize_http_url(
_string_config_value(_get_config().get("AA_BASE_URL", "auto")),
default_scheme="https",
allow_special=("auto",),
)
return bool(configured_base_url and configured_base_url != "auto")
def get_libgen_mirrors() -> list[str]:
"""Get user-configured LibGen mirrors.
Returns:
List of LibGen mirror URLs.
"""
Get Z-Library mirrors, with primary first.
config = _get_config()
configured_list = _normalize_configured_urls(config.get("LIBGEN_MIRROR_URLS", None))
if configured_list:
return configured_list
return _normalize_configured_urls(config.get("LIBGEN_ADDITIONAL_URLS", ""))
def has_libgen_mirror_configuration() -> bool:
"""Return True when at least one LibGen mirror URL is configured."""
return bool(get_libgen_mirrors())
def get_zlib_mirrors() -> list[str]:
"""Get user-configured Z-Library mirrors, with primary first.
Returns:
List of Z-Library mirror URLs, primary first.
"""
config = _get_config()
primary = _normalize_mirror_url(config.get("ZLIB_PRIMARY_URL", DEFAULT_ZLIB_MIRRORS[0]))
if not primary:
primary = _normalize_mirror_url(DEFAULT_ZLIB_MIRRORS[0])
mirrors = [primary]
# Add other defaults (excluding primary)
for url in DEFAULT_ZLIB_MIRRORS:
normalized = _normalize_mirror_url(url)
if normalized and normalized != primary:
mirrors.append(normalized)
# Add custom mirrors
additional = config.get("ZLIB_ADDITIONAL_URLS", "")
if additional:
for url in additional.split(","):
normalized = _normalize_mirror_url(url)
if normalized and normalized not in mirrors:
mirrors.append(normalized)
return mirrors
configured_list = _normalize_configured_urls(config.get("ZLIB_MIRROR_URLS", None))
if configured_list:
return configured_list
return _build_primary_and_additional_mirrors("ZLIB_PRIMARY_URL", "ZLIB_ADDITIONAL_URLS")
def get_zlib_primary_url() -> str:
"""
Get the primary Z-Library mirror URL.
def has_zlib_mirror_configuration() -> bool:
"""Return True when at least one Z-Library mirror URL is configured."""
return bool(get_zlib_mirrors())
def get_zlib_primary_url() -> str | None:
"""Get the primary Z-Library mirror URL.
Returns:
Primary Z-Library mirror URL.
Primary Z-Library mirror URL, if configured.
"""
config = _get_config()
primary = _normalize_mirror_url(config.get("ZLIB_PRIMARY_URL", DEFAULT_ZLIB_MIRRORS[0]))
return primary or _normalize_mirror_url(DEFAULT_ZLIB_MIRRORS[0])
mirrors = get_zlib_mirrors()
return mirrors[0] if mirrors else None
def get_zlib_url_template() -> str:
"""
Get Z-Library URL template using configured primary mirror.
def get_zlib_url_template() -> str | None:
"""Get Z-Library URL template using configured primary mirror.
Returns:
URL template with {md5} placeholder.
URL template with {md5} placeholder, if configured.
"""
primary = get_zlib_primary_url()
return f"{primary}/md5/{{md5}}"
return f"{primary}/md5/{{md5}}" if primary else None
def get_welib_mirrors() -> List[str]:
"""
Get Welib mirrors, with primary first.
def get_welib_mirrors() -> list[str]:
"""Get user-configured Welib mirrors, with primary first.
Returns:
List of Welib mirror URLs, primary first.
"""
config = _get_config()
primary = _normalize_mirror_url(config.get("WELIB_PRIMARY_URL", DEFAULT_WELIB_MIRRORS[0]))
if not primary:
primary = _normalize_mirror_url(DEFAULT_WELIB_MIRRORS[0])
mirrors = [primary]
# Add other defaults (excluding primary)
for url in DEFAULT_WELIB_MIRRORS:
normalized = _normalize_mirror_url(url)
if normalized and normalized != primary:
mirrors.append(normalized)
# Add custom mirrors
additional = config.get("WELIB_ADDITIONAL_URLS", "")
if additional:
for url in additional.split(","):
normalized = _normalize_mirror_url(url)
if normalized and normalized not in mirrors:
mirrors.append(normalized)
return mirrors
configured_list = _normalize_configured_urls(config.get("WELIB_MIRROR_URLS", None))
if configured_list:
return configured_list
return _build_primary_and_additional_mirrors("WELIB_PRIMARY_URL", "WELIB_ADDITIONAL_URLS")
def get_welib_primary_url() -> str:
"""
Get the primary Welib mirror URL.
def has_welib_mirror_configuration() -> bool:
"""Return True when at least one Welib mirror URL is configured."""
return bool(get_welib_mirrors())
def has_download_source_mirror_configuration(source_id: str) -> bool:
"""Return True when the requested direct-download source has mirror config."""
if source_id in {"aa-fast", "aa-slow", "aa-slow-nowait", "aa-slow-wait"}:
return has_aa_mirror_configuration()
if source_id == "libgen":
return has_libgen_mirror_configuration()
if source_id == "zlib":
return has_zlib_mirror_configuration()
if source_id == "welib":
return has_welib_mirror_configuration()
return False
def get_download_source_missing_mirror_reason(source_id: str) -> str | None:
"""Return a user-facing reason when a direct-download source has no mirror config."""
if has_download_source_mirror_configuration(source_id):
return None
label = _DOWNLOAD_SOURCE_MIRROR_LABELS.get(source_id)
if not label:
return None
return f"Add at least one {label} mirror in Mirrors"
def get_welib_primary_url() -> str | None:
"""Get the primary Welib mirror URL.
Returns:
Primary Welib mirror URL.
Primary Welib mirror URL, if configured.
"""
config = _get_config()
primary = _normalize_mirror_url(config.get("WELIB_PRIMARY_URL", DEFAULT_WELIB_MIRRORS[0]))
return primary or _normalize_mirror_url(DEFAULT_WELIB_MIRRORS[0])
mirrors = get_welib_mirrors()
return mirrors[0] if mirrors else None
def get_welib_url_template() -> str:
"""
Get Welib URL template using configured primary mirror.
def get_welib_url_template() -> str | None:
"""Get Welib URL template using configured primary mirror.
Returns:
URL template with {md5} placeholder.
URL template with {md5} placeholder, if configured.
"""
primary = get_welib_primary_url()
return f"{primary}/md5/{{md5}}"
return f"{primary}/md5/{{md5}}" if primary else None
def get_zlib_cookie_domains() -> set:
"""
Get set of Z-Library domains that need full cookie handling.
"""Get set of Z-Library domains that need full cookie handling.
Used by internal_bypasser for CF bypass cookie management.
Returns:
Set of domain strings (without protocol).
"""
domains = set()
# Add all default domains
for url in DEFAULT_ZLIB_MIRRORS:
normalized = _normalize_mirror_url(url)
if normalized:
domain = normalized.replace("https://", "").replace("http://", "").split("/")[0]
domains.add(domain)
# Add custom domains
config = _get_config()
additional = config.get("ZLIB_ADDITIONAL_URLS", "")
if additional:
for url in additional.split(","):
normalized = _normalize_mirror_url(url)
if normalized:
domain = normalized.replace("https://", "").replace("http://", "").split("/")[0]
domains.add(domain)
for url in get_zlib_mirrors():
domain = url.replace("https://", "").replace("http://", "").split("/")[0]
domains.add(domain)
return domains
+95 -92
View File
@@ -1,19 +1,20 @@
"""Data structures and models used across the application."""
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional
from enum import Enum
import re
import time
from dataclasses import dataclass, field
from enum import StrEnum
from pathlib import Path
from typing import Any
def build_filename(
title: str,
author: Optional[str] = None,
year: Optional[str] = None,
fmt: Optional[str] = None,
author: str | None = None,
year: str | None = None,
fmt: str | None = None,
) -> str:
"""Build a filesystem-safe filename from book metadata."""
parts = []
if author:
parts.append(author)
@@ -23,7 +24,7 @@ def build_filename(
parts.append(f" ({year})")
filename = "".join(parts)
filename = re.sub(r'[\\/:*?"<>|]', '_', filename.strip())[:245]
filename = re.sub(r'[\\/:*?"<>|]', "_", filename.strip())[:245]
if fmt:
filename = f"{filename}.{fmt}"
@@ -31,20 +32,39 @@ def build_filename(
return filename
class QueueStatus(str, Enum):
class QueueStatus(StrEnum):
"""Enum for possible book queue statuses."""
QUEUED = "queued"
RESOLVING = "resolving"
LOCATING = "locating"
DOWNLOADING = "downloading"
COMPLETE = "complete"
AVAILABLE = "available"
ERROR = "error"
DONE = "done"
CANCELLED = "cancelled"
class SearchMode(str, Enum):
TERMINAL_QUEUE_STATUSES: frozenset[QueueStatus] = frozenset(
{
QueueStatus.COMPLETE,
QueueStatus.ERROR,
QueueStatus.CANCELLED,
}
)
ACTIVE_QUEUE_STATUSES: frozenset[QueueStatus] = frozenset(
{
QueueStatus.QUEUED,
QueueStatus.RESOLVING,
QueueStatus.LOCATING,
QueueStatus.DOWNLOADING,
}
)
class SearchMode(StrEnum):
"""Search modes supported by the Shelfmark UI and API."""
DIRECT = "direct"
UNIVERSAL = "universal"
@@ -52,11 +72,12 @@ class SearchMode(str, Enum):
@dataclass
class QueueItem:
"""Queue item with priority and metadata."""
book_id: str
priority: int
added_time: float
def __lt__(self, other):
def __lt__(self, other: QueueItem) -> bool:
"""Compare items for priority queue (lower priority number = higher precedence)."""
if self.priority != other.priority:
return self.priority < other.priority
@@ -65,50 +86,80 @@ class QueueItem:
@dataclass
class DownloadTask:
task_id: str # Unique ID (e.g., AA MD5 hash, Prowlarr GUID)
source: str # Handler name ("direct_download", "prowlarr")
title: str # Display title for queue sidebar
"""Mutable download task state tracked throughout the pipeline."""
task_id: str # Unique ID (e.g., AA MD5 hash, Prowlarr GUID)
source: str # Handler name ("direct_download", "prowlarr")
title: str # Display title for queue sidebar
# Display info for queue sidebar
author: Optional[str] = None
year: Optional[str] = None
format: Optional[str] = None
size: Optional[str] = None
preview: Optional[str] = None
content_type: Optional[str] = None # "book (fiction)", "audiobook", "magazine", etc.
source_url: Optional[str] = None # Original release URL used by source-specific handlers
author: str | None = None
year: str | None = None
format: str | None = None
size: str | None = None
downloads: int | None = None # Download count from source
preview: str | None = None
content_type: str | None = None # "book (fiction)", "audiobook", "magazine", etc.
source_url: str | None = None # Original release URL used by source-specific handlers
retry_download_url: str | None = None # Resolved download URL for restart-safe retries
retry_download_protocol: str | None = (
None # Protocol for retry_download_url (e.g. torrent, usenet)
)
retry_release_name: str | None = None # Display name to send back to external download clients
retry_expected_hash: str | None = None # Optional torrent hash used to match client downloads
retry_ratio_limit: float | None = None # Optional post-download seeding ratio
retry_seeding_time_limit_minutes: int | None = None # Optional post-download seeding time limit
retry_source_context: dict[str, Any] = field(
default_factory=dict
) # Source-private context for retry/re-resolution
can_retry_without_staged_source: bool = (
True # Whether the source can restart without a preserved staged file
)
# Series info (for library naming templates)
series_name: Optional[str] = None
series_position: Optional[float] = None # Float for novellas (e.g., 1.5)
subtitle: Optional[str] = None # Book subtitle for naming templates
series_name: str | None = None
series_position: float | None = None # Float for novellas (e.g., 1.5)
subtitle: str | None = None # Book subtitle for naming templates
language: str | None = None # Release language code for the {Language} template variable
# Hardlinking support
original_download_path: Optional[str] = None # Path in download client (for hardlinking)
original_download_path: str | None = None # Path in download client (for hardlinking)
# Search mode - determines post-download processing behavior
# See SearchMode enum for behavioral differences
search_mode: Optional[SearchMode] = None
search_mode: SearchMode | None = None
# Output selection for post-processing.
# This is captured at queue time so in-flight tasks are not affected if the user changes settings later.
output_mode: Optional[str] = None # e.g. "folder", "booklore", "email"
output_args: Dict[str, Any] = field(default_factory=dict) # Per-output parameters (e.g. email recipient)
output_mode: str | None = None
output_args: dict[str, Any] = field(
default_factory=dict
) # Per-output parameters (e.g. email recipient)
# Multi-book packs: one release holding several books. `book_plan` is the split the
# user approved before download (list of {title, series_position, year, files});
# `multi_book` asks post-processing to split heuristically when no plan exists.
multi_book: bool = False
book_plan: list[dict[str, Any]] | None = None
# User association (multi-user support)
user_id: Optional[int] = None # DB user ID who queued this download
username: Optional[str] = None # Username for {User} template variable
request_id: Optional[int] = None # Origin request ID when queued from request fulfilment
user_id: int | None = None # DB user ID who queued this download
username: str | None = None # Username for {User} template variable
request_id: int | None = None # Origin request ID when queued from request fulfilment
# Runtime state
priority: int = 0
added_time: float = field(default_factory=time.time)
progress: float = 0.0
status: QueueStatus = QueueStatus.QUEUED
status_message: Optional[str] = None
download_path: Optional[str] = None
status_message: str | None = None
download_path: str | None = None
last_error_message: str | None = None
last_error_type: str | None = None
staged_path: str | None = None
def __lt__(self, other):
def __lt__(self, other: DownloadTask) -> bool:
"""Compare tasks for priority queue (lower priority number = higher precedence)."""
if self.priority != other.priority:
return self.priority < other.priority
@@ -121,62 +172,14 @@ class DownloadTask:
return build_filename(self.title, self.author, self.year, self.format)
@dataclass
class BookInfo:
"""Data class representing book information."""
id: str
title: str
preview: Optional[str] = None
author: Optional[str] = None
publisher: Optional[str] = None
year: Optional[str] = None
language: Optional[str] = None
content: Optional[str] = None
format: Optional[str] = None
size: Optional[str] = None
info: Optional[Dict[str, List[str]]] = None
description: Optional[str] = None
download_urls: List[str] = field(default_factory=list)
download_path: Optional[str] = None
priority: int = 0
progress: Optional[float] = None
status_message: Optional[str] = None # Detailed status message for UI display
added_time: Optional[float] = None # Timestamp when added to queue
source: str = "direct_download" # Release source handler to use for downloads
source_url: Optional[str] = None # Link to source page (e.g., Anna's Archive)
def get_filename(self, fallback_url: Optional[str] = None) -> str:
"""Build sanitized filename: 'Author - Title (Year).format'
Resolves format from self.format, download_urls, or fallback_url.
Args:
fallback_url: URL to extract format from if not already known
Returns:
Sanitized filename safe for filesystem use
"""
# Resolve format if needed
if not self.format:
urls = [self.download_urls[0]] if self.download_urls else []
if fallback_url:
urls.append(fallback_url)
for url in urls:
ext = url.split(".")[-1].lower()
if ext and len(ext) <= 5 and ext.isalnum():
self.format = ext
break
return build_filename(self.title, self.author, self.year, self.format)
@dataclass
class SearchFilters:
"""Filters for book search queries."""
isbn: Optional[List[str]] = None
author: Optional[List[str]] = None
title: Optional[List[str]] = None
lang: Optional[List[str]] = None
sort: Optional[str] = None
content: Optional[List[str]] = None
format: Optional[List[str]] = None
isbn: list[str] | None = None
author: list[str] | None = None
title: list[str] | None = None
lang: list[str] | None = None
sort: str | None = None
content: list[str] | None = None
format: list[str] | None = None
+152 -65
View File
@@ -1,47 +1,64 @@
"""Template-based naming for library organization."""
import os
import re
from pathlib import Path
from typing import Dict, Optional, Union, Mapping
from typing import TYPE_CHECKING
from shelfmark.core.languages import LANGUAGE_PLACEHOLDERS, normalize_language
from shelfmark.core.logger import setup_logger
if TYPE_CHECKING:
from collections.abc import Mapping
logger = setup_logger(__name__)
# Known variable tokens, sorted longest-first to avoid partial matches
# e.g., "SeriesPosition" must match before "Series"
# e.g., "SeriesPosition" must match before "Series", "FirstAuthor" before "Author"
KNOWN_TOKENS = [
'seriesposition',
'partnumber',
'subtitle',
'author',
'series',
'title',
'year',
'user',
"seriesposition",
"primarytitle",
"originalname",
"firstauthor",
"partnumber",
"language",
"subtitle",
"author",
"series",
"title",
"year",
"user",
]
# Authors reach naming already joined as "First Author, Second Author, ...".
# {FirstAuthor} keeps only the first entry. A single name written "Last, First"
# is split on the comma too and renders as "Last" -- the source metadata does
# not mark which form it is (see #930).
AUTHOR_LIST_SEPARATOR = re.compile(r"\s*[,;]\s*")
# Match any {...} block for template parsing
BRACE_PATTERN = re.compile(r'\{([^}]+)\}')
BRACE_PATTERN = re.compile(r"\{([^}]+)\}")
# Characters that are invalid in filenames on various filesystems
INVALID_CHARS = re.compile(r'[\\/:*?"<>|]')
# Runs of whitespace inside a single placeholder's rendered value, e.g. "Conan Doyle"
# -- collapsed to the configured word separator (see `parse_naming_template`).
WHITESPACE_RUN = re.compile(r"\s+")
def _sanitize(name: Optional[str], max_length: int = 245) -> str:
def _sanitize(name: str | None, max_length: int = 245) -> str:
"""Sanitize a string for filesystem use."""
if not name:
return ""
sanitized = INVALID_CHARS.sub('_', name)
sanitized = re.sub(r'^[\s.]+|[\s.]+$', '', sanitized) # Strip whitespace and dots
sanitized = re.sub(r'_+', '_', sanitized) # Collapse underscores
sanitized = INVALID_CHARS.sub("_", name)
sanitized = re.sub(r"^[\s.]+|[\s.]+$", "", sanitized) # Strip whitespace and dots
sanitized = re.sub(r"_+", "_", sanitized) # Collapse underscores
return sanitized[:max_length]
def sanitize_filename(name: Optional[str], max_length: int = 245) -> str:
def sanitize_filename(name: str | None, max_length: int = 245) -> str:
"""Sanitize a string for use as a filename or path component."""
return _sanitize(name, max_length)
@@ -50,7 +67,16 @@ def sanitize_filename(name: Optional[str], max_length: int = 245) -> str:
sanitize_path_component = sanitize_filename
def format_series_position(position: Optional[Union[str, int, float]]) -> str:
def first_author(value: object) -> str:
"""Return the first entry from an author string joined with ',' or ';'."""
text = " ".join(str(value or "").split())
if not text:
return ""
return AUTHOR_LIST_SEPARATOR.split(text, maxsplit=1)[0].strip()
def format_series_position(position: str | float | None) -> str:
"""Format a series position for naming templates."""
if position is None:
return ""
@@ -61,14 +87,59 @@ def format_series_position(position: Optional[Union[str, int, float]]) -> str:
return str(position)
def normalize_language_code(language: str | None) -> str:
"""Resolve a release language to the single spelling used in a path.
Sources report the same language in different shapes: "en", "eng", "English".
All of them have to collapse to one code, or the editions they identify end
up in separate folders, which is the collision this token exists to prevent.
Placeholder values render empty so `{ (Language)}` disappears entirely
rather than labelling a folder "(unknown)".
A language the bundled data does not know is kept, casefolded, rather than
dropped: it still separates editions, and it cannot collide with a resolved
code precisely because nothing resolves it.
"""
if not language:
return ""
resolved = normalize_language(language)
if resolved is not None:
return resolved
normalized = " ".join(str(language).split()).strip().casefold()
if normalized in LANGUAGE_PLACEHOLDERS:
return ""
return normalized
def derive_primary_title(title: str | None, subtitle: str | None) -> str:
"""Return the title without an explicit subtitle suffix when possible."""
title_value = " ".join(str(title or "").split()).strip()
if not title_value:
return ""
subtitle_value = " ".join(str(subtitle or "").split()).strip()
if not subtitle_value:
return title_value
pattern = rf"^(?P<primary>.+?)(?:\s*:\s*|\s+-\s+){re.escape(subtitle_value)}$"
match = re.match(pattern, title_value, flags=re.IGNORECASE)
if not match:
return title_value
primary = match.group("primary").strip()
return primary or title_value
# Pads numbers to 9 digits for natural sorting (e.g., "Part 2" -> "Part 000000002")
PAD_NUMBERS_PATTERN = re.compile(r'\d+')
PAD_NUMBERS_PATTERN = re.compile(r"\d+")
def natural_sort_key(path: Union[str, Path]) -> str:
def natural_sort_key(path: str | Path) -> str:
"""Generate a sort key with padded numbers for natural sorting."""
filename = Path(path).name.lower()
return PAD_NUMBERS_PATTERN.sub(lambda m: m.group().zfill(9), filename)
return PAD_NUMBERS_PATTERN.sub(lambda m: m.group().zfill(9), str(path).lower())
def assign_part_numbers(
@@ -88,43 +159,56 @@ def assign_part_numbers(
def parse_naming_template(
template: str,
metadata: Mapping[str, Optional[Union[str, int, float]]],
metadata: Mapping[str, str | int | float | None],
*,
allow_path_separators: bool = True,
word_separator: str = " ",
) -> str:
"""Render a naming template with Shelfmark metadata placeholders.
`word_separator` replaces whitespace *inside* each placeholder's rendered
value (e.g. "Conan Doyle" -> "Conan.Doyle" for a "." separator). It never
touches literal characters typed into the template itself, so a template
like "{Author}.-.{Title}" keeps its own dots regardless of this setting.
The default (" ") leaves values untouched, matching prior behavior.
"""
if not template:
return ""
# Normalize metadata keys to lowercase for case-insensitive matching
normalized = {k.lower(): v for k, v in metadata.items()}
def find_token(content: str) -> tuple[Optional[str], int]:
def find_placeholder(content: str) -> tuple[str | None, int]:
content_lower = content.lower()
for token in KNOWN_TOKENS:
idx = content_lower.find(token)
for placeholder_name in KNOWN_TOKENS:
idx = content_lower.find(placeholder_name)
if idx != -1:
return token, idx
return placeholder_name, idx
return None, -1
def token_value(token: str) -> str:
value = normalized.get(token)
if token == 'seriesposition':
def placeholder_value(placeholder_name: str) -> str:
value = normalized.get(placeholder_name)
if placeholder_name == "seriesposition":
value = format_series_position(value)
elif placeholder_name == "firstauthor" and not value:
value = first_author(normalized.get("author"))
if value is None:
return ""
return str(value).strip()
def render_block(content: str) -> Optional[str]:
token, idx = find_token(content)
if token is None:
def render_block(content: str) -> str | None:
placeholder_name, idx = find_placeholder(content)
if placeholder_name is None:
return None
prefix = content[:idx]
suffix = content[idx + len(token):]
value = token_value(token)
suffix = content[idx + len(placeholder_name) :]
value = placeholder_value(placeholder_name)
if not value:
return ""
if word_separator != " ":
value = WHITESPACE_RUN.sub(word_separator, value)
if not allow_path_separators:
value = value.replace("/", "_")
value = sanitize_filename(value)
@@ -139,7 +223,7 @@ def parse_naming_template(
parts: list[str] = []
cursor = 0
for idx, match in enumerate(matches):
parts.append(template[cursor:match.start()])
parts.append(template[cursor : match.start()])
content = match.group(1)
rendered = render_block(content)
@@ -150,17 +234,16 @@ def parse_naming_template(
include_literal = False
if idx + 1 < len(matches) and match.end() == matches[idx + 1].start():
next_content = matches[idx + 1].group(1)
next_token, _next_idx = find_token(next_content)
if next_token is not None:
next_placeholder_name, _next_idx = find_placeholder(next_content)
if next_placeholder_name is not None:
conditional_literal = True
include_literal = bool(token_value(next_token))
include_literal = bool(placeholder_value(next_placeholder_name))
if include_literal:
parts.append(content)
elif not conditional_literal:
elif not conditional_literal and re.search(r"\s", content):
# Preserve blocks that look like literal text, but treat bare unknown
# placeholders as missing variables.
if re.search(r"\s", content):
parts.append(match.group(0))
parts.append(match.group(0))
cursor = match.end()
@@ -168,41 +251,44 @@ def parse_naming_template(
result = "".join(parts)
# Clean up any double slashes that might result from empty tokens
result = re.sub(r'/+', '/', result)
result = re.sub(r"/+", "/", result)
# Remove leading/trailing slashes
result = result.strip('/')
result = result.strip("/")
# Clean up any orphaned separators (e.g., " - " at start/end, or " - - ")
result = re.sub(r'^[\s\-_.]+', '', result)
result = re.sub(r'[\s\-_.]+$', '', result)
result = re.sub(r'(\s*-\s*){2,}', ' - ', result)
result = re.sub(r"^[\s\-_.]+", "", result)
result = re.sub(r"[\s\-_.]+$", "", result)
result = re.sub(r"(\s*-\s*){2,}", " - ", result)
# Clean up empty parentheses/brackets
result = re.sub(r'\(\s*\)', '', result)
result = re.sub(r'\[\s*\]', '', result)
result = re.sub(r"\(\s*\)", "", result)
result = re.sub(r"\[\s*\]", "", result)
# Final trim of any trailing separators left after cleanup
result = re.sub(r'[\s\-_.]+$', '', result)
return result
return re.sub(r"[\s\-_.]+$", "", result)
def build_library_path(
base_path: str,
template: str,
metadata: Mapping[str, Optional[Union[str, int, float]]],
extension: Optional[str] = None,
metadata: Mapping[str, str | int | float | None],
extension: str | None = None,
*,
word_separator: str = " ",
) -> Path:
relative = parse_naming_template(template, metadata, allow_path_separators=True)
"""Build a final library path from a template and metadata."""
relative = parse_naming_template(
template, metadata, allow_path_separators=True, word_separator=word_separator
)
if not relative:
# Fallback to title if template produces empty result
title = metadata.get('Title') or metadata.get('title') or 'Unknown'
title = metadata.get("Title") or metadata.get("title") or "Unknown"
relative = sanitize_filename(str(title))
# Remove any path traversal attempts
relative = relative.replace('..', '')
relative = relative.replace("..", "")
base = Path(base_path).resolve()
full_path = (base / relative).resolve()
@@ -210,11 +296,12 @@ def build_library_path(
# Verify the path is within the base directory
try:
full_path.relative_to(base)
except ValueError:
raise ValueError(f"Path traversal detected: template would escape library directory")
except ValueError as exc:
msg = "Path traversal detected: template would escape library directory"
raise ValueError(msg) from exc
if extension:
ext = extension.lstrip('.')
ext = extension.lstrip(".")
# Don't use with_suffix() - it replaces everything after the first dot
# e.g., "2.5 - Title" would become "2.epub" instead of "2.5 - Title.epub"
full_path = Path(f"{full_path}.{ext}")
@@ -222,27 +309,27 @@ def build_library_path(
return full_path
def same_filesystem(path1: Union[str, Path], path2: Union[str, Path]) -> bool:
def same_filesystem(path1: str | Path, path2: str | Path) -> bool:
"""Check if two paths are on the same filesystem."""
path1 = Path(path1)
path2 = Path(path2)
def get_device(p: Path) -> Optional[int]:
def get_device(p: Path) -> int | None:
try:
while not p.exists():
p = p.parent
if p == p.parent:
break
return os.stat(p).st_dev
return p.stat().st_dev
except (OSError, PermissionError) as e:
logger.debug(f"Cannot stat {p}: {e}")
logger.debug("Cannot stat %s: %s", p, e)
return None
dev1 = get_device(path1)
dev2 = get_device(path2)
if dev1 is None or dev2 is None:
logger.warning(f"Cannot determine filesystem for hardlink check, falling back to copy")
logger.warning("Cannot determine filesystem for hardlink check, falling back to copy")
return False
return dev1 == dev2
+375 -59
View File
@@ -2,18 +2,26 @@
from __future__ import annotations
import logging
import threading
from concurrent.futures import ThreadPoolExecutor
from contextlib import contextmanager, suppress
from dataclasses import dataclass
from enum import Enum
from typing import Any, Iterable
from enum import StrEnum
from typing import TYPE_CHECKING, Any, Protocol, TypeGuard
from urllib.parse import urlsplit
try:
import apprise
except Exception: # pragma: no cover - exercised in tests via monkeypatch
except ImportError: # pragma: no cover - exercised in tests via monkeypatch
apprise = None # type: ignore[assignment]
from shelfmark.core.config import config as app_config
from shelfmark.core.logger import setup_logger
from shelfmark.core.request_helpers import normalize_positive_int
if TYPE_CHECKING:
from collections.abc import Iterable, Iterator
logger = setup_logger(__name__)
@@ -25,9 +33,37 @@ _APPRISE_APP_DESC = "Shelfmark notifications"
_APPRISE_LOGO_URL = (
"https://raw.githubusercontent.com/calibrain/shelfmark/main/src/frontend/public/logo.png"
)
_APPRISE_LOGGER_NAME = "apprise"
_APPRISE_DISPATCH_ERRORS = (RuntimeError, TypeError, ValueError)
class NotificationEvent(str, Enum):
class _ApprisePluginWithUrl(Protocol):
app_id: object
def url(self, *, privacy: bool = False) -> str:
_ = privacy
return ""
class _AppriseClient(Protocol):
asset: object
def add(self, plugin: object) -> object: ...
def notify(self, *, title: str, body: str, notify_type: object) -> object: ...
def _is_apprise_client(candidate: object) -> TypeGuard[_AppriseClient]:
return callable(getattr(candidate, "add", None)) and callable(
getattr(candidate, "notify", None)
)
def _has_plugin_url(candidate: object) -> TypeGuard[_ApprisePluginWithUrl]:
return callable(getattr(candidate, "url", None))
class NotificationEvent(StrEnum):
"""Global notification event identifiers."""
REQUEST_CREATED = "request_created"
@@ -52,7 +88,7 @@ class NotificationContext:
error_message: str | None = None
def _normalize_urls(value: Any) -> list[str]:
def _normalize_urls(value: object) -> list[str]:
if value is None:
return []
@@ -69,6 +105,13 @@ def _normalize_urls(value: Any) -> list[str]:
seen: set[str] = set()
for raw_url in raw_values:
url = str(raw_url or "").strip()
if not url:
continue
# Strip invisible/non-ASCII characters that can sneak in via copy-paste
# (zero-width spaces, smart quotes, non-breaking spaces, etc.).
# These pass Apprise URL validation but cause UnicodeEncodeError when
# requests tries to latin-1 encode credentials for Basic Auth headers.
url = url.encode("ascii", errors="ignore").decode("ascii").strip()
if not url:
continue
if url in seen:
@@ -78,7 +121,116 @@ def _normalize_urls(value: Any) -> list[str]:
return normalized
def _normalize_routes(value: Any) -> list[dict[str, str]]:
def _extract_url_schemes(urls: Iterable[str]) -> list[str]:
schemes: list[str] = []
seen: set[str] = set()
for raw_url in urls:
scheme = urlsplit(str(raw_url or "")).scheme.lower()
if not scheme or scheme in seen:
continue
seen.add(scheme)
schemes.append(scheme)
return schemes
class _AppriseLogCapture(logging.Handler):
def __init__(self, *, thread_id: int) -> None:
super().__init__(level=logging.INFO)
self.records: list[tuple[int, str, str, str]] = []
self._thread_id = thread_id
def emit(self, record: logging.LogRecord) -> None:
if record.thread != self._thread_id:
return
message = record.getMessage()
if message:
exception_summary = ""
if record.exc_info and record.exc_info[0]:
exc_type = getattr(record.exc_info[0], "__name__", "Exception")
exc = record.exc_info[1]
exception_summary = f"{exc_type}: {exc}"
elif record.exc_text:
exception_summary = str(record.exc_text).strip()
self.records.append((record.levelno, record.name, str(message), exception_summary))
@contextmanager
def _capture_apprise_logs(
*, min_level: int = logging.INFO
) -> Iterator[list[tuple[int, str, str, str]]]:
apprise_logger = logging.getLogger(_APPRISE_LOGGER_NAME)
previous_level = apprise_logger.level
handler = _AppriseLogCapture(thread_id=threading.get_ident())
apprise_logger.addHandler(handler)
if previous_level == logging.NOTSET or previous_level > min_level:
apprise_logger.setLevel(min_level)
try:
yield handler.records
finally:
apprise_logger.removeHandler(handler)
apprise_logger.setLevel(previous_level)
def _log_apprise_records(records: Iterable[tuple[int, str, str, str]]) -> None:
seen: set[tuple[int, str, str, str]] = set()
for level, source, raw_message, raw_exception_summary in records:
message = str(raw_message or "").strip()
source_name = str(source or "").strip() or _APPRISE_LOGGER_NAME
exception_summary = str(raw_exception_summary or "").strip()
key = (int(level), source_name, message, exception_summary)
if not message or key in seen:
continue
seen.add(key)
full_message = message if not exception_summary else f"{message} ({exception_summary})"
if level >= logging.ERROR:
logger.error("Apprise source [%s]: %s", source_name, full_message)
elif level >= logging.WARNING:
logger.warning("Apprise source [%s]: %s", source_name, full_message)
else:
logger.info("Apprise source [%s]: %s", source_name, full_message)
def _log_apprise_exception_debug(*, action: str, scheme: str, exc: Exception) -> None:
logger.debug(
"Apprise %s raised %s for scheme '%s': %s",
action,
type(exc).__name__,
scheme,
exc,
exc_info=(type(exc), exc, exc.__traceback__),
)
def _build_apprise_warning_detail(
records: Iterable[tuple[int, str, str, str]],
*,
scheme: str,
) -> str | None:
for level, source, raw_message, raw_exception_summary in records:
if level < logging.WARNING:
continue
message = str(raw_message or "").strip()
if not message:
continue
source_name = str(source or "").strip()
exception_summary = str(raw_exception_summary or "").strip()
full_message = message if not exception_summary else f"{message} ({exception_summary})"
if source_name and source_name != _APPRISE_LOGGER_NAME:
return f"{scheme}: {source_name}: {full_message}"
return f"{scheme}: {full_message}"
return None
def _normalize_routes(value: object) -> list[dict[str, str]]:
if not isinstance(value, list):
return []
@@ -129,14 +281,8 @@ def _resolve_admin_routes() -> list[dict[str, str]]:
return _normalize_routes(app_config.get("ADMIN_NOTIFICATION_ROUTES", []))
def _normalize_user_id(value: Any) -> int | None:
try:
user_id = int(value)
except (TypeError, ValueError):
return None
if user_id < 1:
return None
return user_id
def _normalize_user_id(value: object) -> int | None:
return normalize_positive_int(value)
def _resolve_user_routes(user_id: int | None) -> list[dict[str, str]]:
@@ -172,7 +318,7 @@ def _resolve_route_urls_for_event(
return selected
def _resolve_notify_type(event: NotificationEvent) -> Any:
def _resolve_notify_type(event: NotificationEvent) -> object:
if apprise is None:
fallback = {
NotificationEvent.REQUEST_CREATED: "info",
@@ -193,7 +339,7 @@ def _resolve_notify_type(event: NotificationEvent) -> Any:
return mapping[event]
def _clean_text(value: Any, fallback: str) -> str:
def _clean_text(value: object, fallback: str) -> str:
text = str(value or "").strip()
return text or fallback
@@ -211,7 +357,10 @@ def _render_message(context: NotificationContext) -> tuple[str, str]:
if event == NotificationEvent.REQUEST_REJECTED:
note = _clean_text(context.admin_note, "")
note_line = f"\nNote: {note}" if note else ""
return "Request Rejected", f'Request for "{title}" by {author} was rejected.{note_line}'
return (
"Request Rejected",
f'Request for "{title}" by {author} was rejected.{note_line}',
)
if event == NotificationEvent.DOWNLOAD_COMPLETE:
return "Download Complete", f'"{title}" by {author} downloaded successfully.'
@@ -220,56 +369,209 @@ def _render_message(context: NotificationContext) -> tuple[str, str]:
return "Download Failed", f'Failed to download "{title}" by {author}.{error_line}'
def _plugin_label(plugin: object, fallback_scheme: str) -> str:
"""Build a human-readable label from a validated Apprise plugin.
Combines the URL scheme with the plugin's service name (app_id) and
privacy-safe URL for richer diagnostics, e.g.
``"slack (Slack - slack://TokenA/To...n/To...n/)"``
"""
parts: list[str] = [fallback_scheme]
app_id = getattr(plugin, "app_id", None)
if app_id and str(app_id) != fallback_scheme:
privacy_url: str | None = None
if _has_plugin_url(plugin):
with suppress(Exception):
privacy_url = plugin.url(privacy=True)
suffix = str(app_id)
if privacy_url:
suffix = f"{suffix} - {privacy_url}"
parts.append(f"({suffix})")
return " ".join(parts)
def _apprise_proxy_env() -> dict[str, str]:
"""Build proxy env vars from app config so Apprise respects the proxy setting."""
import os
from shelfmark.core.config import config as _cfg
mode = str(_cfg.get("PROXY_MODE", "") or "").lower()
env: dict[str, str] = {}
if mode == "http":
http = str(_cfg.get("HTTP_PROXY", "") or "").strip()
https = str(_cfg.get("HTTPS_PROXY", "") or "").strip() or http
if http:
env["HTTP_PROXY"] = http
env["http_proxy"] = http
if https:
env["HTTPS_PROXY"] = https
env["https_proxy"] = https
elif mode == "socks5":
socks = str(_cfg.get("SOCKS5_PROXY", "") or "").strip()
if socks:
env["HTTP_PROXY"] = socks
env["http_proxy"] = socks
env["HTTPS_PROXY"] = socks
env["https_proxy"] = socks
no_proxy = str(_cfg.get("NO_PROXY", "") or "").strip()
if no_proxy and env:
env["NO_PROXY"] = no_proxy
env["no_proxy"] = no_proxy
# Don't override if the user already set these in the environment directly
return {k: v for k, v in env.items() if not os.environ.get(k)}
def _dispatch_to_apprise(
urls: Iterable[str],
*,
title: str,
body: str,
notify_type: Any,
notify_type: object,
) -> dict[str, Any]:
import os
normalized_urls = _normalize_urls(list(urls))
url_schemes = _extract_url_schemes(normalized_urls)
if not normalized_urls:
return {"success": False, "message": "No notification URLs configured"}
if apprise is None:
return {"success": False, "message": "Apprise is not installed"}
apobj = _create_apprise_client()
if apobj is None:
return {"success": False, "message": "Apprise is not installed"}
proxy_env = _apprise_proxy_env()
if proxy_env:
logger.debug("Applying proxy env for Apprise dispatch: %s", list(proxy_env.keys()))
os.environ.update(proxy_env)
valid_urls = 0
invalid_urls = 0
for url in normalized_urls:
try:
added = bool(apobj.add(url))
except Exception:
added = False
if added:
valid_urls += 1
else:
invalid_urls += 1
delivered_urls = 0
failed_delivery_urls = 0
failure_details: list[str] = []
for url in normalized_urls:
scheme = urlsplit(url).scheme or "unknown"
apobj = _create_apprise_client()
if apobj is None:
return {"success": False, "message": "Apprise is not installed"}
registration_failure_detail: str | None = None
with _capture_apprise_logs(min_level=logging.INFO) as apprise_records:
try:
plugin = apprise.Apprise.instantiate(url, asset=getattr(apobj, "asset", None))
except _APPRISE_DISPATCH_ERRORS as exc:
logger.warning(
"Failed to register notification route URL for scheme '%s': %s",
scheme,
exc,
)
_log_apprise_exception_debug(
action="route registration",
scheme=scheme,
exc=exc,
)
registration_failure_detail = (
f"{scheme}: route registration failed ({type(exc).__name__}: {exc})"
)
failure_details.append(registration_failure_detail)
plugin = None
if plugin is None:
invalid_urls += 1
logger.warning("Apprise rejected notification route URL for scheme '%s'", scheme)
_log_apprise_records(apprise_records)
warning_detail = _build_apprise_warning_detail(apprise_records, scheme=scheme)
if warning_detail:
failure_details.append(warning_detail)
elif registration_failure_detail is None:
failure_details.append(f"{scheme}: route URL rejected by Apprise")
continue
plugin_label = _plugin_label(plugin, scheme)
apobj.add(plugin)
valid_urls += 1
try:
delivered = bool(apobj.notify(title=title, body=body, notify_type=notify_type))
except _APPRISE_DISPATCH_ERRORS as exc:
_log_apprise_records(apprise_records)
failed_delivery_urls += 1
logger.warning(
"Apprise notify raised %s for %s: %s",
type(exc).__name__,
plugin_label,
exc,
)
_log_apprise_exception_debug(action="notify", scheme=scheme, exc=exc)
warning_detail = _build_apprise_warning_detail(apprise_records, scheme=scheme)
if warning_detail:
failure_details.append(warning_detail)
else:
failure_details.append(f"{scheme}: notify raised {type(exc).__name__}: {exc}")
continue
_log_apprise_records(apprise_records)
if delivered:
delivered_urls += 1
logger.debug("Notification delivered via %s", plugin_label)
continue
failed_delivery_urls += 1
logger.warning("Apprise notify returned False for %s", plugin_label)
warning_detail = _build_apprise_warning_detail(apprise_records, scheme=scheme)
if warning_detail:
failure_details.append(warning_detail)
else:
failure_details.append(f"{scheme}: delivery failed")
scheme_summary = ", ".join(url_schemes) if url_schemes else "unknown"
if valid_urls == 0:
return {
logger.warning(
"No valid Apprise notification routes after registration for scheme(s): %s",
scheme_summary,
)
result: dict[str, Any] = {
"success": False,
"message": "No valid notification URLs configured",
}
if failure_details:
result["details"] = failure_details
return result
try:
delivered = bool(apobj.notify(title=title, body=body, notify_type=notify_type))
except Exception as exc:
return {"success": False, "message": f"Notification send failed: {type(exc).__name__}: {exc}"}
if delivered_urls == 0:
logger.warning(
(
"Apprise notify returned False for scheme(s): %s "
"(valid_urls=%s invalid_urls=%s failed_deliveries=%s)"
),
scheme_summary,
valid_urls,
invalid_urls,
failed_delivery_urls,
)
result = {"success": False, "message": "Notification delivery failed"}
if failure_details:
result["details"] = failure_details
return result
if not delivered:
return {"success": False, "message": "Notification delivery failed"}
message = f"Notification sent to {valid_urls} URL(s)"
if invalid_urls:
message += f" ({invalid_urls} invalid URL(s) skipped)"
return {"success": True, "message": message}
message = f"Notification sent to {delivered_urls} URL(s)"
failed_urls = invalid_urls + failed_delivery_urls
if failed_urls:
message += f" ({failed_urls} URL(s) failed)"
result = {"success": True, "message": message}
if failure_details:
result["details"] = failure_details
return result
def _create_apprise_client() -> Any:
def _create_apprise_client() -> _AppriseClient | None:
if apprise is None:
return None
@@ -279,7 +581,8 @@ def _create_apprise_client() -> Any:
apprise_asset_cls = getattr(apprise, "AppriseAsset", None)
if apprise_asset_cls is None:
return apprise_cls()
client = apprise_cls()
return client if _is_apprise_client(client) else None
try:
asset = apprise_asset_cls(
@@ -289,20 +592,25 @@ def _create_apprise_client() -> Any:
)
except TypeError:
# Support older Apprise versions that do not expose image_url_logo.
asset = apprise_asset_cls(
app_id=_APPRISE_APP_ID,
app_desc=_APPRISE_APP_DESC,
)
except Exception:
return apprise_cls()
try:
asset = apprise_asset_cls(
app_id=_APPRISE_APP_ID,
app_desc=_APPRISE_APP_DESC,
)
except TypeError:
client = apprise_cls()
return client if _is_apprise_client(client) else None
try:
return apprise_cls(asset=asset)
except Exception:
return apprise_cls()
client = apprise_cls(asset=asset)
except TypeError:
client = apprise_cls()
return client if _is_apprise_client(client) else None
def _send_admin_event(event: NotificationEvent, context: NotificationContext, urls: list[str]) -> dict[str, Any]:
def _send_admin_event(
event: NotificationEvent, context: NotificationContext, urls: list[str]
) -> dict[str, Any]:
title, body = _render_message(context)
notify_type = _resolve_notify_type(event)
return _dispatch_to_apprise(urls, title=title, body=body, notify_type=notify_type)
@@ -317,11 +625,13 @@ def notify_admin(event: NotificationEvent, context: NotificationContext) -> None
try:
_executor.submit(_dispatch_admin_async, event, context, urls)
except Exception as exc:
except RuntimeError as exc:
logger.warning("Failed to queue admin notification '%s': %s", event.value, exc)
def notify_user(user_id: int | None, event: NotificationEvent, context: NotificationContext) -> None:
def notify_user(
user_id: int | None, event: NotificationEvent, context: NotificationContext
) -> None:
"""Send a per-user notification for an event if subscribed."""
normalized_user_id = _normalize_user_id(user_id)
if normalized_user_id is None:
@@ -334,7 +644,7 @@ def notify_user(user_id: int | None, event: NotificationEvent, context: Notifica
try:
_executor.submit(_dispatch_user_async, normalized_user_id, event, context, urls)
except Exception as exc:
except RuntimeError as exc:
logger.warning(
"Failed to queue user notification '%s' for user_id=%s: %s",
event.value,
@@ -343,10 +653,16 @@ def notify_user(user_id: int | None, event: NotificationEvent, context: Notifica
)
def _dispatch_admin_async(event: NotificationEvent, context: NotificationContext, urls: list[str]) -> None:
def _dispatch_admin_async(
event: NotificationEvent, context: NotificationContext, urls: list[str]
) -> None:
result = _send_admin_event(event, context, urls)
if not result.get("success", False):
logger.warning("Admin notification failed for event '%s': %s", event.value, result.get("message"))
logger.warning(
"Admin notification failed for event '%s': %s",
event.value,
result.get("message"),
)
def _dispatch_user_async(
+11 -7
View File
@@ -4,12 +4,15 @@ Handles group claim parsing, user info extraction, and user provisioning.
Flask route handlers are registered separately in main.py.
"""
from typing import Any, Dict, List, Optional
from typing import TYPE_CHECKING, Any
from shelfmark.core.external_user_linking import upsert_external_user
from shelfmark.core.user_db import UserDB
def parse_group_claims(id_token: Dict[str, Any], group_claim: str) -> List[str]:
if TYPE_CHECKING:
from shelfmark.core.user_db import UserDB
def parse_group_claims(id_token: dict[str, Any], group_claim: str) -> list[str]:
"""Extract group list from an ID token claim.
Supports list, comma-separated string, or pipe-separated string.
@@ -26,7 +29,7 @@ def parse_group_claims(id_token: Dict[str, Any], group_claim: str) -> List[str]:
return []
def extract_user_info(id_token: Dict[str, Any]) -> Dict[str, Any]:
def extract_user_info(id_token: dict[str, Any]) -> dict[str, Any]:
"""Extract user info from OIDC ID token claims.
Returns a dict with keys: oidc_subject, username, email, display_name.
@@ -47,11 +50,12 @@ def extract_user_info(id_token: Dict[str, Any]) -> Dict[str, Any]:
def provision_oidc_user(
db: UserDB,
user_info: Dict[str, Any],
is_admin: Optional[bool] = None,
user_info: dict[str, Any],
*,
is_admin: bool | None = None,
allow_email_link: bool = False,
allow_create: bool = True,
) -> Optional[Dict[str, Any]]:
) -> dict[str, Any] | None:
"""Create or update a user from OIDC claims.
Matching and collision handling use the shared external user linker:
+229 -70
View File
@@ -4,93 +4,226 @@ Registers /api/auth/oidc/login and /api/auth/oidc/callback endpoints.
Business logic remains in oidc_auth.py.
"""
from typing import Any
from __future__ import annotations
from authlib.jose.errors import InvalidClaimError
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, Protocol, TypeGuard
from urllib.parse import urlencode, urlsplit, urlunsplit
from authlib.integrations.base_client.errors import OAuthError
from authlib.integrations.flask_client import OAuth
from authlib.jose.errors import InvalidClaimError
from flask import Flask, jsonify, redirect, request, session
from shelfmark.core.config import config as app_config
from shelfmark.core.logger import setup_logger
from shelfmark.core.oidc_auth import (
extract_user_info,
parse_group_claims,
provision_oidc_user,
)
from shelfmark.core.settings_registry import load_config_file
from shelfmark.core.user_db import UserDB
from shelfmark.download.network import get_ssl_verify
if TYPE_CHECKING:
from flask.typing import ResponseReturnValue
from shelfmark.core.user_db import UserDB
logger = setup_logger(__name__)
oauth = OAuth()
_RETURN_TO_SESSION_KEY = "oidc_return_to"
_OIDC_CLIENT_ERRORS = (OAuthError, OSError, RuntimeError, TypeError, ValueError)
_EMPTY_JWKS_MESSAGE = (
"Authentication failed: the identity provider returned no token signing keys "
"(empty JWKS). If you use Authentik, select a Signing Key in the provider "
"settings and try again."
)
def _normalize_claims(raw_claims: Any) -> dict[str, Any]:
class _ClaimsMappingLike(Protocol):
"""Protocol for Authlib claims payloads that expose a to_dict method."""
def to_dict(self) -> Mapping[object, object]: ...
def _has_claims_to_dict(candidate: object) -> TypeGuard[_ClaimsMappingLike]:
"""Return True when a claims object exposes a callable to_dict method."""
return callable(getattr(candidate, "to_dict", None))
def _normalize_claim_mapping(raw_claims: Mapping[object, object]) -> dict[str, Any]:
"""Return only string-keyed claims for downstream OIDC helpers."""
return {key: value for key, value in raw_claims.items() if isinstance(key, str)}
def _normalize_claims(raw_claims: object) -> dict[str, Any]:
"""Return a plain dict for claims from Authlib token/userinfo payloads."""
if raw_claims is None:
return {}
if isinstance(raw_claims, dict):
return raw_claims
if hasattr(raw_claims, "to_dict"):
return raw_claims.to_dict() # type: ignore[no-any-return]
try:
return dict(raw_claims)
except Exception:
return {}
if isinstance(raw_claims, Mapping):
return _normalize_claim_mapping(raw_claims)
if _has_claims_to_dict(raw_claims):
converted_claims = raw_claims.to_dict()
if isinstance(converted_claims, Mapping):
return _normalize_claim_mapping(converted_claims)
return {}
def _has_username_or_email(claims: dict[str, Any]) -> bool:
"""Return True when claims include a usable username or email."""
for key in ("preferred_username", "email"):
value = claims.get(key)
if isinstance(value, str) and value.strip():
return True
return False
def _is_email_verified(claims: dict[str, Any]) -> bool:
"""Normalize provider-specific email_verified values into a strict boolean."""
value = claims.get("email_verified", False)
if isinstance(value, bool):
return value
if isinstance(value, str):
return value.strip().lower() == "true"
"""Return True when claims explicitly mark the email address as verified."""
email_verified = claims.get("email_verified")
if isinstance(email_verified, bool):
return email_verified
if isinstance(email_verified, str):
return email_verified.strip().lower() == "true"
return False
def _login_error_url(message: str) -> str:
"""Build a login URL (with script_root) that includes an OIDC error message."""
script_root = request.script_root.rstrip("/")
login_url = f"{script_root}/login" if script_root else "/login"
params = {"oidc_error": message}
return_to = _get_pending_return_to()
if return_to and return_to != "/":
params["return_to"] = return_to
return f"{login_url}?{urlencode(params)}"
def _normalize_return_to(raw_return_to: object) -> str | None:
"""Return a safe app-relative post-login target."""
if not isinstance(raw_return_to, str):
return None
value = raw_return_to.strip()
if not value or not value.startswith("/") or value.startswith("//"):
return None
parsed = urlsplit(value)
if parsed.scheme or parsed.netloc or "\\" in parsed.path:
return None
script_root = request.script_root.rstrip("/")
path = parsed.path or "/"
if script_root:
if path == script_root:
path = "/"
elif path.startswith(f"{script_root}/"):
path = path[len(script_root) :] or "/"
if path in {"/login", "/api"} or path.startswith(("/login/", "/api/")):
return None
return urlunsplit(("", "", path, parsed.query, parsed.fragment))
def _idp_jwks_has_no_keys(client: Any) -> bool:
"""Return True when the IdP's JWKS document verifiably contains no signing keys."""
try:
jwk_set = client.fetch_jwk_set(force=True)
except (*_OIDC_CLIENT_ERRORS, KeyError):
return False
if not isinstance(jwk_set, Mapping):
return False
return not jwk_set.get("keys")
def _get_pending_return_to(*, clear: bool = False) -> str | None:
"""Read the pending post-login target from the session."""
raw_return_to = (
session.pop(_RETURN_TO_SESSION_KEY, None) if clear else session.get(_RETURN_TO_SESSION_KEY)
)
normalized = _normalize_return_to(raw_return_to)
if normalized is None and not clear:
session.pop(_RETURN_TO_SESSION_KEY, None)
return normalized
def _post_login_redirect_target(return_to: str | None) -> str:
"""Build the final redirect target, honoring script_root when present."""
normalized = _normalize_return_to(return_to) or "/"
script_root = request.script_root.rstrip("/")
if not script_root:
return normalized
if normalized == "/":
return f"{script_root}/"
return f"{script_root}{normalized}"
def _get_oidc_client() -> tuple[Any, dict[str, Any]]:
"""Register and return an OIDC client from the current security config."""
config = load_config_file("security")
discovery_url = config.get("OIDC_DISCOVERY_URL", "")
client_id = config.get("OIDC_CLIENT_ID", "")
discovery_url = str(app_config.get("OIDC_DISCOVERY_URL", "") or "")
client_id = str(app_config.get("OIDC_CLIENT_ID", "") or "")
if not discovery_url or not client_id:
raise ValueError("OIDC not configured")
msg = "OIDC not configured"
raise ValueError(msg)
configured_scopes = config.get("OIDC_SCOPES", ["openid", "email", "profile"])
configured_scopes = app_config.get("OIDC_SCOPES", ["openid", "email", "profile"])
if isinstance(configured_scopes, list):
scope_values = [str(scope).strip() for scope in configured_scopes if str(scope).strip()]
elif isinstance(configured_scopes, str):
delimiter = "," if "," in configured_scopes else " "
scope_values = [scope.strip() for scope in configured_scopes.split(delimiter) if scope.strip()]
scope_values = [
scope.strip() for scope in configured_scopes.split(delimiter) if scope.strip()
]
else:
scope_values = []
scopes = list(dict.fromkeys(["openid"] + scope_values))
scopes = list(dict.fromkeys(["openid", *scope_values]))
admin_group = config.get("OIDC_ADMIN_GROUP", "")
group_claim = config.get("OIDC_GROUP_CLAIM", "groups")
use_admin_group = config.get("OIDC_USE_ADMIN_GROUP", True)
admin_group_value = app_config.get("OIDC_ADMIN_GROUP", "")
admin_group = admin_group_value.strip() if isinstance(admin_group_value, str) else ""
group_claim_value = app_config.get("OIDC_GROUP_CLAIM", "groups")
group_claim = (
group_claim_value.strip()
if isinstance(group_claim_value, str) and group_claim_value.strip()
else "groups"
)
use_admin_group = app_config.get("OIDC_USE_ADMIN_GROUP", True)
if admin_group and use_admin_group and group_claim and group_claim not in scopes:
scopes.append(group_claim)
def _ssl_compliance_fix(session: Any, **kwargs: Any) -> Any:
"""Set session.verify based on the Certificate Validation setting."""
session.verify = get_ssl_verify(discovery_url)
return session
oauth._clients.pop("shelfmark_idp", None)
oauth.register(
name="shelfmark_idp",
client_id=client_id,
client_secret=config.get("OIDC_CLIENT_SECRET", ""),
client_secret=app_config.get("OIDC_CLIENT_SECRET", ""),
server_metadata_url=discovery_url,
client_kwargs={
"scope": " ".join(scopes),
"code_challenge_method": "S256",
},
compliance_fix=_ssl_compliance_fix,
overwrite=True,
)
client = oauth.create_client("shelfmark_idp")
if client is None:
raise RuntimeError("OIDC client initialization failed")
msg = "OIDC client initialization failed"
raise RuntimeError(msg)
return client, config
return client, {
"OIDC_DISCOVERY_URL": discovery_url,
"OIDC_GROUP_CLAIM": group_claim,
"OIDC_ADMIN_GROUP": admin_group,
"OIDC_AUTO_PROVISION": app_config.get("OIDC_AUTO_PROVISION", True),
"OIDC_USE_ADMIN_GROUP": use_admin_group,
}
def register_oidc_routes(app: Flask, user_db: UserDB) -> None:
@@ -98,26 +231,31 @@ def register_oidc_routes(app: Flask, user_db: UserDB) -> None:
oauth.init_app(app)
@app.route("/api/auth/oidc/login", methods=["GET"])
def oidc_login():
def oidc_login() -> ResponseReturnValue:
"""Initiate OIDC login flow and redirect to the provider."""
try:
client, _ = _get_oidc_client()
return_to = _normalize_return_to(request.args.get("return_to"))
if return_to and return_to != "/":
session[_RETURN_TO_SESSION_KEY] = return_to
else:
session.pop(_RETURN_TO_SESSION_KEY, None)
redirect_uri = request.url_root.rstrip("/") + "/api/auth/oidc/callback"
return client.authorize_redirect(redirect_uri)
except ValueError:
return jsonify({"error": "OIDC not configured"}), 500
except Exception as e:
logger.error(f"OIDC login error: {e}")
except Exception:
logger.exception("OIDC login error")
return jsonify({"error": "OIDC login failed"}), 500
@app.route("/api/auth/oidc/callback", methods=["GET"])
def oidc_callback():
def oidc_callback() -> ResponseReturnValue:
"""Handle OIDC callback from identity provider."""
try:
error = request.args.get("error")
if error:
logger.warning(f"OIDC callback error from IdP: {error}")
return jsonify({"error": "Authentication failed"}), 400
logger.warning("OIDC callback error from IdP: %s", error)
return redirect(_login_error_url("Authentication failed"))
client, config = _get_oidc_client()
try:
@@ -130,43 +268,57 @@ def register_oidc_routes(app: Flask, user_db: UserDB) -> None:
metadata = client.load_server_metadata()
if isinstance(metadata, dict):
provider_issuer = str(metadata.get("issuer", ""))
except Exception as metadata_error:
logger.debug(f"OIDC metadata lookup failed during claim diagnostics: {metadata_error}")
except _OIDC_CLIENT_ERRORS as metadata_error:
logger.debug(
"OIDC metadata lookup failed during claim diagnostics: %s",
metadata_error,
)
logger.error(
"OIDC callback claim validation failed: claim=%s error=%s discovery_url=%s provider_issuer=%s",
logger.exception(
"OIDC callback claim validation failed: claim=%s discovery_url=%s provider_issuer=%s",
claim_name,
e,
discovery_url or "<unset>",
provider_issuer or "<unknown>",
)
if claim_name == "iss":
return (
jsonify(
{
"error": (
"OIDC issuer validation failed. Verify your discovery URL and IdP issuer/"
"external URL configuration."
)
}
),
400,
msg = (
"OIDC issuer validation failed. Verify your discovery URL and IdP issuer/"
"external URL configuration."
)
return redirect(_login_error_url(msg))
return jsonify({"error": f"OIDC token claim validation failed: {claim_name}"}), 400
return redirect(
_login_error_url(f"OIDC token claim validation failed: {claim_name}")
)
except KeyError, ValueError:
# An IdP serving an empty JWKS document (e.g. an Authentik provider
# with no Signing Key selected) surfaces as KeyError('keys') while
# importing the key set. Test Connection only validates discovery,
# so this is the first place the misconfiguration becomes visible.
if _idp_jwks_has_no_keys(client):
logger.exception(
"OIDC callback failed: the IdP JWKS document contains no signing keys"
)
return redirect(_login_error_url(_EMPTY_JWKS_MESSAGE))
raise
claims = _normalize_claims(token.get("userinfo"))
# If userinfo isn't present in token payload, request it explicitly.
if not claims:
# If userinfo is missing or claims are too sparse, request it explicitly.
if not claims or not _has_username_or_email(claims):
fetched_claims: dict[str, Any] = {}
try:
claims = _normalize_claims(client.userinfo(token=token))
fetched_claims = _normalize_claims(client.userinfo(token=token))
except TypeError:
claims = _normalize_claims(client.userinfo())
except Exception as e:
logger.error(f"Failed to fetch OIDC userinfo: {e}")
fetched_claims = _normalize_claims(client.userinfo())
except Exception:
logger.exception("Failed to fetch OIDC userinfo")
if fetched_claims:
claims = {**claims, **fetched_claims}
if not claims:
raise ValueError("OIDC authentication failed: missing user claims")
msg = "OIDC authentication failed: missing user claims"
logger.error(msg)
return redirect(_login_error_url(msg))
group_claim = config.get("OIDC_GROUP_CLAIM", "groups")
admin_group = config.get("OIDC_ADMIN_GROUP", "")
@@ -181,6 +333,12 @@ def register_oidc_routes(app: Flask, user_db: UserDB) -> None:
is_admin = admin_group in groups
allow_email_link = bool(user_info.get("email")) and _is_email_verified(claims)
if user_info.get("email") and not allow_email_link:
logger.debug(
"OIDC email %s is not marked verified by the IdP; skipping "
"email-based account linking",
user_info["email"],
)
user = provision_oidc_user(
user_db,
user_info,
@@ -190,21 +348,22 @@ def register_oidc_routes(app: Flask, user_db: UserDB) -> None:
)
if user is None:
logger.warning(
f"OIDC login rejected: auto-provision disabled for {user_info['username']}"
"OIDC login rejected: auto-provision disabled for %s",
user_info["username"],
)
return jsonify({"error": "Account not found. Contact your administrator."}), 403
return redirect(_login_error_url("Account not found. Contact your administrator."))
session["user_id"] = user["username"]
session["is_admin"] = user.get("role") == "admin"
session["db_user_id"] = user["id"]
session.permanent = True
logger.info(f"OIDC login successful: {user['username']} (admin={is_admin})")
return redirect(request.script_root or "/")
logger.info("OIDC login successful: %s (admin=%s)", user["username"], is_admin)
return redirect(_post_login_redirect_target(_get_pending_return_to(clear=True)))
except ValueError as e:
logger.error(f"OIDC callback error: {e}")
return jsonify({"error": str(e)}), 400
except Exception as e:
logger.error(f"OIDC callback error: {e}")
return jsonify({"error": "Authentication failed"}), 500
logger.exception("OIDC callback error")
return redirect(_login_error_url(str(e)))
except Exception:
logger.exception("OIDC callback error")
return redirect(_login_error_url("Authentication failed"))
+455 -147
View File
@@ -1,5 +1,4 @@
"""
Onboarding wizard configuration.
"""Onboarding wizard configuration.
Defines the steps and fields for the first-run onboarding experience.
Reuses field definitions from the settings registry where possible.
@@ -8,27 +7,32 @@ Reuses field definitions from the settings registry where possible.
import json
from dataclasses import replace
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Any
from shelfmark.core.logger import setup_logger
from shelfmark.core.settings_registry import (
HeadingField,
MultiSelectField,
SettingsField,
get_settings_tab,
serialize_field,
save_config_file,
get_setting_value,
get_settings_field_map,
get_settings_tab,
save_config_file,
serialize_field,
)
logger = setup_logger(__name__)
ONBOARDING_STORAGE_KEY = "onboarding_complete"
ONBOARDING_RELEASE_SOURCES_KEY = "ONBOARDING_RELEASE_SOURCES"
_ONBOARDING_VIRTUAL_KEYS = {ONBOARDING_RELEASE_SOURCES_KEY}
def _get_config_dir() -> Path:
"""Get the config directory path."""
from shelfmark.config.env import CONFIG_DIR
return Path(CONFIG_DIR)
@@ -45,11 +49,11 @@ def is_onboarding_complete() -> bool:
return False
try:
with open(config_file, 'r') as f:
with config_file.open() as f:
config = json.load(f)
return config.get(ONBOARDING_STORAGE_KEY, False)
except (json.JSONDecodeError, OSError) as e:
logger.warning(f"Could not read onboarding status from settings.json: {e}")
logger.warning("Could not read onboarding status from settings.json: %s", e)
return False
@@ -57,14 +61,13 @@ def mark_onboarding_complete() -> bool:
"""Mark onboarding as complete."""
try:
return save_config_file("general", {ONBOARDING_STORAGE_KEY: True})
except Exception as e:
logger.error(f"Failed to mark onboarding complete: {e}")
except Exception:
logger.exception("Failed to mark onboarding complete")
return False
def _get_field_from_tab(tab_name: str, field_key: str) -> Optional[SettingsField]:
"""
Extract a specific field from a registered settings tab.
def _get_field_from_tab(tab_name: str, field_key: str) -> SettingsField | None:
"""Extract a specific field from a registered settings tab.
Args:
tab_name: Name of the settings tab (e.g., 'search_mode', 'hardcover')
@@ -72,37 +75,145 @@ def _get_field_from_tab(tab_name: str, field_key: str) -> Optional[SettingsField
Returns:
The field if found, None otherwise
"""
tab = get_settings_tab(tab_name)
if not tab:
logger.warning(f"Settings tab not found: {tab_name}")
logger.warning("Settings tab not found: %s", tab_name)
return None
for field in tab.fields:
if hasattr(field, 'key') and field.key == field_key:
if hasattr(field, "key") and field.key == field_key:
return field
logger.warning(f"Field {field_key} not found in tab {tab_name}")
logger.warning("Field %s not found in tab %s", field_key, tab_name)
return None
def _clone_field_with_overrides(field: SettingsField, **overrides) -> SettingsField:
"""
Clone a field with optional attribute overrides.
def _get_field_tab_name(field: SettingsField, fallback_tab_name: str) -> str:
"""Return the owning settings tab for a value field."""
field_key = getattr(field, "key", None)
if not field_key:
return fallback_tab_name
field_map = get_settings_field_map()
field_entry = field_map.get(field_key)
if field_entry is None:
return fallback_tab_name
return field_entry[1]
def _clone_field_with_overrides(field: SettingsField, **overrides: object) -> SettingsField:
"""Clone a field with optional attribute overrides.
Useful for customizing labels, descriptions, or defaults for onboarding context.
"""
return replace(field, **overrides)
def _get_fields_from_tab(
tab_name: str,
field_keys: list[str],
*,
strip_show_when_keys: set[str] | None = None,
) -> list[SettingsField]:
"""Return the requested fields from a settings tab in the supplied order."""
fields: list[SettingsField] = []
for field_key in field_keys:
field = _get_field_from_tab(tab_name, field_key)
if field:
show_when = getattr(field, "show_when", None)
stripped_show_when = _strip_show_when_keys(show_when, strip_show_when_keys or set())
if stripped_show_when != show_when:
field = replace(field, show_when=stripped_show_when)
fields.append(field)
return fields
def _strip_show_when_keys(
show_when: dict[str, Any] | list[dict[str, Any]] | None,
field_keys: set[str],
) -> dict[str, Any] | list[dict[str, Any]] | None:
"""Remove conditions tied to fields that onboarding handles implicitly."""
if not show_when or not field_keys:
return show_when
if isinstance(show_when, list):
remaining = [
condition for condition in show_when if condition.get("field") not in field_keys
]
return remaining or None
if show_when.get("field") in field_keys:
return None
return show_when
def _is_release_source_selected(values: dict[str, Any], source_name: str) -> bool:
"""Return True when a release source has been chosen during onboarding."""
raw_sources = values.get(ONBOARDING_RELEASE_SOURCES_KEY, [])
if not isinstance(raw_sources, list):
return False
return source_name in raw_sources
def _evaluate_show_when_condition(condition: dict[str, Any], values: dict[str, Any]) -> bool:
"""Evaluate one onboarding show_when condition against submitted values."""
current_value = values.get(condition["field"])
expected_value = condition.get("value")
if condition.get("notEmpty"):
if isinstance(current_value, list):
return len(current_value) > 0
return current_value not in (None, "")
if isinstance(current_value, list):
if isinstance(expected_value, list):
return all(item in current_value for item in expected_value)
return expected_value in current_value
if isinstance(expected_value, list):
return current_value in expected_value
return current_value == expected_value
def _is_step_visible(step_config: dict[str, Any], values: dict[str, Any]) -> bool:
"""Return True when a step should be included for the provided values."""
show_when = step_config.get("show_when")
if not show_when:
return True
return all(_evaluate_show_when_condition(condition, values) for condition in show_when)
def _is_field_visible(field: SettingsField, values: dict[str, Any]) -> bool:
"""Return True when a field should be included in the onboarding save."""
if getattr(field, "hidden_in_ui", False):
return False
if getattr(field, "universal_only", False) and values.get("SEARCH_MODE") != "universal":
return False
show_when = getattr(field, "show_when", None)
if not show_when:
return True
if isinstance(show_when, list):
return all(_evaluate_show_when_condition(condition, values) for condition in show_when)
return _evaluate_show_when_condition(show_when, values)
# =============================================================================
# Step Definitions
# =============================================================================
def get_search_mode_fields() -> List[SettingsField]:
def get_search_mode_fields() -> list[SettingsField]:
"""Step 1: Choose search mode - uses actual SEARCH_MODE field from settings."""
fields: List[SettingsField] = [
fields: list[SettingsField] = [
HeadingField(
key="welcome_heading",
title="Welcome to Shelfmark",
@@ -114,17 +225,19 @@ def get_search_mode_fields() -> List[SettingsField]:
search_mode_field = _get_field_from_tab("search_mode", "SEARCH_MODE")
if search_mode_field:
# Clone with onboarding-specific description
fields.append(_clone_field_with_overrides(
search_mode_field,
description="Choose how you want to find books.",
))
fields.append(
_clone_field_with_overrides(
search_mode_field,
description="Choose how you want to find books.",
)
)
return fields
def get_metadata_provider_fields() -> List[SettingsField]:
def get_metadata_provider_fields() -> list[SettingsField]:
"""Step 2: Choose metadata provider - uses actual METADATA_PROVIDER field."""
fields: List[SettingsField] = [
fields: list[SettingsField] = [
HeadingField(
key="metadata_heading",
title="Metadata Provider",
@@ -155,18 +268,20 @@ def get_metadata_provider_fields() -> List[SettingsField]:
]
# Clone with onboarding-specific options and default
fields.append(_clone_field_with_overrides(
provider_field,
default="hardcover",
options=onboarding_options,
))
fields.append(
_clone_field_with_overrides(
provider_field,
default="hardcover",
options=onboarding_options,
)
)
return fields
def get_hardcover_setup_fields() -> List[SettingsField]:
def get_hardcover_setup_fields() -> list[SettingsField]:
"""Step 3a: Configure Hardcover - uses actual API key and test connection fields."""
fields: List[SettingsField] = [
fields: list[SettingsField] = [
HeadingField(
key="hardcover_setup_heading",
title="Hardcover Setup",
@@ -189,9 +304,9 @@ def get_hardcover_setup_fields() -> List[SettingsField]:
return fields
def get_googlebooks_setup_fields() -> List[SettingsField]:
def get_googlebooks_setup_fields() -> list[SettingsField]:
"""Step 3b: Configure Google Books - uses actual API key and test connection fields."""
fields: List[SettingsField] = [
fields: list[SettingsField] = [
HeadingField(
key="googlebooks_setup_heading",
title="Google Books Setup",
@@ -214,129 +329,270 @@ def get_googlebooks_setup_fields() -> List[SettingsField]:
return fields
def get_prowlarr_fields() -> List[SettingsField]:
"""Step 4: Configure Prowlarr connection - uses actual Prowlarr fields."""
fields: List[SettingsField] = [
def get_release_source_selection_fields() -> list[SettingsField]:
"""Choose which release sources to configure during onboarding."""
fields: list[SettingsField] = [
HeadingField(
key="prowlarr_heading",
title="Prowlarr Integration (Optional)",
description="Connect to Prowlarr to search your indexers for torrents and NZBs. Skip this step if you only want to use Direct Download.",
key="release_sources_heading",
title="Release Sources",
description=(
"Choose the release sources you want to configure now. You can always add or "
"change sources later in Settings."
),
),
MultiSelectField(
key=ONBOARDING_RELEASE_SOURCES_KEY,
label="Sources to Set Up",
description="Select one or more release sources to configure now.",
default=[],
variant="dropdown",
env_supported=False,
options=[
{
"value": "direct_download",
"label": "Direct Download",
"description": "Configure your own Anna's Archive mirror URLs for direct ebook downloads.",
},
{
"value": "prowlarr",
"label": "Prowlarr",
"description": "Search your torrent and Usenet indexers through Prowlarr.",
},
{
"value": "audiobookbay",
"label": "AudiobookBay",
"description": "Search AudiobookBay directly for audiobook releases.",
},
{
"value": "irc",
"label": "IRC",
"description": "Connect to IRC for ebook and audiobook release searches.",
},
],
),
]
# Get actual Prowlarr connection fields
prowlarr_fields = ["PROWLARR_ENABLED", "PROWLARR_URL", "PROWLARR_API_KEY", "test_prowlarr"]
for field_key in prowlarr_fields:
field = _get_field_from_tab("prowlarr_config", field_key)
if field:
fields.append(field)
return fields
def get_prowlarr_indexers_fields() -> List[SettingsField]:
"""Step 5: Select Prowlarr indexers to search."""
fields: List[SettingsField] = [
def get_direct_download_setup_fields() -> list[SettingsField]:
"""Render trimmed direct-download essentials for onboarding."""
fields: list[SettingsField] = [
HeadingField(
key="prowlarr_indexers_heading",
title="Select Indexers",
description="Choose which indexers to search for books. Leave empty to search all available indexers.",
),
key="direct_download_setup_onboarding_heading",
title="Direct Download Setup",
description=(
"Add at least one Anna's Archive mirror URL to enable Direct Download. If you "
"have an Anna's Archive donator key, you can add it here too. You can configure "
"alternative mirrors later in Settings."
),
)
]
# Get the indexers multi-select field
indexers_field = _get_field_from_tab("prowlarr_config", "PROWLARR_INDEXERS")
if indexers_field:
fields.append(indexers_field)
fields.extend(_get_fields_from_tab("download_sources", ["AA_DONATOR_KEY"]))
fields.extend(_get_fields_from_tab("mirrors", ["AA_MIRROR_URLS"]))
return fields
# =============================================================================
# Step Configuration
# =============================================================================
ONBOARDING_STEPS = [
{
"id": "search_mode",
"title": "Search Mode",
"tab": "search_mode",
"get_fields": get_search_mode_fields,
},
{
"id": "metadata_provider",
"title": "Metadata Provider",
"tab": "search_mode",
"get_fields": get_metadata_provider_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "universal"}],
},
{
"id": "hardcover_setup",
"title": "Hardcover Setup",
"tab": "hardcover",
"get_fields": get_hardcover_setup_fields,
# Must be universal mode AND hardcover selected
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": "METADATA_PROVIDER", "value": "hardcover"},
def get_direct_download_bypass_fields() -> list[SettingsField]:
"""Render only the core Cloudflare bypass fields for onboarding."""
return _get_fields_from_tab(
"cloudflare_bypass",
[
"USE_CF_BYPASS",
"USING_EXTERNAL_BYPASSER",
"EXT_BYPASSER_URL",
"EXT_BYPASSER_PATH",
],
},
{
"id": "googlebooks_setup",
"title": "Google Books Setup",
"tab": "googlebooks",
"get_fields": get_googlebooks_setup_fields,
# Must be universal mode AND googlebooks selected
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": "METADATA_PROVIDER", "value": "googlebooks"},
],
},
{
"id": "prowlarr",
"title": "Prowlarr",
"tab": "prowlarr_config",
"get_fields": get_prowlarr_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "universal"}],
"optional": True,
},
{
"id": "prowlarr_indexers",
"title": "Indexers",
"tab": "prowlarr_config",
"get_fields": get_prowlarr_indexers_fields,
# Only show when Prowlarr is enabled
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": "PROWLARR_ENABLED", "value": True},
],
"optional": True,
},
]
)
def get_onboarding_config() -> Dict[str, Any]:
"""
Get the full onboarding configuration including steps and current values.
"""
def get_prowlarr_fields() -> list[SettingsField]:
"""Render trimmed Prowlarr setup fields for onboarding."""
return _get_fields_from_tab(
"prowlarr_config",
[
"prowlarr_heading",
"PROWLARR_URL",
"PROWLARR_API_KEY",
"test_prowlarr",
"PROWLARR_INDEXERS",
],
strip_show_when_keys={"PROWLARR_ENABLED"},
)
def get_audiobookbay_fields() -> list[SettingsField]:
"""Render trimmed AudiobookBay setup fields for onboarding."""
return [
HeadingField(
key="audiobookbay_onboarding_heading",
title="AudiobookBay",
description="Add the AudiobookBay domain you want Shelfmark to search.",
),
*_get_fields_from_tab(
"audiobookbay_config",
["ABB_HOSTNAME"],
strip_show_when_keys={"ABB_ENABLED"},
),
]
def get_irc_fields() -> list[SettingsField]:
"""Render trimmed IRC setup fields for onboarding."""
return _get_fields_from_tab(
"irc",
[
"heading",
"IRC_SERVER",
"IRC_PORT",
"IRC_USE_TLS",
"IRC_CHANNEL",
"IRC_NICK",
"IRC_SEARCH_BOT",
],
)
def get_onboarding_steps() -> list[dict[str, Any]]:
"""Return the full onboarding step configuration."""
return [
{
"id": "search_mode",
"title": "Search Mode",
"tab": "search_mode",
"get_fields": get_search_mode_fields,
},
{
"id": "metadata_provider",
"title": "Metadata Provider",
"tab": "search_mode",
"get_fields": get_metadata_provider_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "universal"}],
},
{
"id": "hardcover_setup",
"title": "Hardcover Setup",
"tab": "hardcover",
"get_fields": get_hardcover_setup_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": "METADATA_PROVIDER", "value": "hardcover"},
],
},
{
"id": "googlebooks_setup",
"title": "Google Books Setup",
"tab": "googlebooks",
"get_fields": get_googlebooks_setup_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": "METADATA_PROVIDER", "value": "googlebooks"},
],
},
{
"id": "release_sources",
"title": "Release Sources",
"tab": "search_mode",
"get_fields": get_release_source_selection_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "universal"}],
"optional": True,
},
{
"id": "direct_download_setup_direct_mode",
"title": "Direct Download Setup",
"tab": "download_sources",
"get_fields": get_direct_download_setup_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "direct"}],
},
{
"id": "direct_download_cloudflare_bypass_direct_mode",
"title": "Cloudflare Bypass",
"tab": "cloudflare_bypass",
"get_fields": get_direct_download_bypass_fields,
"show_when": [{"field": "SEARCH_MODE", "value": "direct"}],
},
{
"id": "direct_download_setup",
"title": "Direct Download Setup",
"tab": "download_sources",
"get_fields": get_direct_download_setup_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": ONBOARDING_RELEASE_SOURCES_KEY, "value": "direct_download"},
],
"optional": True,
},
{
"id": "direct_download_cloudflare_bypass",
"title": "Cloudflare Bypass",
"tab": "cloudflare_bypass",
"get_fields": get_direct_download_bypass_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": ONBOARDING_RELEASE_SOURCES_KEY, "value": "direct_download"},
],
"optional": True,
},
{
"id": "prowlarr",
"title": "Prowlarr",
"tab": "prowlarr_config",
"get_fields": get_prowlarr_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": ONBOARDING_RELEASE_SOURCES_KEY, "value": "prowlarr"},
],
"optional": True,
},
{
"id": "audiobookbay",
"title": "AudiobookBay",
"tab": "audiobookbay_config",
"get_fields": get_audiobookbay_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": ONBOARDING_RELEASE_SOURCES_KEY, "value": "audiobookbay"},
],
"optional": True,
},
{
"id": "irc",
"title": "IRC",
"tab": "irc",
"get_fields": get_irc_fields,
"show_when": [
{"field": "SEARCH_MODE", "value": "universal"},
{"field": ONBOARDING_RELEASE_SOURCES_KEY, "value": "irc"},
],
"optional": True,
},
]
def get_onboarding_config() -> dict[str, Any]:
"""Get the full onboarding configuration including steps and current values."""
steps = []
all_values = {}
for step_config in ONBOARDING_STEPS:
for step_config in get_onboarding_steps():
fields = step_config["get_fields"]()
tab_name = step_config["tab"]
# Serialize fields with current values
serialized_fields = []
for field in fields:
serialized = serialize_field(field, tab_name, include_value=True)
field_tab_name = _get_field_tab_name(field, tab_name)
serialized = serialize_field(field, field_tab_name, include_value=True)
serialized_fields.append(serialized)
# Collect values (skip HeadingFields)
if hasattr(field, 'key') and field.key and not isinstance(field, HeadingField):
value = get_setting_value(field, tab_name)
all_values[field.key] = value if value is not None else getattr(field, 'default', '')
if hasattr(field, "env_supported") and getattr(field, "key", None):
if field.key in _ONBOARDING_VIRTUAL_KEYS:
value = getattr(field, "default", "")
else:
value = get_setting_value(field, field_tab_name)
all_values[field.key] = (
value if value is not None else getattr(field, "default", "")
)
step = {
"id": step_config["id"],
@@ -359,22 +615,24 @@ def get_onboarding_config() -> Dict[str, Any]:
}
def save_onboarding_settings(values: Dict[str, Any]) -> Dict[str, Any]:
"""
Save onboarding settings and mark as complete.
def save_onboarding_settings(values: dict[str, Any]) -> dict[str, Any]:
"""Save onboarding settings and mark as complete.
Args:
values: Dict of field key -> value
Returns:
Dict with success status and message
"""
try:
# Group values by their target tab
tab_values: Dict[str, Dict[str, Any]] = {}
tab_values: dict[str, dict[str, Any]] = {}
for step_config in get_onboarding_steps():
if not _is_step_visible(step_config, values):
continue
for step_config in ONBOARDING_STEPS:
tab_name = step_config["tab"]
fields = step_config["get_fields"]()
for field in fields:
@@ -382,7 +640,12 @@ def save_onboarding_settings(values: Dict[str, Any]) -> Dict[str, Any]:
continue
key = field.key
if key in _ONBOARDING_VIRTUAL_KEYS:
continue
if not _is_field_visible(field, values):
continue
if key in values:
tab_name = _get_field_tab_name(field, step_config["tab"])
if tab_name not in tab_values:
tab_values[tab_name] = {}
tab_values[tab_name][key] = values[key]
@@ -391,10 +654,9 @@ def save_onboarding_settings(values: Dict[str, Any]) -> Dict[str, Any]:
for tab_name, tab_data in tab_values.items():
if tab_data:
save_config_file(tab_name, tab_data)
logger.info(f"Saved onboarding settings to {tab_name}: {list(tab_data.keys())}")
logger.info("Saved onboarding settings to %s: %s", tab_name, list(tab_data.keys()))
# Enable the selected metadata provider
search_mode = values.get("SEARCH_MODE", "direct")
search_mode = values.get("SEARCH_MODE", "universal")
if search_mode == "universal":
provider = values.get("METADATA_PROVIDER", "hardcover")
if provider:
@@ -416,7 +678,52 @@ def save_onboarding_settings(values: Dict[str, Any]) -> Dict[str, Any]:
provider_config["GOOGLEBOOKS_API_KEY"] = values["GOOGLEBOOKS_API_KEY"]
save_config_file(provider, provider_config)
logger.info(f"Enabled metadata provider: {provider} with keys: {list(provider_config.keys())}")
logger.info(
"Enabled metadata provider: %s with keys: %s",
provider,
list(provider_config.keys()),
)
selected_release_sources = values.get(ONBOARDING_RELEASE_SOURCES_KEY, [])
if not isinstance(selected_release_sources, list):
selected_release_sources = []
source_updates: dict[str, dict[str, Any]] = {}
if search_mode == "direct":
source_updates.setdefault("download_sources", {})["DIRECT_DOWNLOAD_ENABLED"] = True
else:
if _is_release_source_selected(values, "direct_download"):
source_updates.setdefault("download_sources", {})["DIRECT_DOWNLOAD_ENABLED"] = True
if _is_release_source_selected(values, "prowlarr"):
source_updates.setdefault("prowlarr_config", {})["PROWLARR_ENABLED"] = True
if _is_release_source_selected(values, "audiobookbay"):
source_updates.setdefault("audiobookbay_config", {})["ABB_ENABLED"] = True
if not values.get("DEFAULT_RELEASE_SOURCE"):
for source_name in selected_release_sources:
if source_name in {"direct_download", "prowlarr", "irc"}:
source_updates.setdefault("search_mode", {})["DEFAULT_RELEASE_SOURCE"] = (
source_name
)
break
if not values.get("DEFAULT_RELEASE_SOURCE_AUDIOBOOK"):
for source_name in selected_release_sources:
if source_name in {"prowlarr", "audiobookbay", "irc"}:
source_updates.setdefault("search_mode", {})[
"DEFAULT_RELEASE_SOURCE_AUDIOBOOK"
] = source_name
break
for tab_name, tab_data in source_updates.items():
if tab_data:
save_config_file(tab_name, tab_data)
logger.info(
"Enabled onboarding release source settings for %s: %s",
tab_name,
list(tab_data.keys()),
)
# Mark onboarding as complete
mark_onboarding_complete()
@@ -424,12 +731,13 @@ def save_onboarding_settings(values: Dict[str, Any]) -> Dict[str, Any]:
# Refresh config
try:
from shelfmark.core.config import config
config.refresh()
except ImportError as e:
logger.debug(f"Could not refresh config after onboarding: {e}")
return {"success": True, "message": "Onboarding complete!"}
logger.debug("Could not refresh config after onboarding: %s", e)
except Exception as e:
logger.error(f"Failed to save onboarding settings: {e}")
logger.exception("Failed to save onboarding settings")
return {"success": False, "message": str(e)}
else:
return {"success": True, "message": "Onboarding complete!"}
+73 -14
View File
@@ -10,12 +10,19 @@ A mapping rewrites a remote path prefix into a local path prefix.
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Iterable, Optional
from pathlib import Path, PureWindowsPath
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterable
_WINDOWS_DRIVE_PREFIX_LENGTH = 2
@dataclass(frozen=True)
class RemotePathMapping:
"""Mapping from a remote path prefix to a local path prefix."""
host: str
remote_path: str
local_path: str
@@ -36,14 +43,51 @@ def _normalize_prefix(path: str) -> str:
def _is_windows_path(path: str) -> bool:
"""Check if a path looks like a Windows path (has a drive letter like C:/)."""
return len(path) >= 2 and path[1] == ":" and path[0].isalpha()
return len(path) >= _WINDOWS_DRIVE_PREFIX_LENGTH and path[1] == ":" and path[0].isalpha()
def _normalize_host(host: str) -> str:
return str(host or "").strip().lower()
def parse_remote_path_mappings(value: Any) -> list[RemotePathMapping]:
def _is_relative_to(path: Path, prefix: Path) -> bool:
try:
path.relative_to(prefix)
except ValueError:
return False
return True
def _join_contained_path(local_prefix: str, remainder: str) -> Path | None:
local_path = Path(local_prefix)
if remainder:
remainder_path = Path(remainder)
windows_remainder_path = PureWindowsPath(remainder)
if (
remainder_path.is_absolute()
or windows_remainder_path.is_absolute()
or ".." in remainder_path.parts
or ".." in windows_remainder_path.parts
):
return None
remapped = local_path / remainder_path
else:
remapped = local_path
resolved_local_path = local_path.resolve(strict=False)
resolved_remapped = remapped.resolve(strict=False)
if not _is_relative_to(resolved_remapped, resolved_local_path):
return None
return remapped
def parse_remote_path_mappings(value: object) -> list[RemotePathMapping]:
"""Parse configured remote-path mapping rows into normalized mappings."""
if not value or not isinstance(value, list):
return []
@@ -60,7 +104,9 @@ def parse_remote_path_mappings(value: Any) -> list[RemotePathMapping]:
if not host or not remote_path or not local_path:
continue
mappings.append(RemotePathMapping(host=host, remote_path=remote_path, local_path=local_path))
mappings.append(
RemotePathMapping(host=host, remote_path=remote_path, local_path=local_path)
)
mappings.sort(key=lambda m: len(m.remote_path), reverse=True)
return mappings
@@ -71,7 +117,12 @@ def remap_remote_to_local_with_match(
mappings: Iterable[RemotePathMapping],
host: str,
remote_path: str | Path,
) -> tuple[Path, bool]:
) -> tuple[Path | None, bool]:
"""Remap a remote path and report whether a configured mapping matched.
Returns ``(None, True)`` when a mapping prefix matched but the remainder was
unsafe to join under the local prefix.
"""
host_normalized = _normalize_host(host)
remote_normalized = _normalize_prefix(str(remote_path))
@@ -96,39 +147,47 @@ def remap_remote_to_local_with_match(
prefix_lower = remote_prefix.lower()
matches = remote_lower == prefix_lower or remote_lower.startswith(prefix_lower + "/")
else:
matches = remote_normalized == remote_prefix or remote_normalized.startswith(remote_prefix + "/")
matches = remote_normalized == remote_prefix or remote_normalized.startswith(
remote_prefix + "/"
)
if matches:
# Use the length of the original prefix to extract remainder
# This preserves the original case in folder names
remainder = remote_normalized[len(remote_prefix):]
remainder = remote_normalized[len(remote_prefix) :]
local_prefix = _normalize_prefix(mapping.local_path)
if remainder.startswith("/"):
remainder = remainder[1:]
remainder = remainder.removeprefix("/")
remapped = _join_contained_path(local_prefix, remainder)
if remapped is None:
return None, True
remapped = Path(local_prefix) / remainder if remainder else Path(local_prefix)
return remapped, True
return Path(remote_normalized), False
def remap_remote_to_local(*, mappings: Iterable[RemotePathMapping], host: str, remote_path: str | Path) -> Path:
def remap_remote_to_local(
*, mappings: Iterable[RemotePathMapping], host: str, remote_path: str | Path
) -> Path:
"""Remap a remote path to a local path using the configured mappings."""
remapped, _ = remap_remote_to_local_with_match(
mappings=mappings,
host=host,
remote_path=remote_path,
)
if remapped is None:
return Path(str(remote_path))
return remapped
def get_client_host_identifier(client: Any) -> Optional[str]:
def get_client_host_identifier(client: object) -> str | None:
"""Return a stable identifier used by the mapping UI.
Sonarr uses the download client's configured host. Shelfmark currently uses
the download client 'name' (e.g. qbittorrent, sabnzbd).
"""
name = getattr(client, "name", None)
if isinstance(name, str) and name.strip():
return name.strip().lower()
+16 -5
View File
@@ -2,19 +2,30 @@
from __future__ import annotations
from typing import Iterable, Optional
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Callable, Iterable
class PrefixMiddleware:
"""Strip a configured URL prefix from PATH_INFO before routing."""
def __init__(self, app, prefix: str, bypass_paths: Optional[Iterable[str]] = None) -> None:
def __init__(
self,
app: Callable[[dict[str, object], Callable[..., object]], object],
prefix: str,
bypass_paths: Iterable[str] | None = None,
) -> None:
"""Initialize the middleware with a prefix and optional bypass paths."""
self.app = app
self.prefix = prefix.rstrip("/")
self.bypass_paths = set(bypass_paths or [])
def __call__(self, environ, start_response):
path = environ.get("PATH_INFO", "") or ""
def __call__(self, environ: dict[str, object], start_response: Callable[..., object]) -> object:
"""Rewrite prefixed requests before handing them to the wrapped app."""
raw_path = environ.get("PATH_INFO", "")
path = raw_path if isinstance(raw_path, str) else str(raw_path or "")
if path in self.bypass_paths:
return self.app(environ, start_response)
@@ -24,7 +35,7 @@ class PrefixMiddleware:
if path == self.prefix or path.startswith(self.prefix + "/"):
environ["SCRIPT_NAME"] = self.prefix
environ["PATH_INFO"] = path[len(self.prefix):] or "/"
environ["PATH_INFO"] = path[len(self.prefix) :] or "/"
return self.app(environ, start_response)
start_response("404 Not Found", [("Content-Type", "text/plain")])
+213 -154
View File
@@ -2,19 +2,46 @@
import queue
import time
from datetime import datetime, timedelta
from datetime import UTC, datetime, timedelta
from pathlib import Path
from threading import Lock, Event
from typing import Dict, List, Optional, Tuple, Any, Callable
from threading import Event, Lock
from typing import TYPE_CHECKING, Any
from shelfmark.core.config import config as app_config
from shelfmark.core.models import QueueStatus, QueueItem, DownloadTask
from shelfmark.core.logger import setup_logger
from shelfmark.core.models import (
TERMINAL_QUEUE_STATUSES,
DownloadTask,
QueueItem,
QueueStatus,
)
if TYPE_CHECKING:
from collections.abc import Callable
logger = setup_logger(__name__)
_QUEUE_HOOK_ERRORS = (OSError, RuntimeError, TypeError, ValueError)
def _coerce_status_timeout_seconds(value: object, *, default: int) -> int:
"""Normalize STATUS_TIMEOUT into a usable positive integer."""
if isinstance(value, bool):
return default
if isinstance(value, int):
return value if value > 0 else default
if isinstance(value, str):
stripped = value.strip()
if stripped.isdigit():
parsed = int(stripped)
return parsed if parsed > 0 else default
return default
class BookQueue:
"""Thread-safe download queue manager with priority support and cancellation."""
def __init__(self) -> None:
"""Initialize queue state, locks, and lifecycle hooks."""
self._queue: queue.PriorityQueue[QueueItem] = queue.PriorityQueue()
self._lock = Lock()
self._status: dict[str, QueueStatus] = {}
@@ -22,22 +49,30 @@ class BookQueue:
self._status_timestamps: dict[str, datetime] = {} # Track when each status was last updated
self._cancel_flags: dict[str, Event] = {} # Cancellation flags for active downloads
self._active_downloads: dict[str, bool] = {} # Track currently downloading tasks
self._terminal_status_hook: Optional[
Callable[[str, QueueStatus, DownloadTask], None]
] = None
self._terminal_status_hook: Callable[[str, QueueStatus, DownloadTask], None] | None = None
self._queue_hook: Callable[[str, DownloadTask], None] | None = None
@property
def _status_timeout(self) -> timedelta:
"""Get status timeout from config (allows live updates)."""
return timedelta(seconds=app_config.get("STATUS_TIMEOUT", 3600))
return timedelta(
seconds=_coerce_status_timeout_seconds(
app_config.get("STATUS_TIMEOUT", 3600),
default=3600,
)
)
def add(self, task: DownloadTask) -> bool:
"""Add a download task to the queue. Returns False if already exists."""
hook: Callable[[str, DownloadTask], None] | None = None
with self._lock:
task_id = task.task_id
# Don't add if already exists and not in error/done state
if task_id in self._status and self._status[task_id] not in [QueueStatus.ERROR, QueueStatus.DONE, QueueStatus.CANCELLED]:
# Don't add if already exists and not in error/cancelled state
if task_id in self._status and self._status[task_id] not in [
QueueStatus.ERROR,
QueueStatus.CANCELLED,
]:
return False
# Ensure added_time is set
@@ -48,9 +83,16 @@ class BookQueue:
self._queue.put(queue_item)
self._task_data[task_id] = task
self._update_status(task_id, QueueStatus.QUEUED)
return True
hook = self._queue_hook
def get_next(self) -> Optional[Tuple[str, Event]]:
if hook is not None:
try:
hook(task_id, task)
except _QUEUE_HOOK_ERRORS as exc:
logger.warning("Queue hook failed while adding task %s: %s", task_id, exc)
return True
def get_next(self) -> tuple[str, Event] | None:
"""Get next task ID from queue with cancellation flag."""
# Use iterative approach to avoid stack overflow if many items are cancelled
while True:
@@ -67,58 +109,72 @@ class BookQueue:
cancel_flag = Event()
self._cancel_flags[task_id] = cancel_flag
self._active_downloads[task_id] = True
return task_id, cancel_flag
except queue.Empty:
return None
else:
return task_id, cancel_flag
def get_task(self, task_id: str) -> Optional[DownloadTask]:
def get_task(self, task_id: str) -> DownloadTask | None:
"""Get a task by its ID."""
with self._lock:
return self._task_data.get(task_id)
def get_task_status(self, task_id: str) -> QueueStatus | None:
"""Get queue status for a task id."""
with self._lock:
return self._status.get(task_id)
def _update_status(self, book_id: str, status: QueueStatus) -> None:
"""Internal method to update status and timestamp."""
"""Update the status and timestamp for a task."""
self._status[book_id] = status
self._status_timestamps[book_id] = datetime.now()
self._status_timestamps[book_id] = datetime.now(UTC)
def set_terminal_status_hook(
self,
hook: Optional[Callable[[str, QueueStatus, DownloadTask], None]],
hook: Callable[[str, QueueStatus, DownloadTask], None] | None,
) -> None:
"""Register a callback invoked when a task first enters a terminal status."""
with self._lock:
self._terminal_status_hook = hook
def set_queue_hook(
self,
hook: Callable[[str, DownloadTask], None] | None,
) -> None:
"""Register a callback invoked when a task is added to the queue."""
with self._lock:
self._queue_hook = hook
def _apply_status_locked(
self, book_id: str, status: QueueStatus
) -> tuple[Callable[[str, QueueStatus, DownloadTask], None] | None, DownloadTask | None]:
"""Apply a status change; returns the terminal hook to run after releasing the lock."""
hook: Callable[[str, QueueStatus, DownloadTask], None] | None = None
hook_task: DownloadTask | None = None
previous_status = self._status.get(book_id)
self._update_status(book_id, status)
if (
status in TERMINAL_QUEUE_STATUSES
and previous_status != status
and self._terminal_status_hook is not None
):
current_task = self._task_data.get(book_id)
if current_task is not None:
hook = self._terminal_status_hook
hook_task = current_task
# Clean up active download tracking when finished
if status in TERMINAL_QUEUE_STATUSES:
self._active_downloads.pop(book_id, None)
self._cancel_flags.pop(book_id, None)
return hook, hook_task
def update_status(self, book_id: str, status: QueueStatus) -> None:
"""Update status of a book in the queue."""
hook: Optional[Callable[[str, QueueStatus, DownloadTask], None]] = None
hook_task: Optional[DownloadTask] = None
with self._lock:
previous_status = self._status.get(book_id)
self._update_status(book_id, status)
terminal_statuses = {
QueueStatus.COMPLETE,
QueueStatus.AVAILABLE,
QueueStatus.ERROR,
QueueStatus.DONE,
QueueStatus.CANCELLED,
}
if (
status in terminal_statuses
and previous_status != status
and self._terminal_status_hook is not None
):
current_task = self._task_data.get(book_id)
if current_task is not None:
hook = self._terminal_status_hook
hook_task = current_task
# Clean up active download tracking when finished
if status in [QueueStatus.COMPLETE, QueueStatus.AVAILABLE, QueueStatus.ERROR, QueueStatus.DONE, QueueStatus.CANCELLED]:
self._active_downloads.pop(book_id, None)
self._cancel_flags.pop(book_id, None)
hook, hook_task = self._apply_status_locked(book_id, status)
if hook is not None and hook_task is not None:
hook(book_id, status, hook_task)
@@ -141,25 +197,28 @@ class BookQueue:
if task_id in self._task_data:
self._task_data[task_id].status_message = message
def get_status(self, user_id: Optional[int] = None) -> Dict[QueueStatus, Dict[str, DownloadTask]]:
def get_status(self, user_id: int | None = None) -> dict[QueueStatus, dict[str, DownloadTask]]:
"""Get current queue status grouped by status.
Args:
user_id: If provided, only return tasks belonging to this user
(plus legacy tasks with no user_id). If None, return all.
user_id: If provided, only return tasks belonging to this user.
If None, return all.
"""
self.refresh()
with self._lock:
result: Dict[QueueStatus, Dict[str, DownloadTask]] = {status: {} for status in QueueStatus}
result: dict[QueueStatus, dict[str, DownloadTask]] = {
status: {} for status in QueueStatus
}
for task_id, status in self._status.items():
if task_id in self._task_data:
task = self._task_data[task_id]
if user_id is not None and task.user_id is not None and task.user_id != user_id:
if user_id is not None and task.user_id != user_id:
continue
result[status][task_id] = task
return result
def get_queue_order(self) -> List[Dict[str, Any]]:
def get_queue_order(self) -> list[dict[str, Any]]:
"""Get current queue order for display."""
with self._lock:
queue_items = []
@@ -167,53 +226,51 @@ class BookQueue:
# Get items from priority queue without removing them
temp_items = []
while not self._queue.empty():
try:
item = self._queue.get_nowait()
temp_items.append(item)
task_id = item.book_id # QueueItem uses book_id as the ID field
if task_id in self._task_data:
task = self._task_data[task_id]
queue_items.append({
'id': task_id,
'title': task.title,
'author': task.author,
'priority': item.priority,
'added_time': item.added_time,
'status': self._status.get(task_id, QueueStatus.QUEUED)
})
except queue.Empty:
break
item = self._queue.get_nowait()
temp_items.append(item)
task_id = item.book_id # QueueItem uses book_id as the ID field
if task_id in self._task_data:
task = self._task_data[task_id]
queue_items.append(
{
"id": task_id,
"title": task.title,
"author": task.author,
"priority": item.priority,
"added_time": item.added_time,
"status": self._status.get(task_id, QueueStatus.QUEUED),
}
)
# Put items back in queue
for item in temp_items:
self._queue.put(item)
return sorted(queue_items, key=lambda x: (x['priority'], x['added_time']))
return sorted(queue_items, key=lambda x: (x["priority"], x["added_time"]))
def cancel_download(self, task_id: str) -> bool:
"""Cancel a download or clear a completed/errored item."""
"""Cancel an active or queued download."""
with self._lock:
current_status = self._status.get(task_id)
# Allow cancellation during any active state
if current_status in [QueueStatus.RESOLVING, QueueStatus.LOCATING, QueueStatus.DOWNLOADING]:
if current_status in [
QueueStatus.RESOLVING,
QueueStatus.LOCATING,
QueueStatus.DOWNLOADING,
]:
# Signal active download to stop
if task_id in self._cancel_flags:
self._cancel_flags[task_id].set()
if current_status in [QueueStatus.COMPLETE, QueueStatus.DONE, QueueStatus.AVAILABLE, QueueStatus.ERROR, QueueStatus.CANCELLED]:
# Clear completed/errored/cancelled items from tracking
self._status.pop(task_id, None)
self._status_timestamps.pop(task_id, None)
self._task_data.pop(task_id, None)
self._cancel_flags.pop(task_id, None)
self._active_downloads.pop(task_id, None)
return True
elif current_status != QueueStatus.QUEUED:
# Not in a cancellable state
return False
if current_status in [QueueStatus.RESOLVING, QueueStatus.LOCATING, QueueStatus.DOWNLOADING, QueueStatus.QUEUED]:
self.update_status(task_id, QueueStatus.CANCELLED)
return True
# Write under the same lock so a download that finishes first is not overwritten
hook, hook_task = self._apply_status_locked(task_id, QueueStatus.CANCELLED)
return False
if hook is not None and hook_task is not None:
hook(task_id, QueueStatus.CANCELLED, hook_task)
return True
def set_priority(self, task_id: str, new_priority: int) -> bool:
"""Change the priority of a queued task (lower = higher priority)."""
@@ -226,20 +283,17 @@ class BookQueue:
found = False
while not self._queue.empty():
try:
item = self._queue.get_nowait()
if item.book_id == task_id: # QueueItem uses book_id as the ID field
# Create new item with updated priority
new_item = QueueItem(task_id, new_priority, item.added_time)
temp_items.append(new_item)
found = True
# Update task data priority
if task_id in self._task_data:
self._task_data[task_id].priority = new_priority
else:
temp_items.append(item)
except queue.Empty:
break
item = self._queue.get_nowait()
if item.book_id == task_id: # QueueItem uses book_id as the ID field
# Create new item with updated priority
new_item = QueueItem(task_id, new_priority, item.added_time)
temp_items.append(new_item)
found = True
# Update task data priority
if task_id in self._task_data:
self._task_data[task_id].priority = new_priority
else:
temp_items.append(item)
# Put all items back
for item in temp_items:
@@ -247,25 +301,64 @@ class BookQueue:
return found
def reorder_queue(self, task_priorities: Dict[str, int]) -> bool:
def enqueue_existing(self, task_id: str, *, priority: int | None = None) -> bool:
"""Requeue an existing task regardless of current status.
This is used for retries where task metadata should be preserved.
"""
hook: Callable[[str, DownloadTask], None] | None = None
hook_task: DownloadTask | None = None
with self._lock:
task = self._task_data.get(task_id)
if task is None:
return False
if priority is not None:
task.priority = priority
# Ensure task doesn't appear active while waiting for retry.
self._active_downloads.pop(task_id, None)
self._cancel_flags.pop(task_id, None)
# De-duplicate queue entries for this task id.
temp_items: list[QueueItem] = []
while not self._queue.empty():
item = self._queue.get_nowait()
if item.book_id != task_id:
temp_items.append(item)
for item in temp_items:
self._queue.put(item)
queue_item = QueueItem(task_id, task.priority, time.time())
self._queue.put(queue_item)
self._update_status(task_id, QueueStatus.QUEUED)
hook = self._queue_hook
hook_task = task
if hook is not None and hook_task is not None:
try:
hook(task_id, hook_task)
except _QUEUE_HOOK_ERRORS as exc:
logger.warning("Queue hook failed while requeueing task %s: %s", task_id, exc)
return True
def reorder_queue(self, task_priorities: dict[str, int]) -> bool:
"""Bulk reorder queue by mapping task_id to new priority."""
with self._lock:
# Extract all items from queue
all_items = []
while not self._queue.empty():
try:
item = self._queue.get_nowait()
task_id = item.book_id # QueueItem uses book_id as the ID field
# Update priority if specified
if task_id in task_priorities:
new_priority = task_priorities[task_id]
item = QueueItem(task_id, new_priority, item.added_time)
# Update task data priority
if task_id in self._task_data:
self._task_data[task_id].priority = new_priority
all_items.append(item)
except queue.Empty:
break
item = self._queue.get_nowait()
task_id = item.book_id # QueueItem uses book_id as the ID field
# Update priority if specified
if task_id in task_priorities:
new_priority = task_priorities[task_id]
item = QueueItem(task_id, new_priority, item.added_time)
# Update task data priority
if task_id in self._task_data:
self._task_data[task_id].priority = new_priority
all_items.append(item)
# Put all items back with updated priorities
for item in all_items:
@@ -273,7 +366,7 @@ class BookQueue:
return True
def get_active_downloads(self) -> List[str]:
def get_active_downloads(self) -> list[str]:
"""Get list of currently active download task IDs."""
with self._lock:
return list(self._active_downloads.keys())
@@ -285,45 +378,11 @@ class BookQueue:
return True
return any(status == QueueStatus.QUEUED for status in self._status.values())
def clear_completed(self, user_id: Optional[int] = None) -> int:
"""Remove terminal tasks from tracking, optionally scoped to one user.
Args:
user_id: If provided, only clear tasks belonging to this user,
plus legacy tasks with no user_id. If None, clear all.
"""
terminal_statuses = {QueueStatus.COMPLETE, QueueStatus.DONE, QueueStatus.AVAILABLE, QueueStatus.ERROR, QueueStatus.CANCELLED}
with self._lock:
to_remove: list[str] = []
for task_id, status in self._status.items():
if status not in terminal_statuses:
continue
if user_id is None:
to_remove.append(task_id)
continue
task = self._task_data.get(task_id)
if task is None:
# Without task ownership metadata we cannot safely scope removal.
continue
if task.user_id is None or task.user_id == user_id:
to_remove.append(task_id)
for task_id in to_remove:
self._status.pop(task_id, None)
self._status_timestamps.pop(task_id, None)
self._task_data.pop(task_id, None)
self._cancel_flags.pop(task_id, None)
self._active_downloads.pop(task_id, None)
return len(to_remove)
def refresh(self) -> None:
"""Remove any tasks that are done downloading or have stale status."""
terminal_statuses = {QueueStatus.COMPLETE, QueueStatus.DONE, QueueStatus.ERROR, QueueStatus.AVAILABLE, QueueStatus.CANCELLED}
terminal_statuses = TERMINAL_QUEUE_STATUSES
with self._lock:
current_time = datetime.now()
current_time = datetime.now(UTC)
to_remove = []
for task_id, status in self._status.items():
@@ -335,15 +394,14 @@ class BookQueue:
if task.download_path and not Path(task.download_path).exists():
task.download_path = None
# Mark available downloads as done if file is gone
if status == QueueStatus.AVAILABLE and not task.download_path:
self._update_status(task_id, QueueStatus.DONE)
# Check for stale status entries
last_update = self._status_timestamps.get(task_id)
if last_update and (current_time - last_update) > self._status_timeout:
if status in terminal_statuses:
to_remove.append(task_id)
if (
last_update
and (current_time - last_update) > self._status_timeout
and status in terminal_statuses
):
to_remove.append(task_id)
# Remove stale entries
for task_id in to_remove:
@@ -351,5 +409,6 @@ class BookQueue:
self._status_timestamps.pop(task_id, None)
self._task_data.pop(task_id, None)
# Global instance of BookQueue
book_queue = BookQueue()
+102
View File
@@ -0,0 +1,102 @@
"""Pre-download release inspection: list a release's files and plan a multi-book split."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from flask import jsonify, request
from shelfmark.core.logger import setup_logger
from shelfmark.core.utils import is_audiobook
from shelfmark.download.postprocess.packs import PackFile, PackPlan, plan_pack
from shelfmark.download.postprocess.policy import (
get_supported_audiobook_formats,
get_supported_formats,
)
from shelfmark.release_sources import get_handler
if TYPE_CHECKING:
from collections.abc import Callable
from flask import Flask, Response
logger = setup_logger(__name__)
_INSPECT_ERRORS = (OSError, RuntimeError, ValueError, TypeError, KeyError, AttributeError)
NOT_INSPECTABLE_REASON = "This source cannot list the release's files before downloading"
def _serialize_plan(plan: PackPlan) -> dict[str, Any]:
return {
"is_pack": plan.is_pack,
"ignored": plan.ignored,
"books": [
{
"title": book.title,
"series_position": book.series_position,
"year": book.year,
"files": book.files,
}
for book in plan.books
],
}
def inspect_release(data: dict[str, Any]) -> dict[str, Any]:
"""Build the inspect response for a release payload (same shape as a download)."""
source = str(data["source"])
handler = get_handler(source)
try:
files: list[PackFile] | None = handler.list_files(data)
except _INSPECT_ERRORS as exc:
logger.warning(
"Could not list files for %s release %s: %s", source, data.get("source_id"), exc
)
return {"inspected": False, "reason": str(exc), "files": [], "plan": None}
if files is None:
return {"inspected": False, "reason": NOT_INSPECTABLE_REASON, "files": [], "plan": None}
content_type = data.get("content_type")
supported = (
get_supported_audiobook_formats()
if is_audiobook(content_type if isinstance(content_type, str) else None)
else get_supported_formats()
)
series_name = data.get("series_name")
author_name = data.get("author")
plan = plan_pack(
files,
supported_extensions=set(supported),
series_name=series_name if isinstance(series_name, str) else None,
author_name=author_name if isinstance(author_name, str) else None,
)
return {
"inspected": True,
"reason": None,
"files": [{"path": f.path, "size": f.size} for f in files],
"plan": _serialize_plan(plan),
}
def register_release_inspect_routes(
app: Flask,
login_required: Callable[..., Any],
) -> None:
"""Register POST /api/releases/inspect."""
@app.route("/api/releases/inspect", methods=["POST"])
@login_required
def api_inspect_release() -> Response | tuple[Response, int]:
data = request.get_json(silent=True)
if not isinstance(data, dict):
return jsonify({"error": "No data provided"}), 400
if not data.get("source_id"):
return jsonify({"error": "source_id is required"}), 400
if not data.get("source"):
return jsonify({"error": "source is required"}), 400
try:
get_handler(str(data["source"]))
except ValueError as exc:
return jsonify({"error": str(exc)}), 400
return jsonify(inspect_release(data))
+93
View File
@@ -0,0 +1,93 @@
"""Shared release-search helpers.
Extracted from the ``/api/releases`` route so the same per-source search logic can
be reused outside the HTTP route (for example by background automation) without
going through Flask. Behaviour for the HTTP route is preserved: the route delegates
its inner per-source search to :func:`search_source_releases`.
"""
from __future__ import annotations
import sqlite3
from typing import TYPE_CHECKING
from shelfmark.core.logger import setup_logger
from shelfmark.core.search_plan import build_release_search_plan
if TYPE_CHECKING:
from shelfmark.core.models import SearchFilters
from shelfmark.metadata_providers import BookMetadata
from shelfmark.release_sources import Release, ReleaseSource
logger = setup_logger(__name__)
# Mirror of main._OPERATIONAL_ERRORS so a misbehaving source can't crash a caller.
_OPERATIONAL_ERRORS = (OSError, RuntimeError, TypeError, ValueError, sqlite3.Error)
def search_source_releases(
source_name: str,
search_book: BookMetadata,
*,
languages: list[str] | None = None,
manual_query: str | None = None,
indexers: list[str] | None = None,
expand_search: bool = False,
content_type: str = "ebook",
source_filters: SearchFilters | None = None,
user_id: int | None = None,
) -> tuple[ReleaseSource | None, list[Release], str | None]:
"""Search a single release source, returning any error instead of raising.
Returns ``(source, releases, error_message)``. On failure ``source`` is ``None``
and ``error_message`` describes the problem. ``user_id`` lets the search plan
pick up that user's default languages when no explicit filter is given.
"""
from shelfmark.release_sources import SourceUnavailableError, get_source
try:
source = get_source(source_name)
plan = build_release_search_plan(
search_book,
languages=languages,
manual_query=manual_query,
indexers=indexers,
source_filters=source_filters,
user_id=user_id,
)
if plan.source_filters is not None:
planned_query = plan.manual_query or plan.primary_query
planned_query_type = "query"
elif plan.manual_query:
planned_query = plan.manual_query
planned_query_type = "manual"
elif not expand_search and plan.isbn_candidates:
planned_query = plan.isbn_candidates[0]
planned_query_type = "isbn"
else:
planned_query = plan.primary_query
planned_query_type = "title_author"
logger.debug(
"Searching %s: %s='%s' (title='%s', authors=%s, expand=%s, content_type=%s)",
source_name,
planned_query_type,
planned_query,
search_book.title,
search_book.authors,
expand_search,
content_type,
)
releases = source.search(
search_book, plan, expand_search=expand_search, content_type=content_type
)
except ValueError:
return None, [], f"Unknown source: {source_name}"
except (SourceUnavailableError, *_OPERATIONAL_ERRORS) as exc:
logger.warning("Release search failed for source %s: %s", source_name, exc)
return None, [], f"{source_name}: {exc!s}"
else:
return source, releases, None
+184
View File
@@ -0,0 +1,184 @@
"""Shared request-related helper functions used by routes and services."""
from __future__ import annotations
from datetime import UTC, datetime
from typing import Any, Protocol, SupportsIndex, SupportsInt, TypeGuard
from shelfmark.core.config import config as app_config
from shelfmark.core.logger import setup_logger
_logger = setup_logger(__name__)
type _ConvertibleToInt = str | bytes | bytearray | SupportsInt | SupportsIndex
class _MappingWithGet(Protocol):
"""Minimal mapping protocol for session-like objects."""
def get(self, key: str, default: object = None, /) -> object: ...
class _UserDBLike(Protocol):
"""Minimal user DB protocol for username population helpers."""
def get_user(self, *, user_id: int) -> dict[str, Any] | None: ...
def _is_mapping_with_get(candidate: object) -> TypeGuard[_MappingWithGet]:
"""Return True when *candidate* exposes a mapping-style get method."""
return callable(getattr(candidate, "get", None))
def _is_user_db_like(candidate: object) -> TypeGuard[_UserDBLike]:
"""Return True when *candidate* exposes the user lookup API we need."""
return callable(getattr(candidate, "get_user", None))
def _is_convertible_to_int(value: object) -> TypeGuard[_ConvertibleToInt]:
"""Return True when *value* can be passed to ``int`` safely."""
return (
isinstance(value, (str, bytes, bytearray))
or hasattr(value, "__int__")
or hasattr(value, "__index__")
)
def now_utc_iso() -> str:
"""Return the current UTC time as a seconds-precision ISO 8601 string."""
return datetime.now(UTC).isoformat(timespec="seconds")
def emit_ws_event(
ws_manager: object,
*,
event_name: str,
payload: dict[str, Any],
room: str,
) -> None:
"""Emit a WebSocket event via the shared manager, swallowing failures."""
if ws_manager is None:
return
try:
socketio = getattr(ws_manager, "socketio", None)
is_enabled = getattr(ws_manager, "is_enabled", None)
if socketio is None or not callable(is_enabled) or not is_enabled():
return
socketio.emit(event_name, payload, to=room)
except (AttributeError, RuntimeError, TypeError, ValueError) as exc:
_logger.warning(
"Failed to emit WebSocket event '%s' to room '%s': %s",
event_name,
room,
exc,
)
def load_users_request_policy_settings() -> dict[str, Any]:
"""Load global request-policy settings from the users config file."""
from shelfmark.core.request_policy import REQUEST_POLICY_KEYS
return {key: app_config.get(key) for key in REQUEST_POLICY_KEYS}
def coerce_bool(value: object, *, default: bool = False) -> bool:
"""Coerce arbitrary values into booleans with string-friendly semantics."""
if isinstance(value, bool):
return value
if value is None:
return default
if isinstance(value, str):
normalized = value.strip().lower()
if normalized in {"1", "true", "yes", "on"}:
return True
if normalized in {"0", "false", "no", "off", ""}:
return False
return bool(value)
def get_session_db_user_id(session_obj: object) -> int | None:
"""Extract and coerce `db_user_id` from a Flask session to ``int | None``."""
raw = session_obj.get("db_user_id") if _is_mapping_with_get(session_obj) else None
try:
return int(raw) if raw is not None and _is_convertible_to_int(raw) else None
except TypeError, ValueError:
return None
def coerce_int(value: object, default: int) -> int:
"""Best-effort integer coercion with fallback to default."""
if not _is_convertible_to_int(value):
return default
try:
return int(value)
except TypeError, ValueError:
return default
def normalize_optional_text(value: object) -> str | None:
"""Return a trimmed string or None for empty/non-string input."""
if not isinstance(value, str):
return None
normalized = value.strip()
return normalized or None
def normalize_positive_int(value: object) -> int | None:
"""Parse *value* as a positive integer, returning ``None`` on failure."""
if not _is_convertible_to_int(value):
return None
try:
parsed = int(value)
except TypeError, ValueError:
return None
return parsed if parsed > 0 else None
def normalize_optional_positive_int(value: object, field_name: str = "value") -> int | None:
"""Parse *value* as a positive integer or ``None``.
Raises ``ValueError`` when *value* is present but not a valid
positive integer.
"""
if value is None:
return None
if not _is_convertible_to_int(value):
msg = f"{field_name} must be a positive integer when provided"
raise ValueError(msg)
try:
parsed = int(value)
except (TypeError, ValueError) as exc:
msg = f"{field_name} must be a positive integer when provided"
raise ValueError(msg) from exc
if parsed < 1:
msg = f"{field_name} must be a positive integer when provided"
raise ValueError(msg)
return parsed
def populate_request_usernames(rows: list[dict[str, Any]], user_db: object) -> None:
"""Add 'username' to each request row by looking up user_id."""
if not _is_user_db_like(user_db):
return
cache: dict[int, str] = {}
for row in rows:
requester_id = normalize_positive_int(row.get("user_id"))
if requester_id is None:
row["username"] = ""
continue
if requester_id not in cache:
requester = user_db.get_user(user_id=requester_id)
cache[requester_id] = requester.get("username", "") if requester else ""
row["username"] = cache[requester_id]
def extract_release_source_id(release_data: object) -> str | None:
"""Extract and normalize release_data.source_id."""
if not isinstance(release_data, dict):
return None
source_id = release_data.get("source_id")
if not isinstance(source_id, str):
return None
normalized = source_id.strip()
return normalized or None

Some files were not shown because too many files have changed in this diff Show More